feature(ffi): add connection option to preserve header order (#2798)

Libcurl expects that headers are iterated in the same order that they
are recieved. Previously this caused curl tests 580 and 581 to fail.
This necessitated exposing a way to preserve the original ordering of
http headers.

SUMMARY OF CHANGES: Add a new data structure called OriginalHeaderOrder that
represents the order in which headers originally appear in a HTTP
message. This datastructure is `Vec<(Headername, multimap-index)>`.
This vector is ordered by the order which headers were recieved.
Add the following ffi functions:
- ffi::client::hyper_clientconn_options_set_preserve_header_order : An
     ffi interface to configure a connection to preserve header order.
- ffi::client::hyper_clientconn_options_set_preserve_header_case : An
     ffi interface to configure a connection to preserve header case.
- Add a new option to ParseContext, and Conn::State called `preserve_header_order`.
  This option, and all the code paths it creates are behind the `ffi`
  feature flag. This should not change performance of response parsing for
  non-ffi users.

Closes #2780

BREAKING CHANGE: hyper_clientconn_options_new no longer
  sets the http1_preserve_header_case connection option by default.
  Users should now call
  hyper_clientconn_options_set_preserve_header_case
  if they desire that functionality.
This commit is contained in:
Liam Warfield
2022-04-23 10:05:37 -06:00
committed by GitHub
parent e1138d716d
commit 78de8914ea
9 changed files with 381 additions and 30 deletions

View File

@@ -93,8 +93,7 @@ unsafe impl AsTaskType for hyper_clientconn {
ffi_fn! {
/// Creates a new set of HTTP clientconn options to be used in a handshake.
fn hyper_clientconn_options_new() -> *mut hyper_clientconn_options {
let mut builder = conn::Builder::new();
builder.http1_preserve_header_case(true);
let builder = conn::Builder::new();
Box::into_raw(Box::new(hyper_clientconn_options {
builder,
@@ -103,6 +102,26 @@ ffi_fn! {
} ?= std::ptr::null_mut()
}
ffi_fn! {
/// 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(enabled != 0);
}
}
ffi_fn! {
/// 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(enabled != 0);
}
}
ffi_fn! {
/// Free a `hyper_clientconn_options *`.
fn hyper_clientconn_options_free(opts: *mut hyper_clientconn_options) {