Skip to content

Commit

Permalink
feat(ffi): add option to get raw headers from response
Browse files Browse the repository at this point in the history
  • Loading branch information
seanmonstar committed Jun 15, 2021
1 parent 08b2138 commit 8c89a8c
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 2 deletions.
26 changes: 26 additions & 0 deletions capi/include/hyper.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,17 @@ void hyper_clientconn_options_exec(struct hyper_clientconn_options *opts,
*/
enum hyper_code hyper_clientconn_options_http2(struct hyper_clientconn_options *opts, int enabled);

/*
Set the whether to include a copy of the raw headers in responses
received on this connection.
Pass `0` to disable, `1` to enable.
If enabled, see `hyper_response_headers_raw()` for usage.
*/
enum hyper_code hyper_clientconn_options_headers_raw(struct hyper_clientconn_options *opts,
int enabled);

/*
Frees a `hyper_error`.
*/
Expand Down Expand Up @@ -475,6 +486,21 @@ const uint8_t *hyper_response_reason_phrase(const struct hyper_response *resp);
*/
size_t hyper_response_reason_phrase_len(const struct hyper_response *resp);

/*
Get a reference to the full raw headers of this response.
You must have enabled `hyper_clientconn_options_headers_raw()`, or this
will return NULL.
The returned `hyper_buf *` is just a reference, owned by the response.
You need to make a copy if you wish to use it after freeing the
response.
The buffer is not null-terminated, see the `hyper_buf` functions for
getting the bytes and length.
*/
const struct hyper_buf *hyper_response_headers_raw(const struct hyper_response *resp);

/*
Get the HTTP version used by this response.
Expand Down
14 changes: 14 additions & 0 deletions src/client/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ pub struct Builder {
h1_preserve_header_case: bool,
h1_read_buf_exact_size: Option<usize>,
h1_max_buf_size: Option<usize>,
#[cfg(feature = "ffi")]
h1_headers_raw: bool,
#[cfg(feature = "http2")]
h2_builder: proto::h2::client::Config,
version: Proto,
Expand Down Expand Up @@ -528,6 +530,8 @@ impl Builder {
h1_title_case_headers: false,
h1_preserve_header_case: false,
h1_max_buf_size: None,
#[cfg(feature = "ffi")]
h1_headers_raw: false,
#[cfg(feature = "http2")]
h2_builder: Default::default(),
#[cfg(feature = "http1")]
Expand Down Expand Up @@ -588,6 +592,12 @@ impl Builder {
self
}

#[cfg(feature = "ffi")]
pub(crate) fn http1_headers_raw(&mut self, enabled: bool) -> &mut Self {
self.h1_headers_raw = enabled;
self
}

/// Sets whether HTTP2 is required.
///
/// Default is false.
Expand Down Expand Up @@ -773,6 +783,10 @@ impl Builder {
if opts.h09_responses {
conn.set_h09_responses();
}

#[cfg(feature = "ffi")]
conn.set_raw_headers(opts.h1_headers_raw);

if let Some(sz) = opts.h1_read_buf_exact_size {
conn.set_read_buf_exact_size(sz);
}
Expand Down
2 changes: 1 addition & 1 deletion src/ffi/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::body::{Body, Bytes, HttpBody as _};
pub struct hyper_body(pub(super) Body);

/// A buffer of bytes that is sent or received on a `hyper_body`.
pub struct hyper_buf(pub(super) Bytes);
pub struct hyper_buf(pub(crate) Bytes);

pub(crate) struct UserBody {
data_func: hyper_body_data_callback,
Expand Down
14 changes: 14 additions & 0 deletions src/ffi/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,17 @@ ffi_fn! {
}
}
}

ffi_fn! {
/// Set the whether to include a copy of the raw headers in responses
/// received on this connection.
///
/// Pass `0` to disable, `1` to enable.
///
/// If enabled, see `hyper_response_headers_raw()` for usage.
fn hyper_clientconn_options_headers_raw(opts: *mut hyper_clientconn_options, enabled: c_int) -> hyper_code {
let opts = unsafe { &mut *opts };
opts.builder.http1_headers_raw(enabled != 0);
hyper_code::HYPERE_OK
}
}
24 changes: 23 additions & 1 deletion src/ffi/http_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bytes::Bytes;
use libc::{c_int, size_t};
use std::ffi::c_void;

use super::body::hyper_body;
use super::body::{hyper_body, hyper_buf};
use super::error::hyper_code;
use super::task::{hyper_task_return_type, AsTaskType};
use super::HYPER_ITER_CONTINUE;
Expand All @@ -27,6 +27,8 @@ pub struct hyper_headers {
#[derive(Debug)]
pub(crate) struct ReasonPhrase(pub(crate) Bytes);

pub(crate) struct RawHeaders(pub(crate) hyper_buf);

// ===== impl hyper_request =====

ffi_fn! {
Expand Down Expand Up @@ -178,6 +180,26 @@ ffi_fn! {
}
}

ffi_fn! {
/// Get a reference to the full raw headers of this response.
///
/// You must have enabled `hyper_clientconn_options_headers_raw()`, or this
/// will return NULL.
///
/// The returned `hyper_buf *` is just a reference, owned by the response.
/// You need to make a copy if you wish to use it after freeing the
/// response.
///
/// The buffer is not null-terminated, see the `hyper_buf` functions for
/// getting the bytes and length.
fn hyper_response_headers_raw(resp: *const hyper_response) -> *const hyper_buf {
match unsafe { &*resp }.0.extensions().get::<RawHeaders>() {
Some(raw) => &raw.0,
None => std::ptr::null(),
}
} ?= std::ptr::null()
}

ffi_fn! {
/// Get the HTTP version used by this response.
///
Expand Down
11 changes: 11 additions & 0 deletions src/proto/h1/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ where
preserve_header_case: false,
title_case_headers: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
notify_read: false,
reading: Reading::Init,
writing: Writing::Init,
Expand Down Expand Up @@ -98,6 +100,11 @@ where
self.state.allow_half_close = true;
}

#[cfg(feature = "ffi")]
pub(crate) fn set_raw_headers(&mut self, enabled: bool) {
self.state.raw_headers = enabled;
}

pub(crate) fn into_inner(self) -> (I, Bytes) {
self.io.into_inner()
}
Expand Down Expand Up @@ -162,6 +169,8 @@ where
h1_parser_config: self.state.h1_parser_config.clone(),
preserve_header_case: self.state.preserve_header_case,
h09_responses: self.state.h09_responses,
#[cfg(feature = "ffi")]
raw_headers: self.state.raw_headers,
}
)) {
Ok(msg) => msg,
Expand Down Expand Up @@ -766,6 +775,8 @@ struct State {
preserve_header_case: bool,
title_case_headers: bool,
h09_responses: bool,
#[cfg(feature = "ffi")]
raw_headers: bool,
/// Set to true when the Dispatcher should poll read operations
/// again. See the `maybe_notify` method for more.
notify_read: bool,
Expand Down
4 changes: 4 additions & 0 deletions src/proto/h1/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ where
h1_parser_config: parse_ctx.h1_parser_config.clone(),
preserve_header_case: parse_ctx.preserve_header_case,
h09_responses: parse_ctx.h09_responses,
#[cfg(feature = "ffi")]
raw_headers: parse_ctx.raw_headers,
},
)? {
Some(msg) => {
Expand Down Expand Up @@ -675,6 +677,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
};
assert!(buffered
.parse::<ClientTransaction>(cx, parse_ctx)
Expand Down
2 changes: 2 additions & 0 deletions src/proto/h1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ pub(crate) struct ParseContext<'a> {
h1_parser_config: ParserConfig,
preserve_header_case: bool,
h09_responses: bool,
#[cfg(feature = "ffi")]
raw_headers: bool,
}

/// Passed to Http1Transaction::encode
Expand Down
37 changes: 37 additions & 0 deletions src/proto/h1/role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,11 @@ impl Http1Transaction for Client {
#[cfg(not(feature = "ffi"))]
drop(reason);

#[cfg(feature = "ffi")]
if ctx.raw_headers {
extensions.insert(crate::ffi::RawHeaders(crate::ffi::hyper_buf(slice)));
}

let head = MessageHead {
version,
subject: status,
Expand Down Expand Up @@ -1424,6 +1429,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
},
)
.unwrap()
Expand All @@ -1447,6 +1454,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
};
let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
assert_eq!(raw.len(), 0);
Expand All @@ -1465,6 +1474,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
};
Server::parse(&mut raw, ctx).unwrap_err();
}
Expand All @@ -1481,6 +1492,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: true,
#[cfg(feature = "ffi")]
raw_headers: false,
};
let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
assert_eq!(raw, H09_RESPONSE);
Expand All @@ -1499,6 +1512,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
};
Client::parse(&mut raw, ctx).unwrap_err();
assert_eq!(raw, H09_RESPONSE);
Expand All @@ -1521,6 +1536,8 @@ mod tests {
h1_parser_config,
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
};
let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
assert_eq!(raw.len(), 0);
Expand All @@ -1540,6 +1557,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
};
Client::parse(&mut raw, ctx).unwrap_err();
}
Expand All @@ -1554,6 +1573,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: true,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
};
let parsed_message = Server::parse(&mut raw, ctx).unwrap().unwrap();
let orig_headers = parsed_message
Expand Down Expand Up @@ -1589,6 +1610,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
},
)
.expect("parse ok")
Expand All @@ -1605,6 +1628,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
},
)
.expect_err(comment)
Expand Down Expand Up @@ -1820,6 +1845,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
}
)
.expect("parse ok")
Expand All @@ -1836,6 +1863,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
},
)
.expect("parse ok")
Expand All @@ -1852,6 +1881,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
},
)
.expect_err("parse should err")
Expand Down Expand Up @@ -2335,6 +2366,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
},
)
.expect("parse ok")
Expand Down Expand Up @@ -2415,6 +2448,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
},
)
.unwrap()
Expand Down Expand Up @@ -2451,6 +2486,8 @@ mod tests {
h1_parser_config: Default::default(),
preserve_header_case: false,
h09_responses: false,
#[cfg(feature = "ffi")]
raw_headers: false,
},
)
.unwrap()
Expand Down

0 comments on commit 8c89a8c

Please sign in to comment.