refactor(ffi): Add Reason-Phrase API
This adds an internal ability to copy the HTTP/1 reason-phrase and place it in the `http::Extensions` of a response, if it doesn't match the canonical reason. This could be exposed in the Rust API later, but for now it is only used by the C API.
This commit is contained in:
		| @@ -23,6 +23,9 @@ pub struct hyper_headers { | ||||
| #[derive(Debug, Default)] | ||||
| pub(crate) struct HeaderCaseMap(HeaderMap<Bytes>); | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub(crate) struct ReasonPhrase(pub(crate) Bytes); | ||||
|  | ||||
| // ===== impl hyper_request ===== | ||||
|  | ||||
| ffi_fn! { | ||||
| @@ -150,6 +153,30 @@ ffi_fn! { | ||||
|     } | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
|     /// Get a pointer to the reason-phrase of this response. | ||||
|     /// | ||||
|     /// This buffer is not null-terminated. | ||||
|     /// | ||||
|     /// This buffer is owned by the response, and should not be used after | ||||
|     /// the response has been freed. | ||||
|     /// | ||||
|     /// Use `hyper_response_reason_phrase_len()` to get the length of this | ||||
|     /// buffer. | ||||
|     fn hyper_response_reason_phrase(resp: *const hyper_response) -> *const u8 { | ||||
|         unsafe { &*resp }.reason_phrase().as_ptr() | ||||
|     } | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
|     /// Get the length of the reason-phrase of this response. | ||||
|     /// | ||||
|     /// Use `hyper_response_reason_phrase()` to get the buffer pointer. | ||||
|     fn hyper_response_reason_phrase_len(resp: *const hyper_response) -> size_t { | ||||
|         unsafe { &*resp }.reason_phrase().len() | ||||
|     } | ||||
| } | ||||
|  | ||||
| ffi_fn! { | ||||
|     /// Get the HTTP version used by this response. | ||||
|     /// | ||||
| @@ -205,6 +232,18 @@ impl hyper_response { | ||||
|  | ||||
|         hyper_response(resp) | ||||
|     } | ||||
|  | ||||
|     fn reason_phrase(&self) -> &[u8] { | ||||
|         if let Some(reason) = self.0.extensions().get::<ReasonPhrase>() { | ||||
|             return &reason.0; | ||||
|         } | ||||
|  | ||||
|         if let Some(reason) = self.0.status().canonical_reason() { | ||||
|             return reason.as_bytes(); | ||||
|         } | ||||
|  | ||||
|         &[] | ||||
|     } | ||||
| } | ||||
|  | ||||
| unsafe impl AsTaskType for hyper_response { | ||||
|   | ||||
| @@ -28,7 +28,7 @@ mod io; | ||||
| mod task; | ||||
|  | ||||
| pub(crate) use self::body::UserBody; | ||||
| pub(crate) use self::http_types::HeaderCaseMap; | ||||
| pub(crate) use self::http_types::{HeaderCaseMap, ReasonPhrase}; | ||||
|  | ||||
| pub const HYPER_ITER_CONTINUE: libc::c_int = 0; | ||||
| #[allow(unused)] | ||||
|   | ||||
| @@ -5,6 +5,8 @@ | ||||
| use std::fmt::{self, Write}; | ||||
| use std::mem; | ||||
|  | ||||
| #[cfg(feature = "ffi")] | ||||
| use bytes::Bytes; | ||||
| use bytes::BytesMut; | ||||
| use http::header::{self, Entry, HeaderName, HeaderValue}; | ||||
| use http::{HeaderMap, Method, StatusCode, Version}; | ||||
| @@ -660,7 +662,7 @@ impl Http1Transaction for Client { | ||||
|         loop { | ||||
|             // Unsafe: see comment in Server Http1Transaction, above. | ||||
|             let mut headers_indices: [HeaderIndices; MAX_HEADERS] = unsafe { mem::uninitialized() }; | ||||
|             let (len, status, version, headers_len) = { | ||||
|             let (len, status, reason, version, headers_len) = { | ||||
|                 let mut headers: [httparse::Header<'_>; MAX_HEADERS] = | ||||
|                     unsafe { mem::uninitialized() }; | ||||
|                 trace!( | ||||
| @@ -674,6 +676,20 @@ impl Http1Transaction for Client { | ||||
|                     httparse::Status::Complete(len) => { | ||||
|                         trace!("Response.parse Complete({})", len); | ||||
|                         let status = StatusCode::from_u16(res.code.unwrap())?; | ||||
|  | ||||
|                         #[cfg(not(feature = "ffi"))] | ||||
|                         let reason = (); | ||||
|                         #[cfg(feature = "ffi")] | ||||
|                         let reason = { | ||||
|                             let reason = res.reason.unwrap(); | ||||
|                             // Only save the reason phrase if it isnt the canonical reason | ||||
|                             if Some(reason) != status.canonical_reason() { | ||||
|                                 Some(Bytes::copy_from_slice(reason.as_bytes())) | ||||
|                             } else { | ||||
|                                 None | ||||
|                             } | ||||
|                         }; | ||||
|  | ||||
|                         let version = if res.version.unwrap() == 1 { | ||||
|                             Version::HTTP_11 | ||||
|                         } else { | ||||
| @@ -681,7 +697,7 @@ impl Http1Transaction for Client { | ||||
|                         }; | ||||
|                         record_header_indices(bytes, &res.headers, &mut headers_indices)?; | ||||
|                         let headers_len = res.headers.len(); | ||||
|                         (len, status, version, headers_len) | ||||
|                         (len, status, reason, version, headers_len) | ||||
|                     } | ||||
|                     httparse::Status::Partial => return Ok(None), | ||||
|                 } | ||||
| @@ -728,6 +744,13 @@ impl Http1Transaction for Client { | ||||
|                 extensions.insert(header_case_map); | ||||
|             } | ||||
|  | ||||
|             #[cfg(feature = "ffi")] | ||||
|             if let Some(reason) = reason { | ||||
|                 extensions.insert(crate::ffi::ReasonPhrase(reason)); | ||||
|             } | ||||
|             #[cfg(not(feature = "ffi"))] | ||||
|             drop(reason); | ||||
|  | ||||
|             let head = MessageHead { | ||||
|                 version, | ||||
|                 subject: status, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user