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:
@@ -254,8 +254,10 @@ int main(int argc, char *argv[]) {
|
|||||||
hyper_task_free(task);
|
hyper_task_free(task);
|
||||||
|
|
||||||
uint16_t http_status = hyper_response_status(resp);
|
uint16_t http_status = hyper_response_status(resp);
|
||||||
|
const uint8_t *rp = hyper_response_reason_phrase(resp);
|
||||||
|
size_t rp_len = hyper_response_reason_phrase_len(resp);
|
||||||
|
|
||||||
printf("\nResponse Status: %d\n", http_status);
|
printf("\nResponse Status: %d %.*s\n", http_status, (int) rp_len, rp);
|
||||||
|
|
||||||
hyper_headers *headers = hyper_response_headers(resp);
|
hyper_headers *headers = hyper_response_headers(resp);
|
||||||
hyper_headers_foreach(headers, print_each_header, NULL);
|
hyper_headers_foreach(headers, print_each_header, NULL);
|
||||||
|
|||||||
@@ -349,6 +349,26 @@ void hyper_response_free(hyper_response *resp);
|
|||||||
*/
|
*/
|
||||||
uint16_t hyper_response_status(const hyper_response *resp);
|
uint16_t hyper_response_status(const hyper_response *resp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
const uint8_t *hyper_response_reason_phrase(const hyper_response *resp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the length of the reason-phrase of this response.
|
||||||
|
|
||||||
|
Use `hyper_response_reason_phrase()` to get the buffer pointer.
|
||||||
|
*/
|
||||||
|
size_t hyper_response_reason_phrase_len(const hyper_response *resp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get the HTTP version used by this response.
|
Get the HTTP version used by this response.
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ pub struct hyper_headers {
|
|||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct HeaderCaseMap(HeaderMap<Bytes>);
|
pub(crate) struct HeaderCaseMap(HeaderMap<Bytes>);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct ReasonPhrase(pub(crate) Bytes);
|
||||||
|
|
||||||
// ===== impl hyper_request =====
|
// ===== impl hyper_request =====
|
||||||
|
|
||||||
ffi_fn! {
|
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! {
|
ffi_fn! {
|
||||||
/// Get the HTTP version used by this response.
|
/// Get the HTTP version used by this response.
|
||||||
///
|
///
|
||||||
@@ -205,6 +232,18 @@ impl hyper_response {
|
|||||||
|
|
||||||
hyper_response(resp)
|
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 {
|
unsafe impl AsTaskType for hyper_response {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ mod io;
|
|||||||
mod task;
|
mod task;
|
||||||
|
|
||||||
pub(crate) use self::body::UserBody;
|
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;
|
pub const HYPER_ITER_CONTINUE: libc::c_int = 0;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
#[cfg(feature = "ffi")]
|
||||||
|
use bytes::Bytes;
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use http::header::{self, Entry, HeaderName, HeaderValue};
|
use http::header::{self, Entry, HeaderName, HeaderValue};
|
||||||
use http::{HeaderMap, Method, StatusCode, Version};
|
use http::{HeaderMap, Method, StatusCode, Version};
|
||||||
@@ -660,7 +662,7 @@ impl Http1Transaction for Client {
|
|||||||
loop {
|
loop {
|
||||||
// Unsafe: see comment in Server Http1Transaction, above.
|
// Unsafe: see comment in Server Http1Transaction, above.
|
||||||
let mut headers_indices: [HeaderIndices; MAX_HEADERS] = unsafe { mem::uninitialized() };
|
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] =
|
let mut headers: [httparse::Header<'_>; MAX_HEADERS] =
|
||||||
unsafe { mem::uninitialized() };
|
unsafe { mem::uninitialized() };
|
||||||
trace!(
|
trace!(
|
||||||
@@ -674,6 +676,20 @@ impl Http1Transaction for Client {
|
|||||||
httparse::Status::Complete(len) => {
|
httparse::Status::Complete(len) => {
|
||||||
trace!("Response.parse Complete({})", len);
|
trace!("Response.parse Complete({})", len);
|
||||||
let status = StatusCode::from_u16(res.code.unwrap())?;
|
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 {
|
let version = if res.version.unwrap() == 1 {
|
||||||
Version::HTTP_11
|
Version::HTTP_11
|
||||||
} else {
|
} else {
|
||||||
@@ -681,7 +697,7 @@ impl Http1Transaction for Client {
|
|||||||
};
|
};
|
||||||
record_header_indices(bytes, &res.headers, &mut headers_indices)?;
|
record_header_indices(bytes, &res.headers, &mut headers_indices)?;
|
||||||
let headers_len = res.headers.len();
|
let headers_len = res.headers.len();
|
||||||
(len, status, version, headers_len)
|
(len, status, reason, version, headers_len)
|
||||||
}
|
}
|
||||||
httparse::Status::Partial => return Ok(None),
|
httparse::Status::Partial => return Ok(None),
|
||||||
}
|
}
|
||||||
@@ -728,6 +744,13 @@ impl Http1Transaction for Client {
|
|||||||
extensions.insert(header_case_map);
|
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 {
|
let head = MessageHead {
|
||||||
version,
|
version,
|
||||||
subject: status,
|
subject: status,
|
||||||
|
|||||||
Reference in New Issue
Block a user