Skip to content

Commit

Permalink
Implemented a few PR Suggestions:
Browse files Browse the repository at this point in the history
1. Added a few more #[cfg(feature = "ffi")]'s all around
2. Replaced a few temp descriptions
3. Removed printlns.
4. Removed a ` + std::fmt::Display,`
5. Removed unused param for OriginalHeaderOrder::append and
   OriginalHeaderOrder::insert
6. Made the new connection options more like the current boolean options
  • Loading branch information
liamwarfield committed Apr 10, 2022
1 parent a2d8e5d commit 0ff3b20
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 34 deletions.
16 changes: 11 additions & 5 deletions capi/include/hyper.h
Expand Up @@ -356,14 +356,20 @@ void hyper_clientconn_free(struct hyper_clientconn *conn);
struct hyper_clientconn_options *hyper_clientconn_options_new(void);

/*
temp
Set the whether or not header case is preserved.
Pass `0` to allow lowercase normalization (default), `1` to retain original case.
*/
void hyper_clientconn_options_set_preserve_header_case(struct hyper_clientconn_options *opts);
void hyper_clientconn_options_set_preserve_header_case(struct hyper_clientconn_options *opts,
int enabled);

/*
temp
Set the whether or not header order is preserved.
Pass `0` to allow reordering (default), `1` to retain original ordering.
*/
void hyper_clientconn_options_set_preserve_header_order(struct hyper_clientconn_options *opts);
void hyper_clientconn_options_set_preserve_header_order(struct hyper_clientconn_options *opts,
int enabled);

