Skip to content

Commit 8c89a8c

Browse files
committedJun 15, 2021
feat(ffi): add option to get raw headers from response
1 parent 08b2138 commit 8c89a8c

File tree

9 files changed

+132
-2
lines changed

9 files changed

+132
-2
lines changed
 

‎capi/include/hyper.h

+26
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,17 @@ void hyper_clientconn_options_exec(struct hyper_clientconn_options *opts,
371371
*/
372372
enum hyper_code hyper_clientconn_options_http2(struct hyper_clientconn_options *opts, int enabled);
373373

374+
/*
375+
Set the whether to include a copy of the raw headers in responses
376+
received on this connection.
377+
378+
Pass `0` to disable, `1` to enable.
379+
380+
If enabled, see `hyper_response_headers_raw()` for usage.
381+
*/
382+
enum hyper_code hyper_clientconn_options_headers_raw(struct hyper_clientconn_options *opts,
383+
int enabled);
384+
374385
/*
375386
Frees a `hyper_error`.
376387
*/
@@ -475,6 +486,21 @@ const uint8_t *hyper_response_reason_phrase(const struct hyper_response *resp);
475486
*/
476487
size_t hyper_response_reason_phrase_len(const struct hyper_response *resp);
477488

489+
/*
490+
Get a reference to the full raw headers of this response.
491+
492+
You must have enabled `hyper_clientconn_options_headers_raw()`, or this
493+
will return NULL.
494+
495+
The returned `hyper_buf *` is just a reference, owned by the response.
496+
You need to make a copy if you wish to use it after freeing the
497+
response.
498+
499+
The buffer is not null-terminated, see the `hyper_buf` functions for
500+
getting the bytes and length.
501+
*/
502+
const struct hyper_buf *hyper_response_headers_raw(const struct hyper_response *resp);
503+
478504
/*
479505
Get the HTTP version used by this response.
480506

‎src/client/conn.rs

+14
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ pub struct Builder {
147147
h1_preserve_header_case: bool,
148148
h1_read_buf_exact_size: Option<usize>,
149149
h1_max_buf_size: Option<usize>,
150+
#[cfg(feature = "ffi")]
151+
h1_headers_raw: bool,
150152
#[cfg(feature = "http2")]
151153
h2_builder: proto::h2::client::Config,
152154
version: Proto,
@@ -528,6 +530,8 @@ impl Builder {
528530
h1_title_case_headers: false,
529531
h1_preserve_header_case: false,
530532
h1_max_buf_size: None,
533+
#[cfg(feature = "ffi")]
534+
h1_headers_raw: false,
531535
#[cfg(feature = "http2")]
532536
h2_builder: Default::default(),
533537
#[cfg(feature = "http1")]
@@ -588,6 +592,12 @@ impl Builder {
588592
self
589593
}
590594

595+
#[cfg(feature = "ffi")]
596+
pub(crate) fn http1_headers_raw(&mut self, enabled: bool) -> &mut Self {
597+
self.h1_headers_raw = enabled;
598+
self
599+
}
600+
591601
/// Sets whether HTTP2 is required.
592602
///
593603
/// Default is false.
@@ -773,6 +783,10 @@ impl Builder {
773783
if opts.h09_responses {
774784
conn.set_h09_responses();
775785
}
786+
787+
#[cfg(feature = "ffi")]
788+
conn.set_raw_headers(opts.h1_headers_raw);
789+
776790
if let Some(sz) = opts.h1_read_buf_exact_size {
777791
conn.set_read_buf_exact_size(sz);
778792
}

‎src/ffi/body.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::body::{Body, Bytes, HttpBody as _};
1414
pub struct hyper_body(pub(super) Body);
1515

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

1919
pub(crate) struct UserBody {
2020
data_func: hyper_body_data_callback,

‎src/ffi/client.rs

+14
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,17 @@ ffi_fn! {
159159
}
160160
}
161161
}
162+
163+
ffi_fn! {
164+
/// Set the whether to include a copy of the raw headers in responses
165+
/// received on this connection.
166+
///
167+
/// Pass `0` to disable, `1` to enable.
168+
///
169+
/// If enabled, see `hyper_response_headers_raw()` for usage.
170+
fn hyper_clientconn_options_headers_raw(opts: *mut hyper_clientconn_options, enabled: c_int) -> hyper_code {
171+
let opts = unsafe { &mut *opts };
172+
opts.builder.http1_headers_raw(enabled != 0);
173+
hyper_code::HYPERE_OK
174+
}
175+
}

‎src/ffi/http_types.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use bytes::Bytes;
22
use libc::{c_int, size_t};
33
use std::ffi::c_void;
44

5-
use super::body::hyper_body;
5+
use super::body::{hyper_body, hyper_buf};
66
use super::error::hyper_code;
77
use super::task::{hyper_task_return_type, AsTaskType};
88
use super::HYPER_ITER_CONTINUE;
@@ -27,6 +27,8 @@ pub struct hyper_headers {
2727
#[derive(Debug)]
2828
pub(crate) struct ReasonPhrase(pub(crate) Bytes);
2929

30+
pub(crate) struct RawHeaders(pub(crate) hyper_buf);
31+
3032
// ===== impl hyper_request =====
3133

3234
ffi_fn! {
@@ -178,6 +180,26 @@ ffi_fn! {
178180
}
179181
}
180182

183+
ffi_fn! {
184+
/// Get a reference to the full raw headers of this response.
185+
///
186+
/// You must have enabled `hyper_clientconn_options_headers_raw()`, or this
187+
/// will return NULL.
188+
///
189+
/// The returned `hyper_buf *` is just a reference, owned by the response.
190+
/// You need to make a copy if you wish to use it after freeing the
191+
/// response.
192+
///
193+
/// The buffer is not null-terminated, see the `hyper_buf` functions for
194+
/// getting the bytes and length.
195+
fn hyper_response_headers_raw(resp: *const hyper_response) -> *const hyper_buf {
196+
match unsafe { &*resp }.0.extensions().get::<RawHeaders>() {
197+
Some(raw) => &raw.0,
198+
None => std::ptr::null(),
199+
}
200+
} ?= std::ptr::null()
201+
}
202+
181203
ffi_fn! {
182204
/// Get the HTTP version used by this response.
183205
///

‎src/proto/h1/conn.rs

+11
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ where
4949
preserve_header_case: false,
5050
title_case_headers: false,
5151
h09_responses: false,
52+
#[cfg(feature = "ffi")]
53+
raw_headers: false,
5254
notify_read: false,
5355
reading: Reading::Init,
5456
writing: Writing::Init,
@@ -98,6 +100,11 @@ where
98100
self.state.allow_half_close = true;
99101
}
100102

103+
#[cfg(feature = "ffi")]
104+
pub(crate) fn set_raw_headers(&mut self, enabled: bool) {
105+
self.state.raw_headers = enabled;
106+
}
107+
101108
pub(crate) fn into_inner(self) -> (I, Bytes) {
102109
self.io.into_inner()
103110
}
@@ -162,6 +169,8 @@ where
162169
h1_parser_config: self.state.h1_parser_config.clone(),
163170
preserve_header_case: self.state.preserve_header_case,
164171
h09_responses: self.state.h09_responses,
172+
#[cfg(feature = "ffi")]
173+
raw_headers: self.state.raw_headers,
165174
}
166175
)) {
167176
Ok(msg) => msg,
@@ -766,6 +775,8 @@ struct State {
766775
preserve_header_case: bool,
767776
title_case_headers: bool,
768777
h09_responses: bool,
778+
#[cfg(feature = "ffi")]
779+
raw_headers: bool,
769780
/// Set to true when the Dispatcher should poll read operations
770781
/// again. See the `maybe_notify` method for more.
771782
notify_read: bool,

‎src/proto/h1/io.rs

+4
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ where
167167
h1_parser_config: parse_ctx.h1_parser_config.clone(),
168168
preserve_header_case: parse_ctx.preserve_header_case,
169169
h09_responses: parse_ctx.h09_responses,
170+
#[cfg(feature = "ffi")]
171+
raw_headers: parse_ctx.raw_headers,
170172
},
171173
)? {
172174
Some(msg) => {
@@ -675,6 +677,8 @@ mod tests {
675677
h1_parser_config: Default::default(),
676678
preserve_header_case: false,
677679
h09_responses: false,
680+
#[cfg(feature = "ffi")]
681+
raw_headers: false,
678682
};
679683
assert!(buffered
680684
.parse::<ClientTransaction>(cx, parse_ctx)

‎src/proto/h1/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ pub(crate) struct ParseContext<'a> {
7474
h1_parser_config: ParserConfig,
7575
preserve_header_case: bool,
7676
h09_responses: bool,
77+
#[cfg(feature = "ffi")]
78+
raw_headers: bool,
7779
}
7880

7981
/// Passed to Http1Transaction::encode

‎src/proto/h1/role.rs

+37
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,11 @@ impl Http1Transaction for Client {
970970
#[cfg(not(feature = "ffi"))]
971971
drop(reason);
972972

973+
#[cfg(feature = "ffi")]
974+
if ctx.raw_headers {
975+
extensions.insert(crate::ffi::RawHeaders(crate::ffi::hyper_buf(slice)));
976+
}
977+
973978
let head = MessageHead {
974979
version,
975980
subject: status,
@@ -1424,6 +1429,8 @@ mod tests {
14241429
h1_parser_config: Default::default(),
14251430
preserve_header_case: false,
14261431
h09_responses: false,
1432+
#[cfg(feature = "ffi")]
1433+
raw_headers: false,
14271434
},
14281435
)
14291436
.unwrap()
@@ -1447,6 +1454,8 @@ mod tests {
14471454
h1_parser_config: Default::default(),
14481455
preserve_header_case: false,
14491456
h09_responses: false,
1457+
#[cfg(feature = "ffi")]
1458+
raw_headers: false,
14501459
};
14511460
let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
14521461
assert_eq!(raw.len(), 0);
@@ -1465,6 +1474,8 @@ mod tests {
14651474
h1_parser_config: Default::default(),
14661475
preserve_header_case: false,
14671476
h09_responses: false,
1477+
#[cfg(feature = "ffi")]
1478+
raw_headers: false,
14681479
};
14691480
Server::parse(&mut raw, ctx).unwrap_err();
14701481
}
@@ -1481,6 +1492,8 @@ mod tests {
14811492
h1_parser_config: Default::default(),
14821493
preserve_header_case: false,
14831494
h09_responses: true,
1495+
#[cfg(feature = "ffi")]
1496+
raw_headers: false,
14841497
};
14851498
let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
14861499
assert_eq!(raw, H09_RESPONSE);
@@ -1499,6 +1512,8 @@ mod tests {
14991512
h1_parser_config: Default::default(),
15001513
preserve_header_case: false,
15011514
h09_responses: false,
1515+
#[cfg(feature = "ffi")]
1516+
raw_headers: false,
15021517
};
15031518
Client::parse(&mut raw, ctx).unwrap_err();
15041519
assert_eq!(raw, H09_RESPONSE);
@@ -1521,6 +1536,8 @@ mod tests {
15211536
h1_parser_config,
15221537
preserve_header_case: false,
15231538
h09_responses: false,
1539+
#[cfg(feature = "ffi")]
1540+
raw_headers: false,
15241541
};
15251542
let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
15261543
assert_eq!(raw.len(), 0);
@@ -1540,6 +1557,8 @@ mod tests {
15401557
h1_parser_config: Default::default(),
15411558
preserve_header_case: false,
15421559
h09_responses: false,
1560+
#[cfg(feature = "ffi")]
1561+
raw_headers: false,
15431562
};
15441563
Client::parse(&mut raw, ctx).unwrap_err();
15451564
}
@@ -1554,6 +1573,8 @@ mod tests {
15541573
h1_parser_config: Default::default(),
15551574
preserve_header_case: true,
15561575
h09_responses: false,
1576+
#[cfg(feature = "ffi")]
1577+
raw_headers: false,
15571578
};
15581579
let parsed_message = Server::parse(&mut raw, ctx).unwrap().unwrap();
15591580
let orig_headers = parsed_message
@@ -1589,6 +1610,8 @@ mod tests {
15891610
h1_parser_config: Default::default(),
15901611
preserve_header_case: false,
15911612
h09_responses: false,
1613+
#[cfg(feature = "ffi")]
1614+
raw_headers: false,
15921615
},
15931616
)
15941617
.expect("parse ok")
@@ -1605,6 +1628,8 @@ mod tests {
16051628
h1_parser_config: Default::default(),
16061629
preserve_header_case: false,
16071630
h09_responses: false,
1631+
#[cfg(feature = "ffi")]
1632+
raw_headers: false,
16081633
},
16091634
)
16101635
.expect_err(comment)
@@ -1820,6 +1845,8 @@ mod tests {
18201845
h1_parser_config: Default::default(),
18211846
preserve_header_case: false,
18221847
h09_responses: false,
1848+
#[cfg(feature = "ffi")]
1849+
raw_headers: false,
18231850
}
18241851
)
18251852
.expect("parse ok")
@@ -1836,6 +1863,8 @@ mod tests {
18361863
h1_parser_config: Default::default(),
18371864
preserve_header_case: false,
18381865
h09_responses: false,
1866+
#[cfg(feature = "ffi")]
1867+
raw_headers: false,
18391868
},
18401869
)
18411870
.expect("parse ok")
@@ -1852,6 +1881,8 @@ mod tests {
18521881
h1_parser_config: Default::default(),
18531882
preserve_header_case: false,
18541883
h09_responses: false,
1884+
#[cfg(feature = "ffi")]
1885+
raw_headers: false,
18551886
},
18561887
)
18571888
.expect_err("parse should err")
@@ -2335,6 +2366,8 @@ mod tests {
23352366
h1_parser_config: Default::default(),
23362367
preserve_header_case: false,
23372368
h09_responses: false,
2369+
#[cfg(feature = "ffi")]
2370+
raw_headers: false,
23382371
},
23392372
)
23402373
.expect("parse ok")
@@ -2415,6 +2448,8 @@ mod tests {
24152448
h1_parser_config: Default::default(),
24162449
preserve_header_case: false,
24172450
h09_responses: false,
2451+
#[cfg(feature = "ffi")]
2452+
raw_headers: false,
24182453
},
24192454
)
24202455
.unwrap()
@@ -2451,6 +2486,8 @@ mod tests {
24512486
h1_parser_config: Default::default(),
24522487
preserve_header_case: false,
24532488
h09_responses: false,
2489+
#[cfg(feature = "ffi")]
2490+
raw_headers: false,
24542491
},
24552492
)
24562493
.unwrap()

0 commit comments

Comments
 (0)
Please sign in to comment.