oxedyne/fe2o3/fe2o3_text/tests/annealer_corpus/rocket_response.rs
37.4 KiB, 1 run
created by r1870400018:11808, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | use std::{fmt, str}; |
| 2 | use std::borrow::Cow; |
| 3 | use std::collections::HashMap; |
| 4 | |
| 5 | use tokio::io::{AsyncRead, AsyncSeek}; |
| 6 | |
| 7 | use crate::http::{Header, HeaderMap, Status, ContentType, Cookie}; |
| 8 | use crate::http::uncased::{Uncased, AsUncased}; |
| 9 | use crate::data::IoHandler; |
| 10 | use crate::response::Body; |
| 11 | |
| 12 | /// Builder for the [`Response`] type. |
| 13 | /// |
| 14 | /// Building a [`Response`] can be a low-level ordeal; this structure presents a |
| 15 | /// higher-level API that simplifies building `Response`s. |
| 16 | /// |
| 17 | /// # Usage |
| 18 | /// |
| 19 | /// `Builder` follows the builder pattern and is usually obtained by calling |
| 20 | /// [`Response::build()`] on `Response`. Almost all methods take the current |
| 21 | /// builder as a mutable reference and return the same mutable reference with |
| 22 | /// field(s) modified in the `Response` being built. These method calls can be |
| 23 | /// chained: `build.a().b()`. |
| 24 | /// |
| 25 | /// To finish building and retrieve the built `Response`, use the |
| 26 | /// [`finalize()`](#method.finalize) or [`ok()`](#method.ok) methods. |
| 27 | /// |
| 28 | /// ## Headers |
| 29 | /// |
| 30 | /// When building a `Response`, headers can either be _replaced_ or _adjoined_; |
| 31 | /// the default behavior (using `header(..)`) is to _replace_. When a header is |
| 32 | /// _replaced_, any existing values for headers with the same name are removed, |
| 33 | /// and the new value is set. If no header exists, the header is simply added. |
| 34 | /// On the other hand, when a header is _adjoined_, all existing values will |
| 35 | /// remain, and the `value` of the adjoined header will be added to the set of |
| 36 | /// existing values, if any. Adjoining maintains order: headers adjoined first |
| 37 | /// will appear first in the `Response`. |
| 38 | /// |
| 39 | /// ## Joining and Merging |
| 40 | /// |
| 41 | /// It is often necessary to combine multiple `Response`s in some way. The |
| 42 | /// [merge](#method.merge) and [join](#method.join) methods facilitate this. The |
| 43 | /// `merge` method replaces all of the fields in `self` with those present in |
| 44 | /// `other`. The `join` method sets any fields not set in `self` to the value in |
| 45 | /// `other`. See their documentation for more details. |
| 46 | /// ## Example |
| 47 | /// |
| 48 | /// The following example builds a `Response` with: |
| 49 | /// |
| 50 | /// * **Status**: `418 I'm a teapot` |
| 51 | /// * **Content-Type** header: `text/plain; charset=utf-8` |
| 52 | /// * **X-Teapot-Make** header: `Rocket` |
| 53 | /// * **X-Teapot-Model** headers: `Utopia`, `Series 1` |
| 54 | /// * **Body**: fixed-size string `"Brewing the best coffee!"` |
| 55 | /// |
| 56 | /// ```rust |
| 57 | /// use std::io::Cursor; |
| 58 | /// use rocket::response::Response; |
| 59 | /// use rocket::http::{Status, ContentType}; |
| 60 | /// |
| 61 | /// let body = "Brewing the best coffee!"; |
| 62 | /// let response = Response::build() |
| 63 | /// .status(Status::ImATeapot) |
| 64 | /// .header(ContentType::Plain) |
| 65 | /// .raw_header("X-Teapot-Make", "Rocket") |
| 66 | /// .raw_header("X-Teapot-Model", "Utopia") |
| 67 | /// .raw_header_adjoin("X-Teapot-Model", "Series 1") |
| 68 | /// .sized_body(body.len(), Cursor::new(body)) |
| 69 | /// .finalize(); |
| 70 | /// ``` |
| 71 | pub struct Builder<'r> { |
| 72 | response: Response<'r>, |
| 73 | } |
| 74 | |
| 75 | impl<'r> Builder<'r> { |
| 76 | /// Creates a new `Builder` that will build on top of the `base` |
| 77 | /// `Response`. |
| 78 | /// |
| 79 | /// # Example |
| 80 | /// |
| 81 | /// ```rust |
| 82 | /// use rocket::response::{Builder, Response}; |
| 83 | /// |
| 84 | /// # #[allow(unused_variables)] |
| 85 | /// let builder = Builder::new(Response::new()); |
| 86 | /// ``` |
| 87 | #[inline(always)] |
| 88 | pub fn new(base: Response<'r>) -> Builder<'r> { |
| 89 | Builder { |
| 90 | response: base, |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | /// Sets the status of the `Response` being built to `status`. |
| 95 | /// |
| 96 | /// # Example |
| 97 | /// |
| 98 | /// ```rust |
| 99 | /// use rocket::Response; |
| 100 | /// use rocket::http::Status; |
| 101 | /// |
| 102 | /// let response = Response::build() |
| 103 | /// .status(Status::NotFound) |
| 104 | /// .finalize(); |
| 105 | /// ``` |
| 106 | #[inline(always)] |
| 107 | pub fn status(&mut self, status: Status) -> &mut Builder<'r> { |
| 108 | self.response.set_status(status); |
| 109 | self |
| 110 | } |
| 111 | |
| 112 | /// Adds `header` to the `Response`, replacing any header with the same name |
| 113 | /// that already exists in the response. If multiple headers with |
| 114 | /// the same name exist, they are all removed, and only the new header and |
| 115 | /// value will remain. |
| 116 | /// |
| 117 | /// The type of `header` can be any type that implements `Into<Header>`. See |
| 118 | /// [trait implementations](Header#trait-implementations). |
| 119 | /// |
| 120 | /// # Example |
| 121 | /// |
| 122 | /// ```rust |
| 123 | /// use rocket::Response; |
| 124 | /// use rocket::http::ContentType; |
| 125 | /// |
| 126 | /// let response = Response::build() |
| 127 | /// .header(ContentType::JSON) |
| 128 | /// .header(ContentType::HTML) |
| 129 | /// .finalize(); |
| 130 | /// |
| 131 | /// assert_eq!(response.headers().get("Content-Type").count(), 1); |
| 132 | /// ``` |
| 133 | #[inline(always)] |
| 134 | pub fn header<'h: 'r, H>(&mut self, header: H) -> &mut Builder<'r> |
| 135 | where H: Into<Header<'h>> |
| 136 | { |
| 137 | self.response.set_header(header); |
| 138 | self |
| 139 | } |
| 140 | |
| 141 | /// Adds `header` to the `Response` by adjoining the header with any |
| 142 | /// existing headers with the same name that already exist in the |
| 143 | /// `Response`. This allows for multiple headers with the same name and |
| 144 | /// potentially different values to be present in the `Response`. |
| 145 | /// |
| 146 | /// The type of `header` can be any type that implements `Into<Header>`. See |
| 147 | /// [trait implementations](Header#trait-implementations). |
| 148 | /// |
| 149 | /// # Example |
| 150 | /// |
| 151 | /// ```rust |
| 152 | /// use rocket::Response; |
| 153 | /// use rocket::http::{Header, Accept}; |
| 154 | /// |
| 155 | /// let response = Response::build() |
| 156 | /// .header_adjoin(Header::new("Accept", "application/json")) |
| 157 | /// .header_adjoin(Accept::XML) |
| 158 | /// .finalize(); |
| 159 | /// |
| 160 | /// assert_eq!(response.headers().get("Accept").count(), 2); |
| 161 | /// ``` |
| 162 | #[inline(always)] |
| 163 | pub fn header_adjoin<'h: 'r, H>(&mut self, header: H) -> &mut Builder<'r> |
| 164 | where H: Into<Header<'h>> |
| 165 | { |
| 166 | self.response.adjoin_header(header); |
| 167 | self |
| 168 | } |
| 169 | |
| 170 | /// Adds a custom header to the `Response` with the given name and value, |
| 171 | /// replacing any header with the same name that already exists in the |
| 172 | /// response. If multiple headers with the same name exist, they are all |
| 173 | /// removed, and only the new header and value will remain. |
| 174 | /// |
| 175 | /// # Example |
| 176 | /// |
| 177 | /// ```rust |
| 178 | /// use rocket::Response; |
| 179 | /// |
| 180 | /// let response = Response::build() |
| 181 | /// .raw_header("X-Custom", "first") |
| 182 | /// .raw_header("X-Custom", "second") |
| 183 | /// .finalize(); |
| 184 | /// |
| 185 | /// assert_eq!(response.headers().get("X-Custom").count(), 1); |
| 186 | /// ``` |
| 187 | #[inline(always)] |
| 188 | pub fn raw_header<'a, 'b, N, V>(&mut self, name: N, value: V) -> &mut Builder<'r> |
| 189 | where N: Into<Cow<'a, str>>, V: Into<Cow<'b, str>>, 'a: 'r, 'b: 'r |
| 190 | { |
| 191 | self.response.set_raw_header(name, value); |
| 192 | self |
| 193 | } |
| 194 | |
| 195 | /// Adds custom header to the `Response` with the given name and value, |
| 196 | /// adjoining the header with any existing headers with the same name that |
| 197 | /// already exist in the `Response`. This allows for multiple headers with |
| 198 | /// the same name and potentially different values to be present in the |
| 199 | /// `Response`. |
| 200 | /// |
| 201 | /// # Example |
| 202 | /// |
| 203 | /// ```rust |
| 204 | /// use rocket::Response; |
| 205 | /// |
| 206 | /// let response = Response::build() |
| 207 | /// .raw_header_adjoin("X-Custom", "first") |
| 208 | /// .raw_header_adjoin("X-Custom", "second") |
| 209 | /// .finalize(); |
| 210 | /// |
| 211 | /// assert_eq!(response.headers().get("X-Custom").count(), 2); |
| 212 | /// ``` |
| 213 | #[inline(always)] |
| 214 | pub fn raw_header_adjoin<'a, 'b, N, V>(&mut self, name: N, value: V) -> &mut Builder<'r> |
| 215 | where N: Into<Cow<'a, str>>, V: Into<Cow<'b, str>>, 'a: 'r, 'b: 'r |
| 216 | { |
| 217 | self.response.adjoin_raw_header(name, value); |
| 218 | self |
| 219 | } |
| 220 | |
| 221 | /// Sets the body of the `Response` to be the fixed-sized `body` with size |
| 222 | /// `size`, which may be `None`. If `size` is `None`, the body's size will |
| 223 | /// be computed with calls to `seek` when the response is written out. |
| 224 | /// |
| 225 | /// # Example |
| 226 | /// |
| 227 | /// ```rust |
| 228 | /// use std::io::Cursor; |
| 229 | /// use rocket::Response; |
| 230 | /// |
| 231 | /// let body = "Hello, world!"; |
| 232 | /// let response = Response::build() |
| 233 | /// .sized_body(body.len(), Cursor::new(body)) |
| 234 | /// .finalize(); |
| 235 | /// ``` |
| 236 | pub fn sized_body<B, S>(&mut self, size: S, body: B) -> &mut Builder<'r> |
| 237 | where B: AsyncRead + AsyncSeek + Send + 'r, |
| 238 | S: Into<Option<usize>> |
| 239 | { |
| 240 | self.response.set_sized_body(size, body); |
| 241 | self |
| 242 | } |
| 243 | |
| 244 | /// Sets the body of the `Response` to be the streamed `body`. |
| 245 | /// |
| 246 | /// # Example |
| 247 | /// |
| 248 | /// ```rust |
| 249 | /// use std::io::Cursor; |
| 250 | /// use rocket::Response; |
| 251 | /// |
| 252 | /// let response = Response::build() |
| 253 | /// .streamed_body(Cursor::new("Hello, world!")) |
| 254 | /// .finalize(); |
| 255 | /// ``` |
| 256 | #[inline(always)] |
| 257 | pub fn streamed_body<B>(&mut self, body: B) -> &mut Builder<'r> |
| 258 | where B: AsyncRead + Send + 'r |
| 259 | { |
| 260 | self.response.set_streamed_body(body); |
| 261 | self |
| 262 | } |
| 263 | |
| 264 | /// Registers `handler` as the I/O handler for upgrade protocol `protocol`. |
| 265 | /// |
| 266 | /// This is equivalent to [`Response::add_upgrade()`]. |
| 267 | /// |
| 268 | /// **NOTE**: Responses registering I/O handlers for upgraded protocols |
| 269 | /// **should not** set the response status to `101 Switching Protocols`, nor set the |
| 270 | /// `Connection` or `Upgrade` headers. Rocket automatically sets these |
| 271 | /// headers as needed. See [`Response`#upgrading] for details. |
| 272 | /// |
| 273 | /// # Example |
| 274 | /// |
| 275 | /// ```rust |
| 276 | /// use std::pin::Pin; |
| 277 | /// |
| 278 | /// use rocket::Response; |
| 279 | /// use rocket::data::{IoHandler, IoStream}; |
| 280 | /// use rocket::tokio::io; |
| 281 | /// |
| 282 | /// struct EchoHandler; |
| 283 | /// |
| 284 | /// #[rocket::async_trait] |
| 285 | /// impl IoHandler for EchoHandler { |
| 286 | /// async fn io(self: Box<Self>, io: IoStream) -> io::Result<()> { |
| 287 | /// let (mut reader, mut writer) = io::split(io); |
| 288 | /// io::copy(&mut reader, &mut writer).await?; |
| 289 | /// Ok(()) |
| 290 | /// } |
| 291 | /// } |
| 292 | /// |
| 293 | /// let response = Response::build() |
| 294 | /// .upgrade("raw-echo", EchoHandler) |
| 295 | /// .streamed_body(std::io::Cursor::new("We didn't upgrade!")) |
| 296 | /// .finalize(); |
| 297 | /// ``` |
| 298 | #[inline(always)] |
| 299 | pub fn upgrade<P, H>(&mut self, protocol: P, handler: H) -> &mut Builder<'r> |
| 300 | where P: Into<Uncased<'r>>, H: IoHandler + 'r |
| 301 | { |
| 302 | self.response.add_upgrade(protocol.into(), handler); |
| 303 | self |
| 304 | } |
| 305 | |
| 306 | /// Sets the max chunk size of a body, if any, to `size`. |
| 307 | /// |
| 308 | /// See [`Response::set_max_chunk_size()`] for notes. |
| 309 | /// |
| 310 | /// # Example |
| 311 | /// |
| 312 | /// ```rust |
| 313 | /// use std::io::Cursor; |
| 314 | /// use rocket::Response; |
| 315 | /// |
| 316 | /// let response = Response::build() |
| 317 | /// .streamed_body(Cursor::new("Hello, world!")) |
| 318 | /// .max_chunk_size(3072) |
| 319 | /// .finalize(); |
| 320 | /// ``` |
| 321 | #[inline(always)] |
| 322 | pub fn max_chunk_size(&mut self, size: usize) -> &mut Builder<'r> { |
| 323 | self.response.set_max_chunk_size(size); |
| 324 | self |
| 325 | } |
| 326 | |
| 327 | /// Merges the `other` `Response` into `self` by setting any fields in |
| 328 | /// `self` to the corresponding value in `other` if they are set in `other`. |
| 329 | /// Fields in `self` are unchanged if they are not set in `other`. If a |
| 330 | /// header is set in both `self` and `other`, the values in `other` are |
| 331 | /// kept. Headers set only in `self` remain. |
| 332 | /// |
| 333 | /// # Example |
| 334 | /// |
| 335 | /// ```rust |
| 336 | /// use rocket::Response; |
| 337 | /// use rocket::http::{Status, ContentType}; |
| 338 | /// |
| 339 | /// let base = Response::build() |
| 340 | /// .status(Status::NotFound) |
| 341 | /// .header(ContentType::HTML) |
| 342 | /// .raw_header("X-Custom", "value 1") |
| 343 | /// .finalize(); |
| 344 | /// |
| 345 | /// let response = Response::build() |
| 346 | /// .status(Status::ImATeapot) |
| 347 | /// .raw_header("X-Custom", "value 2") |
| 348 | /// .raw_header_adjoin("X-Custom", "value 3") |
| 349 | /// .merge(base) |
| 350 | /// .finalize(); |
| 351 | /// |
| 352 | /// assert_eq!(response.status(), Status::NotFound); |
| 353 | /// |
| 354 | /// let ctype: Vec<_> = response.headers().get("Content-Type").collect(); |
| 355 | /// assert_eq!(ctype, vec![ContentType::HTML.to_string()]); |
| 356 | /// |
| 357 | /// let custom_values: Vec<_> = response.headers().get("X-Custom").collect(); |
| 358 | /// assert_eq!(custom_values, vec!["value 1"]); |
| 359 | /// ``` |
| 360 | #[inline(always)] |
| 361 | pub fn merge(&mut self, other: Response<'r>) -> &mut Builder<'r> { |
| 362 | self.response.merge(other); |
| 363 | self |
| 364 | } |
| 365 | |
| 366 | /// Joins the `other` `Response` into `self` by setting any fields in `self` |
| 367 | /// to the corresponding value in `other` if they are set in `self`. Fields |
| 368 | /// in `self` are unchanged if they are already set. If a header is set in |
| 369 | /// both `self` and `other`, the values are adjoined, with the values in |
| 370 | /// `self` coming first. Headers only in `self` or `other` are set in |
| 371 | /// `self`. |
| 372 | /// |
| 373 | /// # Example |
| 374 | /// |
| 375 | /// ```rust |
| 376 | /// use rocket::Response; |
| 377 | /// use rocket::http::{Status, ContentType}; |
| 378 | /// |
| 379 | /// let other = Response::build() |
| 380 | /// .status(Status::NotFound) |
| 381 | /// .header(ContentType::HTML) |
| 382 | /// .raw_header("X-Custom", "value 1") |
| 383 | /// .finalize(); |
| 384 | /// |
| 385 | /// let response = Response::build() |
| 386 | /// .status(Status::ImATeapot) |
| 387 | /// .raw_header("X-Custom", "value 2") |
| 388 | /// .raw_header_adjoin("X-Custom", "value 3") |
| 389 | /// .join(other) |
| 390 | /// .finalize(); |
| 391 | /// |
| 392 | /// assert_eq!(response.status(), Status::ImATeapot); |
| 393 | /// |
| 394 | /// let ctype: Vec<_> = response.headers().get("Content-Type").collect(); |
| 395 | /// assert_eq!(ctype, vec![ContentType::HTML.to_string()]); |
| 396 | /// |
| 397 | /// let custom_values: Vec<_> = response.headers().get("X-Custom").collect(); |
| 398 | /// assert_eq!(custom_values, vec!["value 2", "value 3", "value 1"]); |
| 399 | /// ``` |
| 400 | #[inline(always)] |
| 401 | pub fn join(&mut self, other: Response<'r>) -> &mut Builder<'r> { |
| 402 | self.response.join(other); |
| 403 | self |
| 404 | } |
| 405 | |
| 406 | /// Return the `Response` structure that was being built by this builder. |
| 407 | /// After calling this method, `self` is cleared and must be rebuilt as if |
| 408 | /// from `new()`. |
| 409 | /// |
| 410 | /// # Example |
| 411 | /// |
| 412 | /// ```rust |
| 413 | /// use std::io::Cursor; |
| 414 | /// |
| 415 | /// use rocket::Response; |
| 416 | /// use rocket::http::Status; |
| 417 | /// |
| 418 | /// let body = "Brewing the best coffee!"; |
| 419 | /// let response = Response::build() |
| 420 | /// .status(Status::ImATeapot) |
| 421 | /// .sized_body(body.len(), Cursor::new(body)) |
| 422 | /// .raw_header("X-Custom", "value 2") |
| 423 | /// .finalize(); |
| 424 | /// ``` |
| 425 | pub fn finalize(&mut self) -> Response<'r> { |
| 426 | std::mem::replace(&mut self.response, Response::new()) |
| 427 | } |
| 428 | |
| 429 | /// Retrieve the built `Response` wrapped in `Ok`. After calling this |
| 430 | /// method, `self` is cleared and must be rebuilt as if from `new()`. |
| 431 | /// |
| 432 | /// # Example |
| 433 | /// |
| 434 | /// ```rust |
| 435 | /// use rocket::Response; |
| 436 | /// |
| 437 | /// let response: Result<Response, ()> = Response::build() |
| 438 | /// // build the response |
| 439 | /// .ok(); |
| 440 | /// |
| 441 | /// assert!(response.is_ok()); |
| 442 | /// ``` |
| 443 | #[inline(always)] |
| 444 | pub fn ok<E>(&mut self) -> Result<Response<'r>, E> { |
| 445 | Ok(self.finalize()) |
| 446 | } |
| 447 | } |
| 448 | |
| 449 | /// A response, as returned by types implementing |
| 450 | /// [`Responder`](crate::response::Responder). |
| 451 | /// |
| 452 | /// See [`Builder`] for docs on how a `Response` is typically created and the |
| 453 | /// [module docs](crate::response) for notes on composing responses |
| 454 | /// |
| 455 | /// ## Upgrading |
| 456 | /// |
| 457 | /// A response may optionally register [`IoHandler`]s for upgraded requests via |
| 458 | /// [`Response::add_upgrade()`] or the corresponding builder method |
| 459 | /// [`Builder::upgrade()`]. If the incoming request 1) requests an upgrade via a |
| 460 | /// `Connection: Upgrade` header _and_ 2) includes a protocol in its `Upgrade` |
| 461 | /// header that is registered by the returned `Response`, the connection will be |
| 462 | /// upgraded. An upgrade response is sent to the client, and the registered |
| 463 | /// `IoHandler` for the client's preferred protocol is invoked with an |
| 464 | /// [`IoStream`](crate::data::IoStream) representing a raw byte stream to the |
| 465 | /// client. Note that protocol names are treated case-insensitively during |
| 466 | /// matching. |
| 467 | /// |
| 468 | /// If a connection is upgraded, Rocket automatically set the following in the |
| 469 | /// upgrade response: |
| 470 | /// * The response status to `101 Switching Protocols`. |
| 471 | /// * The `Connection: Upgrade` header. |
| 472 | /// * The `Upgrade` header's value to the selected protocol. |
| 473 | /// |
| 474 | /// As such, a response **should never** set a `101` status nor the `Connection` |
| 475 | /// or `Upgrade` headers: Rocket handles this automatically. Instead, it should |
| 476 | /// set a status and headers to use in case the connection is not upgraded, |
| 477 | /// either due to an error or because the client did not request an upgrade. |
| 478 | /// |
| 479 | /// If a connection _is not_ upgraded due to an error, even though there was a |
| 480 | /// matching, registered protocol, the `IoHandler` is not invoked, and the |
| 481 | /// original response is sent to the client without alteration. |
| 482 | #[derive(Default)] |
| 483 | pub struct Response<'r> { |
| 484 | status: Option<Status>, |
| 485 | headers: HeaderMap<'r>, |
| 486 | body: Body<'r>, |
| 487 | upgrade: HashMap<Uncased<'r>, Box<dyn IoHandler + 'r>>, |
| 488 | } |
| 489 | |
| 490 | impl<'r> Response<'r> { |
| 491 | /// Creates a new, empty `Response` without a status, body, or headers. |
| 492 | /// Because all HTTP responses must have a status, if a default `Response` |
| 493 | /// is written to the client without a status, the status defaults to `200 |
| 494 | /// Ok`. |
| 495 | /// |
| 496 | /// # Example |
| 497 | /// |
| 498 | /// ```rust |
| 499 | /// use rocket::Response; |
| 500 | /// use rocket::http::Status; |
| 501 | /// |
| 502 | /// let mut response = Response::new(); |
| 503 | /// |
| 504 | /// assert_eq!(response.status(), Status::Ok); |
| 505 | /// assert_eq!(response.headers().len(), 0); |
| 506 | /// assert!(response.body().is_none()); |
| 507 | /// ``` |
| 508 | #[inline(always)] |
| 509 | pub fn new() -> Response<'r> { |
| 510 | Response::default() |
| 511 | } |
| 512 | |
| 513 | /// Returns a `Builder` with a base of `Response::new()`. |
| 514 | /// |
| 515 | /// # Example |
| 516 | /// |
| 517 | /// ```rust |
| 518 | /// use rocket::Response; |
| 519 | /// |
| 520 | /// # #[allow(unused_variables)] |
| 521 | /// let builder = Response::build(); |
| 522 | /// ``` |
| 523 | #[inline(always)] |
| 524 | pub fn build() -> Builder<'r> { |
| 525 | Response::build_from(Response::new()) |
| 526 | } |
| 527 | |
| 528 | /// Returns a `Builder` with a base of `other`. |
| 529 | /// |
| 530 | /// # Example |
| 531 | /// |
| 532 | /// ```rust |
| 533 | /// # #![allow(unused_variables)] |
| 534 | /// use rocket::Response; |
| 535 | /// |
| 536 | /// let other = Response::new(); |
| 537 | /// let builder = Response::build_from(other); |
| 538 | /// ``` |
| 539 | #[inline(always)] |
| 540 | pub fn build_from(other: Response<'r>) -> Builder<'r> { |
| 541 | Builder::new(other) |
| 542 | } |
| 543 | |
| 544 | /// Returns the status of `self`. |
| 545 | /// |
| 546 | /// # Example |
| 547 | /// |
| 548 | /// ```rust |
| 549 | /// use rocket::Response; |
| 550 | /// use rocket::http::Status; |
| 551 | /// |
| 552 | /// let mut response = Response::new(); |
| 553 | /// assert_eq!(response.status(), Status::Ok); |
| 554 | /// |
| 555 | /// response.set_status(Status::NotFound); |
| 556 | /// assert_eq!(response.status(), Status::NotFound); |
| 557 | /// ``` |
| 558 | #[inline(always)] |
| 559 | pub fn status(&self) -> Status { |
| 560 | self.status.unwrap_or(Status::Ok) |
| 561 | } |
| 562 | |
| 563 | /// Sets the status of `self` to `status`. |
| 564 | /// |
| 565 | /// # Example |
| 566 | /// |
| 567 | /// ```rust |
| 568 | /// use rocket::Response; |
| 569 | /// use rocket::http::Status; |
| 570 | /// |
| 571 | /// let mut response = Response::new(); |
| 572 | /// response.set_status(Status::ImATeapot); |
| 573 | /// assert_eq!(response.status(), Status::ImATeapot); |
| 574 | /// ``` |
| 575 | #[inline(always)] |
| 576 | pub fn set_status(&mut self, status: Status) { |
| 577 | self.status = Some(status); |
| 578 | } |
| 579 | |
| 580 | /// Returns the Content-Type header of `self`. If the header is not present |
| 581 | /// or is malformed, returns `None`. |
| 582 | /// |
| 583 | /// # Example |
| 584 | /// |
| 585 | /// ```rust |
| 586 | /// use rocket::Response; |
| 587 | /// use rocket::http::ContentType; |
| 588 | /// |
| 589 | /// let mut response = Response::new(); |
| 590 | /// response.set_header(ContentType::HTML); |
| 591 | /// assert_eq!(response.content_type(), Some(ContentType::HTML)); |
| 592 | /// ``` |
| 593 | #[inline(always)] |
| 594 | pub fn content_type(&self) -> Option<ContentType> { |
| 595 | self.headers().get_one("Content-Type").and_then(|v| v.parse().ok()) |
| 596 | } |
| 597 | |
| 598 | /// Returns an iterator over the cookies in `self` as identified by the |
| 599 | /// `Set-Cookie` header. Malformed cookies are skipped. |
| 600 | /// |
| 601 | /// # Example |
| 602 | /// |
| 603 | /// ```rust |
| 604 | /// use rocket::Response; |
| 605 | /// use rocket::http::Cookie; |
| 606 | /// |
| 607 | /// let mut response = Response::new(); |
| 608 | /// response.set_header(Cookie::new("hello", "world!")); |
| 609 | /// let cookies: Vec<_> = response.cookies().collect(); |
| 610 | /// assert_eq!(cookies, vec![Cookie::new("hello", "world!")]); |
| 611 | /// ``` |
| 612 | pub fn cookies(&self) -> impl Iterator<Item = Cookie<'_>> { |
| 613 | self.headers() |
| 614 | .get("Set-Cookie") |
| 615 | .filter_map(|header| Cookie::parse_encoded(header).ok()) |
| 616 | } |
| 617 | |
| 618 | /// Returns a [`HeaderMap`] of all of the headers in `self`. |
| 619 | /// |
| 620 | /// # Example |
| 621 | /// |
| 622 | /// ```rust |
| 623 | /// use rocket::Response; |
| 624 | /// use rocket::http::Header; |
| 625 | /// |
| 626 | /// let mut response = Response::new(); |
| 627 | /// response.adjoin_raw_header("X-Custom", "1"); |
| 628 | /// response.adjoin_raw_header("X-Custom", "2"); |
| 629 | /// |
| 630 | /// let mut custom_headers = response.headers().iter(); |
| 631 | /// assert_eq!(custom_headers.next(), Some(Header::new("X-Custom", "1"))); |
| 632 | /// assert_eq!(custom_headers.next(), Some(Header::new("X-Custom", "2"))); |
| 633 | /// assert_eq!(custom_headers.next(), None); |
| 634 | /// ``` |
| 635 | #[inline(always)] |
| 636 | pub fn headers(&self) -> &HeaderMap<'r> { |
| 637 | &self.headers |
| 638 | } |
| 639 | |
| 640 | pub fn set_header_map<'h: 'r>(&mut self, headers: HeaderMap<'h>) { |
| 641 | self.headers = headers; |
| 642 | } |
| 643 | |
| 644 | /// Sets the header `header` in `self`. Any existing headers with the name |
| 645 | /// `header.name` will be lost, and only `header` will remain. The type of |
| 646 | /// `header` can be any type that implements `Into<Header>`. See [trait |
| 647 | /// implementations](Header#trait-implementations). |
| 648 | /// |
| 649 | /// # Example |
| 650 | /// |
| 651 | /// ```rust |
| 652 | /// use rocket::Response; |
| 653 | /// use rocket::http::ContentType; |
| 654 | /// |
| 655 | /// let mut response = Response::new(); |
| 656 | /// |
| 657 | /// response.set_header(ContentType::HTML); |
| 658 | /// assert_eq!(response.headers().iter().next(), Some(ContentType::HTML.into())); |
| 659 | /// assert_eq!(response.headers().len(), 1); |
| 660 | /// |
| 661 | /// response.set_header(ContentType::JSON); |
| 662 | /// assert_eq!(response.headers().iter().next(), Some(ContentType::JSON.into())); |
| 663 | /// assert_eq!(response.headers().len(), 1); |
| 664 | /// ``` |
| 665 | #[inline(always)] |
| 666 | pub fn set_header<'h: 'r, H: Into<Header<'h>>>(&mut self, header: H) -> bool { |
| 667 | self.headers.replace(header) |
| 668 | } |
| 669 | |
| 670 | /// Sets the custom header with name `name` and value `value` in `self`. Any |
| 671 | /// existing headers with the same `name` will be lost, and the new custom |
| 672 | /// header will remain. This method should be used sparingly; prefer to use |
| 673 | /// [set_header](#method.set_header) instead. |
| 674 | /// |
| 675 | /// # Example |
| 676 | /// |
| 677 | /// ```rust |
| 678 | /// use rocket::Response; |
| 679 | /// use rocket::http::Header; |
| 680 | /// |
| 681 | /// let mut response = Response::new(); |
| 682 | /// |
| 683 | /// response.set_raw_header("X-Custom", "1"); |
| 684 | /// assert_eq!(response.headers().get_one("X-Custom"), Some("1")); |
| 685 | /// assert_eq!(response.headers().len(), 1); |
| 686 | /// |
| 687 | /// response.set_raw_header("X-Custom", "2"); |
| 688 | /// assert_eq!(response.headers().get_one("X-Custom"), Some("2")); |
| 689 | /// assert_eq!(response.headers().len(), 1); |
| 690 | /// ``` |
| 691 | #[inline(always)] |
| 692 | pub fn set_raw_header<'a: 'r, 'b: 'r, N, V>(&mut self, name: N, value: V) -> bool |
| 693 | where N: Into<Cow<'a, str>>, V: Into<Cow<'b, str>> |
| 694 | { |
| 695 | self.set_header(Header::new(name, value)) |
| 696 | } |
| 697 | |
| 698 | /// Adds the header `header` to `self`. If `self` contains headers with the |
| 699 | /// name `header.name`, another header with the same name and value |
| 700 | /// `header.value` is added. The type of `header` can be any type that |
| 701 | /// implements `Into<Header>`. This includes `Header` itself, |
| 702 | /// [`ContentType`](crate::http::ContentType), |
| 703 | /// [`Accept`](crate::http::Accept). |
| 704 | /// |
| 705 | /// # Example |
| 706 | /// |
| 707 | /// ```rust |
| 708 | /// use rocket::Response; |
| 709 | /// use rocket::http::{Header, Accept}; |
| 710 | /// |
| 711 | /// let mut response = Response::new(); |
| 712 | /// response.adjoin_header(Accept::JSON); |
| 713 | /// response.adjoin_header(Header::new("Accept", "text/plain")); |
| 714 | /// |
| 715 | /// let mut accept_headers = response.headers().iter(); |
| 716 | /// assert_eq!(accept_headers.next(), Some(Header::new("Accept", "application/json"))); |
| 717 | /// assert_eq!(accept_headers.next(), Some(Header::new("Accept", "text/plain"))); |
| 718 | /// assert_eq!(accept_headers.next(), None); |
| 719 | /// ``` |
| 720 | #[inline(always)] |
| 721 | pub fn adjoin_header<'h: 'r, H: Into<Header<'h>>>(&mut self, header: H) { |
| 722 | self.headers.add(header) |
| 723 | } |
| 724 | |
| 725 | /// Adds a custom header with name `name` and value `value` to `self`. If |
| 726 | /// `self` already contains headers with the name `name`, another header |
| 727 | /// with the same `name` and `value` is added. |
| 728 | /// |
| 729 | /// # Example |
| 730 | /// |
| 731 | /// ```rust |
| 732 | /// use rocket::Response; |
| 733 | /// use rocket::http::Header; |
| 734 | /// |
| 735 | /// let mut response = Response::new(); |
| 736 | /// response.adjoin_raw_header("X-Custom", "one"); |
| 737 | /// response.adjoin_raw_header("X-Custom", "two"); |
| 738 | /// |
| 739 | /// let mut custom_headers = response.headers().iter(); |
| 740 | /// assert_eq!(custom_headers.next(), Some(Header::new("X-Custom", "one"))); |
| 741 | /// assert_eq!(custom_headers.next(), Some(Header::new("X-Custom", "two"))); |
| 742 | /// assert_eq!(custom_headers.next(), None); |
| 743 | /// ``` |
| 744 | #[inline(always)] |
| 745 | pub fn adjoin_raw_header<'a: 'r, 'b: 'r, N, V>(&mut self, name: N, value: V) |
| 746 | where N: Into<Cow<'a, str>>, V: Into<Cow<'b, str>> |
| 747 | { |
| 748 | self.adjoin_header(Header::new(name, value)); |
| 749 | } |
| 750 | |
| 751 | /// Removes all headers with the name `name`. |
| 752 | /// |
| 753 | /// # Example |
| 754 | /// |
| 755 | /// ```rust |
| 756 | /// use rocket::Response; |
| 757 | /// |
| 758 | /// let mut response = Response::new(); |
| 759 | /// |
| 760 | /// response.adjoin_raw_header("X-Custom", "one"); |
| 761 | /// response.adjoin_raw_header("X-Custom", "two"); |
| 762 | /// response.adjoin_raw_header("X-Other", "hi"); |
| 763 | /// assert_eq!(response.headers().len(), 3); |
| 764 | /// |
| 765 | /// response.remove_header("X-Custom"); |
| 766 | /// assert_eq!(response.headers().len(), 1); |
| 767 | /// ``` |
| 768 | #[inline(always)] |
| 769 | pub fn remove_header(&mut self, name: &str) { |
| 770 | self.headers.remove(name); |
| 771 | } |
| 772 | |
| 773 | /// Returns an immutable borrow of the body of `self`, if there is one. |
| 774 | /// |
| 775 | /// # Example |
| 776 | /// |
| 777 | /// ```rust |
| 778 | /// use std::io::Cursor; |
| 779 | /// use rocket::Response; |
| 780 | /// |
| 781 | /// # rocket::async_test(async { |
| 782 | /// let mut response = Response::new(); |
| 783 | /// assert!(response.body().is_none()); |
| 784 | /// |
| 785 | /// let string = "Hello, world!"; |
| 786 | /// response.set_sized_body(string.len(), Cursor::new(string)); |
| 787 | /// assert!(response.body().is_some()); |
| 788 | /// # }) |
| 789 | /// ``` |
| 790 | #[inline(always)] |
| 791 | pub fn body(&self) -> &Body<'r> { |
| 792 | &self.body |
| 793 | } |
| 794 | |
| 795 | /// Returns `Ok(Some(_))` if `self` contains a suitable handler for any of |
| 796 | /// the comma-separated protocol strings in `I`. Returns `Err(_)` if |
| 797 | /// `protocols` is non-empty but no match was found in `self`. If `self` |
| 798 | /// doesn't support any kind of upgrade, return `Ok(None)`. |
| 799 | pub(crate) fn search_upgrades<'a, I: Iterator<Item = &'a str>>( |
| 800 | &mut self, |
| 801 | protocols: I |
| 802 | ) -> Result<Option<(Uncased<'r>, Box<dyn IoHandler + 'r>)>, ()> { |
| 803 | if self.upgrade.is_empty() { |
| 804 | return Ok(None); |
| 805 | } |
| 806 | |
| 807 | let mut protocols = protocols.peekable(); |
| 808 | let have_protocols = protocols.peek().is_some(); |
| 809 | let found = protocols |
| 810 | .flat_map(|v| v.split(',').map(str::trim)) |
| 811 | .find_map(|p| self.upgrade.remove_entry(p.as_uncased())); |
| 812 | |
| 813 | match found { |
| 814 | Some(handler) => Ok(Some(handler)), |
| 815 | None if have_protocols => Err(()), |
| 816 | None => Ok(None) |
| 817 | } |
| 818 | } |
| 819 | |
| 820 | /// Returns the [`IoHandler`] for the protocol `proto`. |
| 821 | /// |
| 822 | /// Returns `Some` if such a handler was registered via |
| 823 | /// [`Response::add_upgrade()`] or the corresponding builder method |
| 824 | /// [`upgrade()`](Builder::upgrade()). Otherwise returns `None`. |
| 825 | /// |
| 826 | /// ```rust |
| 827 | /// use std::pin::Pin; |
| 828 | /// |
| 829 | /// use rocket::Response; |
| 830 | /// use rocket::data::{IoHandler, IoStream}; |
| 831 | /// use rocket::tokio::io; |
| 832 | /// |
| 833 | /// struct EchoHandler; |
| 834 | /// |
| 835 | /// #[rocket::async_trait] |
| 836 | /// impl IoHandler for EchoHandler { |
| 837 | /// async fn io(self: Box<Self>, io: IoStream) -> io::Result<()> { |
| 838 | /// let (mut reader, mut writer) = io::split(io); |
| 839 | /// io::copy(&mut reader, &mut writer).await?; |
| 840 | /// Ok(()) |
| 841 | /// } |
| 842 | /// } |
| 843 | /// |
| 844 | /// # rocket::async_test(async { |
| 845 | /// let mut response = Response::new(); |
| 846 | /// assert!(response.upgrade("raw-echo").is_none()); |
| 847 | /// |
| 848 | /// response.add_upgrade("raw-echo", EchoHandler); |
| 849 | /// assert!(response.upgrade("raw-echo").is_some()); |
| 850 | /// # }) |
| 851 | /// ``` |
| 852 | pub fn upgrade(&mut self, proto: &str) -> Option<&mut (dyn IoHandler + 'r)> { |
| 853 | self.upgrade.get_mut(proto.as_uncased()).map(|h| h.as_mut()) |
| 854 | } |
| 855 | |
| 856 | /// Returns a mutable borrow of the body of `self`, if there is one. A |
| 857 | /// mutable borrow allows for reading the body. |
| 858 | /// |
| 859 | /// # Example |
| 860 | /// |
| 861 | /// ```rust |
| 862 | /// use std::io::Cursor; |
| 863 | /// use rocket::Response; |
| 864 | /// |
| 865 | /// # rocket::async_test(async { |
| 866 | /// let mut response = Response::new(); |
| 867 | /// assert!(response.body().is_none()); |
| 868 | /// |
| 869 | /// let string = "Hello, world!"; |
| 870 | /// response.set_sized_body(string.len(), Cursor::new(string)); |
| 871 | /// let string = response.body_mut().to_string().await; |
| 872 | /// assert_eq!(string.unwrap(), "Hello, world!"); |
| 873 | /// # }) |
| 874 | /// ``` |
| 875 | #[inline(always)] |
| 876 | pub fn body_mut(&mut self) -> &mut Body<'r> { |
| 877 | &mut self.body |
| 878 | } |
| 879 | |
| 880 | // Makes the `AsyncRead`er in the body empty but leaves the size of the body |
| 881 | // if it exists. Meant to be used during HEAD handling. |
| 882 | #[inline(always)] |
| 883 | pub(crate) fn strip_body(&mut self) { |
| 884 | self.body.strip(); |
| 885 | } |
| 886 | |
| 887 | /// Sets the body of `self` to be the fixed-sized `body` with size |
| 888 | /// `size`, which may be `None`. If `size` is `None`, the body's size will |
| 889 | /// be computing with calls to `seek` just before being written out in a |
| 890 | /// response. |
| 891 | /// |
| 892 | /// # Example |
| 893 | /// |
| 894 | /// ```rust |
| 895 | /// use std::io; |
| 896 | /// use rocket::Response; |
| 897 | /// |
| 898 | /// # let o: io::Result<()> = rocket::async_test(async { |
| 899 | /// let string = "Hello, world!"; |
| 900 | /// |
| 901 | /// let mut response = Response::new(); |
| 902 | /// response.set_sized_body(string.len(), io::Cursor::new(string)); |
| 903 | /// assert_eq!(response.body_mut().to_string().await?, "Hello, world!"); |
| 904 | /// # Ok(()) |
| 905 | /// # }); |
| 906 | /// # assert!(o.is_ok()); |
| 907 | /// ``` |
| 908 | pub fn set_sized_body<B, S>(&mut self, size: S, body: B) |
| 909 | where B: AsyncRead + AsyncSeek + Send + 'r, |
| 910 | S: Into<Option<usize>> |
| 911 | { |
| 912 | self.body = Body::with_sized(body, size.into()); |
| 913 | } |
| 914 | |
| 915 | /// Sets the body of `self` to `body`, which will be streamed. |
| 916 | /// |
| 917 | /// The max chunk size is configured via [`Response::set_max_chunk_size()`] |
| 918 | /// and defaults to [`Body::DEFAULT_MAX_CHUNK`]. |
| 919 | /// |
| 920 | /// # Example |
| 921 | /// |
| 922 | /// ```rust |
| 923 | /// # use std::io; |
| 924 | /// use tokio::io::{repeat, AsyncReadExt}; |
| 925 | /// use rocket::Response; |
| 926 | /// |
| 927 | /// # let o: io::Result<()> = rocket::async_test(async { |
| 928 | /// let mut response = Response::new(); |
| 929 | /// response.set_streamed_body(repeat(97).take(5)); |
| 930 | /// assert_eq!(response.body_mut().to_string().await?, "aaaaa"); |
| 931 | /// # Ok(()) |
| 932 | /// # }); |
| 933 | /// # assert!(o.is_ok()); |
| 934 | /// ``` |
| 935 | #[inline(always)] |
| 936 | pub fn set_streamed_body<B>(&mut self, body: B) |
| 937 | where B: AsyncRead + Send + 'r |
| 938 | { |
| 939 | self.body = Body::with_unsized(body); |
| 940 | } |
| 941 | |
| 942 | /// Registers `handler` as the I/O handler for upgrade protocol `protocol`. |
| 943 | /// |
| 944 | /// Responses registering I/O handlers for upgraded protocols **should not** |
| 945 | /// set the response status to `101`, nor set the `Connection` or `Upgrade` |
| 946 | /// headers. Rocket automatically sets these headers as needed. See |
| 947 | /// [`Response`#upgrading] for details. |
| 948 | /// |
| 949 | /// If a handler was previously registered for `protocol`, this `handler` |
| 950 | /// replaces it. If the connection is upgraded to `protocol`, the last |
| 951 | /// `handler` registered for the protocol is used to handle the connection. |
| 952 | /// See [`IoHandler`] for details on implementing an I/O handler. For |
| 953 | /// details on connection upgrading, see [`Response`#upgrading]. |
| 954 | /// |
| 955 | /// [`Response`#upgrading]: Response#upgrading |
| 956 | /// |
| 957 | /// # Example |
| 958 | /// |
| 959 | /// ```rust |
| 960 | /// use std::pin::Pin; |
| 961 | /// |
| 962 | /// use rocket::Response; |
| 963 | /// use rocket::data::{IoHandler, IoStream}; |
| 964 | /// use rocket::tokio::io; |
| 965 | /// |
| 966 | /// struct EchoHandler; |
| 967 | /// |
| 968 | /// #[rocket::async_trait] |
| 969 | /// impl IoHandler for EchoHandler { |
| 970 | /// async fn io(self: Box<Self>, io: IoStream) -> io::Result<()> { |
| 971 | /// let (mut reader, mut writer) = io::split(io); |
| 972 | /// io::copy(&mut reader, &mut writer).await?; |
| 973 | /// Ok(()) |
| 974 | /// } |
| 975 | /// } |
| 976 | /// |
| 977 | /// # rocket::async_test(async { |
| 978 | /// let mut response = Response::new(); |
| 979 | /// assert!(response.upgrade("raw-echo").is_none()); |
| 980 | /// |
| 981 | /// response.add_upgrade("raw-echo", EchoHandler); |
| 982 | /// assert!(response.upgrade("raw-echo").is_some()); |
| 983 | /// # }) |
| 984 | /// ``` |
| 985 | pub fn add_upgrade<N, H>(&mut self, protocol: N, handler: H) |
| 986 | where N: Into<Uncased<'r>>, H: IoHandler + 'r |
| 987 | { |
| 988 | self.upgrade.insert(protocol.into(), Box::new(handler)); |
| 989 | } |
| 990 | |
| 991 | /// Sets the body's maximum chunk size to `size` bytes. |
| 992 | /// |
| 993 | /// The default max chunk size is [`Body::DEFAULT_MAX_CHUNK`]. The max chunk |
| 994 | /// size is a property of the body and is thus reset whenever a body is set |
| 995 | /// via [`Response::set_streamed_body()`], [`Response::set_sized_body()`], |
| 996 | /// or the corresponding builder methods. |
| 997 | /// |
| 998 | /// This setting does not typically need to be changed. Configuring a high |
| 999 | /// value can result in high memory usage. Similarly, configuring a low |
| 1000 | /// value can result in excessive network writes. When unsure, leave the |
| 1001 | /// value unchanged. |
| 1002 | /// |
| 1003 | /// # Example |
| 1004 | /// |
| 1005 | /// ```rust |
| 1006 | /// use tokio::io::{repeat, AsyncReadExt}; |
| 1007 | /// use rocket::Response; |
| 1008 | /// |
| 1009 | /// # let o: Option<()> = rocket::async_test(async { |
| 1010 | /// let mut response = Response::new(); |
| 1011 | /// response.set_streamed_body(repeat(97).take(5)); |
| 1012 | /// response.set_max_chunk_size(3072); |
| 1013 | /// # Some(()) |
| 1014 | /// # }); |
| 1015 | /// # assert!(o.is_some()); |
| 1016 | #[inline(always)] |
| 1017 | pub fn set_max_chunk_size(&mut self, size: usize) { |
| 1018 | self.body_mut().set_max_chunk_size(size); |
| 1019 | } |
| 1020 | |
| 1021 | /// Replaces this response's status and body with that of `other`, if they |
| 1022 | /// exist in `other`. Any headers that exist in `other` replace the ones in |
| 1023 | /// `self`. Any in `self` that aren't in `other` remain in `self`. |
| 1024 | /// |
| 1025 | /// # Example |
| 1026 | /// |
| 1027 | /// ```rust |
| 1028 | /// use rocket::Response; |
| 1029 | /// use rocket::http::{Status, ContentType}; |
| 1030 | /// |
| 1031 | /// let base = Response::build() |
| 1032 | /// .status(Status::NotFound) |
| 1033 | /// .header(ContentType::HTML) |
| 1034 | /// .raw_header("X-Custom", "value 1") |
| 1035 | /// .finalize(); |
| 1036 | /// |
| 1037 | /// let response = Response::build() |
| 1038 | /// .status(Status::ImATeapot) |
| 1039 | /// .raw_header("X-Custom", "value 2") |
| 1040 | /// .raw_header_adjoin("X-Custom", "value 3") |
| 1041 | /// .merge(base) |
| 1042 | /// .finalize(); |
| 1043 | /// |
| 1044 | /// assert_eq!(response.status(), Status::NotFound); |
| 1045 | /// |
| 1046 | /// let ctype: Vec<_> = response.headers().get("Content-Type").collect(); |
| 1047 | /// assert_eq!(ctype, vec![ContentType::HTML.to_string()]); |
| 1048 | /// |
| 1049 | /// let custom_values: Vec<_> = response.headers().get("X-Custom").collect(); |
| 1050 | /// assert_eq!(custom_values, vec!["value 1"]); |
| 1051 | /// ``` |
| 1052 | pub fn merge(&mut self, other: Response<'r>) { |
| 1053 | if let Some(status) = other.status { |
| 1054 | self.status = Some(status); |
| 1055 | } |
| 1056 | |
| 1057 | if other.body().is_some() { |
| 1058 | self.body = other.body; |
| 1059 | } |
| 1060 | |
| 1061 | for (name, values) in other.headers.into_iter_raw() { |
| 1062 | self.headers.replace_all(name.into_cow(), values); |
| 1063 | } |
| 1064 | } |
| 1065 | |
| 1066 | /// Sets `self`'s status and body to that of `other` if they are not already |
| 1067 | /// set in `self`. Any headers present in both `other` and `self` are |
| 1068 | /// adjoined. |
| 1069 | /// |
| 1070 | /// # Example |
| 1071 | /// |
| 1072 | /// ```rust |
| 1073 | /// use rocket::Response; |
| 1074 | /// use rocket::http::{Status, ContentType}; |
| 1075 | /// |
| 1076 | /// let other = Response::build() |
| 1077 | /// .status(Status::NotFound) |
| 1078 | /// .header(ContentType::HTML) |
| 1079 | /// .raw_header("X-Custom", "value 1") |
| 1080 | /// .finalize(); |
| 1081 | /// |
| 1082 | /// let response = Response::build() |
| 1083 | /// .status(Status::ImATeapot) |
| 1084 | /// .raw_header("X-Custom", "value 2") |
| 1085 | /// .raw_header_adjoin("X-Custom", "value 3") |
| 1086 | /// .join(other) |
| 1087 | /// .finalize(); |
| 1088 | /// |
| 1089 | /// assert_eq!(response.status(), Status::ImATeapot); |
| 1090 | /// |
| 1091 | /// let ctype: Vec<_> = response.headers().get("Content-Type").collect(); |
| 1092 | /// assert_eq!(ctype, vec![ContentType::HTML.to_string()]); |
| 1093 | /// |
| 1094 | /// let custom_values: Vec<_> = response.headers().get("X-Custom").collect(); |
| 1095 | /// assert_eq!(custom_values, vec!["value 2", "value 3", "value 1"]); |
| 1096 | /// ``` |
| 1097 | pub fn join(&mut self, other: Response<'r>) { |
| 1098 | if self.status.is_none() { |
| 1099 | self.status = other.status; |
| 1100 | } |
| 1101 | |
| 1102 | if self.body.is_none() { |
| 1103 | self.body = other.body; |
| 1104 | } |
| 1105 | |
| 1106 | for (name, mut values) in other.headers.into_iter_raw() { |
| 1107 | self.headers.add_all(name.into_cow(), &mut values); |
| 1108 | } |
| 1109 | } |
| 1110 | } |
| 1111 | |
| 1112 | impl fmt::Debug for Response<'_> { |
| 1113 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1114 | writeln!(f, "{}", self.status())?; |
| 1115 | |
| 1116 | for header in self.headers().iter() { |
| 1117 | writeln!(f, "{}", header)?; |
| 1118 | } |
| 1119 | |
| 1120 | self.body.fmt(f) |
| 1121 | } |
| 1122 | } |