/*
Free a `hyper_clientconn_options *`.
Expand Down Expand Up @@ -606,7 +612,7 @@ void hyper_headers_foreach(const struct hyper_headers *headers,
void *userdata);

/*
Iterates the headers passing each name and value pair to the callback.
Iterates the headers in the order the were recieved, passing each name and value pair to the callback.
The `userdata` pointer is also passed to the callback.
Expand Down
1 change: 1 addition & 0 deletions src/client/conn.rs
Expand Up @@ -716,6 +716,7 @@ impl Builder {
/// Note that this setting does not affect HTTP/2.
///
/// Default is false.
#[cfg(feature = "ffi")]
pub fn http1_preserve_header_order(&mut self, enabled: bool) -> &mut Builder {
self.h1_preserve_header_order = enabled;
self
Expand Down
10 changes: 5 additions & 5 deletions src/ext.rs
Expand Up @@ -5,7 +5,7 @@ use http::header::HeaderName;
#[cfg(feature = "http1")]
use http::header::{IntoHeaderName, ValueIter};
use http::HeaderMap;
use std::collections::{HashSet, HashMap};
use std::collections::HashMap;
#[cfg(feature = "http2")]
use std::fmt;

Expand Down Expand Up @@ -117,7 +117,7 @@ impl HeaderCaseMap {

pub(crate) fn append<N>(&mut self, name: N, orig: Bytes)
where
N: IntoHeaderName + std::fmt::Display,
N: IntoHeaderName,
{
self.0.append(name, orig);
}
Expand All @@ -127,14 +127,14 @@ impl HeaderCaseMap {
/// Hashmap<Headername, numheaders with that name>
pub(crate) struct OriginalHeaderOrder(HashMap<HeaderName, usize>, Vec<(HeaderName, usize)>);

#[cfg(feature = "http1")]
#[cfg(all(feature = "http1", feature = "ffi"))]
impl OriginalHeaderOrder {
pub(crate) fn default() -> Self {
Self(Default::default(), Default::default())
}

#[cfg(any(test, feature = "ffi"))]
pub(crate) fn insert(&mut self, name: HeaderName, orig: Bytes) {
pub(crate) fn insert(&mut self, name: HeaderName) {
if !self.0.contains_key(&name) {
let idx = 0;
self.0.insert(name.clone(), 1);
Expand All @@ -145,7 +145,7 @@ impl OriginalHeaderOrder {
// header name encountered
}

pub(crate) fn append<N>(&mut self, name: N, orig: Bytes)
pub(crate) fn append<N>(&mut self, name: N)
where
N: IntoHeaderName + Into<HeaderName> + Clone,
{
Expand Down
16 changes: 10 additions & 6 deletions src/ffi/client.rs
Expand Up @@ -105,18 +105,22 @@ ffi_fn! {
}

ffi_fn! {
/// temp
fn hyper_clientconn_options_set_preserve_header_case(opts: *mut hyper_clientconn_options) {
/// Set the whether or not header case is preserved.
///
/// Pass `0` to allow lowercase normalization (default), `1` to retain original case.
fn hyper_clientconn_options_set_preserve_header_case(opts: *mut hyper_clientconn_options, enabled: c_int) {
let opts = non_null! { &mut *opts ?= () };
opts.builder.http1_preserve_header_case(true);
opts.builder.http1_preserve_header_case(enabled != 0);
}
}

ffi_fn! {
/// temp
fn hyper_clientconn_options_set_preserve_header_order(opts: *mut hyper_clientconn_options) {
/// Set the whether or not header order is preserved.
///
/// Pass `0` to allow reordering (default), `1` to retain original ordering.
fn hyper_clientconn_options_set_preserve_header_order(opts: *mut hyper_clientconn_options, enabled: c_int) {
let opts = non_null! { &mut *opts ?= () };
opts.builder.http1_preserve_header_order(true);
opts.builder.http1_preserve_header_order(enabled != 0);
}
}

Expand Down
99 changes: 83 additions & 16 deletions src/ffi/http_types.rs
Expand Up @@ -411,26 +411,32 @@ ffi_fn! {
// and for each one, try to pair the originally cased name with the value.
//
// TODO: consider adding http::HeaderMap::entries() iterator
for (name, idx) in headers.orig_order.get_in_order() {
//println!("OHEA {:?}", (name, idx));
let orig_name = headers.orig_casing.get_all(&name).nth(*idx).unwrap();
let value = headers.headers.get_all(name).iter().nth(*idx).unwrap();

let name_ptr = orig_name.as_ref().as_ptr();
let name_len = orig_name.as_ref().len();

let val_ptr = value.as_bytes().as_ptr();
let val_len = value.as_bytes().len();

if HYPER_ITER_CONTINUE != func(userdata, name_ptr, name_len, val_ptr, val_len) {
return;
for name in headers.headers.keys() {
let mut names = headers.orig_casing.get_all(name);

for value in headers.headers.get_all(name) {
let (name_ptr, name_len) = if let Some(orig_name) = names.next() {
(orig_name.as_ref().as_ptr(), orig_name.as_ref().len())
} else {
(
name.as_str().as_bytes().as_ptr(),
name.as_str().as_bytes().len(),
)
};

let val_ptr = value.as_bytes().as_ptr();
let val_len = value.as_bytes().len();

if HYPER_ITER_CONTINUE != func(userdata, name_ptr, name_len, val_ptr, val_len) {
return;
}
}
}
}
}

ffi_fn! {
/// Iterates the headers passing each name and value pair to the callback.
/// Iterates the headers in the order the were recieved, passing each name and value pair to the callback.
///
/// The `userdata` pointer is also passed to the callback.
///
Expand Down Expand Up @@ -470,7 +476,7 @@ ffi_fn! {
Ok((name, value, orig_name)) => {
headers.headers.insert(&name, value);
headers.orig_casing.insert(name.clone(), orig_name.clone());
headers.orig_order.insert(name, orig_name);
headers.orig_order.insert(name);
hyper_code::HYPERE_OK
}
Err(code) => code,
Expand All @@ -490,7 +496,7 @@ ffi_fn! {
Ok((name, value, orig_name)) => {
headers.headers.append(&name, value);
headers.orig_casing.append(&name, orig_name.clone());
headers.orig_order.append(name, orig_name);
headers.orig_order.append(name);
hyper_code::HYPERE_OK
}
Err(code) => code,
Expand Down Expand Up @@ -590,4 +596,65 @@ mod tests {
HYPER_ITER_CONTINUE
}
}

#[cfg(all(feature = "http1", feature = "ffi"))]
#[test]
fn test_headers_foreach_order_preserved() {
let mut headers = hyper_headers::default();

let name1 = b"Set-CookiE";
let value1 = b"a=b";
hyper_headers_add(
&mut headers,
name1.as_ptr(),
name1.len(),
value1.as_ptr(),
value1.len(),
);

let name2 = b"Content-Encoding";
let value2 = b"gzip";
hyper_headers_add(
&mut headers,
name2.as_ptr(),
name2.len(),
value2.as_ptr(),
value2.len(),
);

let name3 = b"SET-COOKIE";
let value3 = b"c=d";
hyper_headers_add(
&mut headers,
name3.as_ptr(),
name3.len(),
value3.as_ptr(),
value3.len(),
);

let mut vec = Vec::<u8>::new();
hyper_headers_foreach_ordered(&headers, concat, &mut vec as *mut _ as *mut c_void);

println!("{}", std::str::from_utf8(&vec).unwrap());
assert_eq!(vec, b"Set-CookiE: a=b\r\nContent-Encoding: gzip\r\nSET-COOKIE: c=d\r\n");

extern "C" fn concat(
vec: *mut c_void,
name: *const u8,
name_len: usize,
value: *const u8,
value_len: usize,
) -> c_int {
unsafe {
let vec = &mut *(vec as *mut Vec<u8>);
let name = std::slice::from_raw_parts(name, name_len);
let value = std::slice::from_raw_parts(value, value_len);
vec.extend(name);
vec.extend(b": ");
vec.extend(value);
vec.extend(b"\r\n");
}
HYPER_ITER_CONTINUE
}
}
}
10 changes: 8 additions & 2 deletions src/proto/h1/role.rs
@@ -1,6 +1,8 @@
use std::fmt::{self, Write};
use std::mem::MaybeUninit;

#[cfg(all(feature = "server", feature = "runtime"))]
use tokio::time::Instant;
#[cfg(any(test, feature = "server", feature = "ffi"))]
use bytes::Bytes;
use bytes::BytesMut;
Expand Down Expand Up @@ -212,6 +214,7 @@ impl Http1Transaction for Server {
None
};

#[cfg(feature = "ffi")]
let mut header_order = if ctx.preserve_header_order {
Some(OriginalHeaderOrder::default())
} else {
Expand Down Expand Up @@ -294,8 +297,9 @@ impl Http1Transaction for Server {
header_case_map.append(&name, slice.slice(header.name.0..header.name.1));
}

#[cfg(feature = "ffi")]
if let Some(ref mut header_order) = header_order {
header_order.append(&name, slice.slice(header.name.0..header.name.1));
header_order.append(&name);
}

headers.append(name, value);
Expand Down Expand Up @@ -996,6 +1000,7 @@ impl Http1Transaction for Client {
None
};

#[cfg(feature = "ffi")]
let mut header_order = if ctx.preserve_header_order {
Some(OriginalHeaderOrder::default())
} else {
Expand Down Expand Up @@ -1024,8 +1029,9 @@ impl Http1Transaction for Client {
header_case_map.append(&name, slice.slice(header.name.0..header.name.1));
}

#[cfg(feature = "ffi")]
if let Some(ref mut header_order) = header_order {
header_order.append(&name, slice.slice(header.name.0..header.name.1));
header_order.append(&name);
}

headers.append(name, value);
Expand Down

0 comments on commit 0ff3b20

Please sign in to comment.