1use std::ffi::{c_int, c_void};
2
3use bytes::Bytes;
4
5use super::body::hyper_body;
6use super::error::hyper_code;
7use super::task::{hyper_task_return_type, AsTaskType};
8use super::{UserDataPointer, HYPER_ITER_CONTINUE};
9use crate::body::Incoming as IncomingBody;
10use crate::ext::{HeaderCaseMap, OriginalHeaderOrder, ReasonPhrase};
11use crate::ffi::size_t;
12use crate::header::{HeaderName, HeaderValue};
13use crate::{HeaderMap, Method, Request, Response, Uri};
14
15pub struct hyper_request(pub(super) Request<IncomingBody>);
32
33pub struct hyper_response(pub(super) Response<IncomingBody>);
52
53#[derive(Clone)]
66pub struct hyper_headers {
67 pub(super) headers: HeaderMap,
68 orig_casing: HeaderCaseMap,
69 orig_order: OriginalHeaderOrder,
70}
71
72#[derive(Clone)]
73struct OnInformational {
74 func: hyper_request_on_informational_callback,
75 data: UserDataPointer,
76}
77
78type hyper_request_on_informational_callback = extern "C" fn(*mut c_void, *mut hyper_response);
79
80ffi_fn! {
83 fn hyper_request_new() -> *mut hyper_request {
91 Box::into_raw(Box::new(hyper_request(Request::new(IncomingBody::empty()))))
92 } ?= std::ptr::null_mut()
93}
94
95ffi_fn! {
96 fn hyper_request_free(req: *mut hyper_request) {
101 drop(non_null!(Box::from_raw(req) ?= ()));
102 }
103}
104
105ffi_fn! {
106 fn hyper_request_set_method(req: *mut hyper_request, method: *const u8, method_len: size_t) -> hyper_code {
108 let bytes = unsafe {
109 std::slice::from_raw_parts(method, method_len as usize)
110 };
111 let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
112 match Method::from_bytes(bytes) {
113 Ok(m) => {
114 *req.0.method_mut() = m;
115 hyper_code::HYPERE_OK
116 },
117 Err(_) => {
118 hyper_code::HYPERE_INVALID_ARG
119 }
120 }
121 }
122}
123
124ffi_fn! {
125 fn hyper_request_set_uri(req: *mut hyper_request, uri: *const u8, uri_len: size_t) -> hyper_code {
140 let bytes = unsafe {
141 std::slice::from_raw_parts(uri, uri_len as usize)
142 };
143 let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
144 match Uri::from_maybe_shared(bytes) {
145 Ok(u) => {
146 *req.0.uri_mut() = u;
147 hyper_code::HYPERE_OK
148 },
149 Err(_) => {
150 hyper_code::HYPERE_INVALID_ARG
151 }
152 }
153 }
154}
155
156ffi_fn! {
157 fn hyper_request_set_uri_parts(
165 req: *mut hyper_request,
166 scheme: *const u8,
167 scheme_len: size_t,
168 authority: *const u8,
169 authority_len: size_t,
170 path_and_query: *const u8,
171 path_and_query_len: size_t
172 ) -> hyper_code {
173 let mut builder = Uri::builder();
174 if !scheme.is_null() {
175 let scheme_bytes = unsafe {
176 std::slice::from_raw_parts(scheme, scheme_len as usize)
177 };
178 builder = builder.scheme(scheme_bytes);
179 }
180 if !authority.is_null() {
181 let authority_bytes = unsafe {
182 std::slice::from_raw_parts(authority, authority_len as usize)
183 };
184 builder = builder.authority(authority_bytes);
185 }
186 if !path_and_query.is_null() {
187 let path_and_query_bytes = unsafe {
188 std::slice::from_raw_parts(path_and_query, path_and_query_len as usize)
189 };
190 builder = builder.path_and_query(path_and_query_bytes);
191 }
192 let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
193 match builder.build() {
194 Ok(u) => {
195 *req.0.uri_mut() = u;
196 hyper_code::HYPERE_OK
197 },
198 Err(_) => {
199 hyper_code::HYPERE_INVALID_ARG
200 }
201 }
202 }
203}
204
205ffi_fn! {
206 fn hyper_request_set_version(req: *mut hyper_request, version: c_int) -> hyper_code {
213 use http::Version;
214
215 let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
216 *req.0.version_mut() = match version {
217 super::HYPER_HTTP_VERSION_NONE => Version::HTTP_11,
218 super::HYPER_HTTP_VERSION_1_0 => Version::HTTP_10,
219 super::HYPER_HTTP_VERSION_1_1 => Version::HTTP_11,
220 super::HYPER_HTTP_VERSION_2 => Version::HTTP_2,
221 _ => {
222 return hyper_code::HYPERE_INVALID_ARG;
224 }
225 };
226 hyper_code::HYPERE_OK
227 }
228}
229
230ffi_fn! {
231 fn hyper_request_headers(req: *mut hyper_request) -> *mut hyper_headers {
236 let req = non_null!(&mut *req ?= std::ptr::null_mut());
237 hyper_headers::get_or_default(req.0.extensions_mut())
238 } ?= std::ptr::null_mut()
239}
240
241ffi_fn! {
242 fn hyper_request_set_body(req: *mut hyper_request, body: *mut hyper_body) -> hyper_code {
249 let body = non_null!(Box::from_raw(body) ?= hyper_code::HYPERE_INVALID_ARG);
250 let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
251 *req.0.body_mut() = body.0;
252 hyper_code::HYPERE_OK
253 }
254}
255
256ffi_fn! {
257 fn hyper_request_on_informational(req: *mut hyper_request, callback: hyper_request_on_informational_callback, data: *mut c_void) -> hyper_code {
273 #[cfg(feature = "client")]
274 {
275 let ext = OnInformational {
276 func: callback,
277 data: UserDataPointer(data),
278 };
279 let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
280 crate::ext::on_informational_raw(&mut req.0, ext);
281 hyper_code::HYPERE_OK
282 }
283 #[cfg(not(feature = "client"))]
284 {
285 drop((req, callback, data));
286 hyper_code::HYPERE_FEATURE_NOT_ENABLED
287 }
288 }
289}
290
291impl hyper_request {
292 pub(super) fn finalize_request(&mut self) {
293 if let Some(headers) = self.0.extensions_mut().remove::<hyper_headers>() {
294 *self.0.headers_mut() = headers.headers;
295 self.0.extensions_mut().insert(headers.orig_casing);
296 self.0.extensions_mut().insert(headers.orig_order);
297 }
298 }
299}
300
301ffi_fn! {
304 fn hyper_response_free(resp: *mut hyper_response) {
308 drop(non_null!(Box::from_raw(resp) ?= ()));
309 }
310}
311
312ffi_fn! {
313 fn hyper_response_status(resp: *const hyper_response) -> u16 {
317 non_null!(&*resp ?= 0).0.status().as_u16()
318 }
319}
320
321ffi_fn! {
322 fn hyper_response_reason_phrase(resp: *const hyper_response) -> *const u8 {
332 non_null!(&*resp ?= std::ptr::null()).reason_phrase().as_ptr()
333 } ?= std::ptr::null()
334}
335
336ffi_fn! {
337 fn hyper_response_reason_phrase_len(resp: *const hyper_response) -> size_t {
341 non_null!(&*resp ?= 0).reason_phrase().len()
342 }
343}
344
345ffi_fn! {
346 fn hyper_response_version(resp: *const hyper_response) -> c_int {
355 use http::Version;
356
357 match non_null!(&*resp ?= 0).0.version() {
358 Version::HTTP_10 => super::HYPER_HTTP_VERSION_1_0,
359 Version::HTTP_11 => super::HYPER_HTTP_VERSION_1_1,
360 Version::HTTP_2 => super::HYPER_HTTP_VERSION_2,
361 _ => super::HYPER_HTTP_VERSION_NONE,
362 }
363 }
364}
365
366ffi_fn! {
367 fn hyper_response_headers(resp: *mut hyper_response) -> *mut hyper_headers {
372 let resp = non_null!(&mut *resp ?= std::ptr::null_mut());
373 hyper_headers::get_or_default(resp.0.extensions_mut())
374 } ?= std::ptr::null_mut()
375}
376
377ffi_fn! {
378 fn hyper_response_body(resp: *mut hyper_response) -> *mut hyper_body {
385 let body = std::mem::replace(non_null!(&mut *resp ?= std::ptr::null_mut()).0.body_mut(), IncomingBody::empty());
386 Box::into_raw(Box::new(hyper_body(body)))
387 } ?= std::ptr::null_mut()
388}
389
390impl hyper_response {
391 pub(super) fn wrap(mut resp: Response<IncomingBody>) -> hyper_response {
392 let headers = std::mem::take(resp.headers_mut());
393 let orig_casing = resp
394 .extensions_mut()
395 .remove::<HeaderCaseMap>()
396 .unwrap_or_else(HeaderCaseMap::default);
397 let orig_order = resp
398 .extensions_mut()
399 .remove::<OriginalHeaderOrder>()
400 .unwrap_or_else(OriginalHeaderOrder::default);
401 resp.extensions_mut().insert(hyper_headers {
402 headers,
403 orig_casing,
404 orig_order,
405 });
406
407 hyper_response(resp)
408 }
409
410 fn reason_phrase(&self) -> &[u8] {
411 if let Some(reason) = self.0.extensions().get::<ReasonPhrase>() {
412 return reason.as_bytes();
413 }
414
415 if let Some(reason) = self.0.status().canonical_reason() {
416 return reason.as_bytes();
417 }
418
419 &[]
420 }
421}
422
423unsafe impl AsTaskType for hyper_response {
424 fn as_task_type(&self) -> hyper_task_return_type {
425 hyper_task_return_type::HYPER_TASK_RESPONSE
426 }
427}
428
429type hyper_headers_foreach_callback =
432 extern "C" fn(*mut c_void, *const u8, size_t, *const u8, size_t) -> c_int;
433
434impl hyper_headers {
435 pub(super) fn get_or_default(ext: &mut http::Extensions) -> &mut hyper_headers {
436 if let None = ext.get_mut::<hyper_headers>() {
437 ext.insert(hyper_headers::default());
438 }
439
440 ext.get_mut::<hyper_headers>().unwrap()
441 }
442}
443
444ffi_fn! {
445 fn hyper_headers_foreach(headers: *const hyper_headers, func: hyper_headers_foreach_callback, userdata: *mut c_void) {
452 let headers = non_null!(&*headers ?= ());
453 let mut ordered_iter = headers.orig_order.get_in_order().peekable();
459 if ordered_iter.peek().is_some() {
460 for (name, idx) in ordered_iter {
461 let (name_ptr, name_len) = if let Some(orig_name) = headers.orig_casing.get_all(name).nth(*idx) {
462 (orig_name.as_ref().as_ptr(), orig_name.as_ref().len())
463 } else {
464 (
465 name.as_str().as_bytes().as_ptr(),
466 name.as_str().as_bytes().len(),
467 )
468 };
469
470 let val_ptr;
471 let val_len;
472 if let Some(value) = headers.headers.get_all(name).iter().nth(*idx) {
473 val_ptr = value.as_bytes().as_ptr();
474 val_len = value.as_bytes().len();
475 } else {
476 return;
478 }
479
480 if HYPER_ITER_CONTINUE != func(userdata, name_ptr, name_len, val_ptr, val_len) {
481 return;
482 }
483 }
484 } else {
485 for name in headers.headers.keys() {
486 let mut names = headers.orig_casing.get_all(name);
487
488 for value in headers.headers.get_all(name) {
489 let (name_ptr, name_len) = if let Some(orig_name) = names.next() {
490 (orig_name.as_ref().as_ptr(), orig_name.as_ref().len())
491 } else {
492 (
493 name.as_str().as_bytes().as_ptr(),
494 name.as_str().as_bytes().len(),
495 )
496 };
497
498 let val_ptr = value.as_bytes().as_ptr();
499 let val_len = value.as_bytes().len();
500
501 if HYPER_ITER_CONTINUE != func(userdata, name_ptr, name_len, val_ptr, val_len) {
502 return;
503 }
504 }
505 }
506 }
507 }
508}
509
510ffi_fn! {
511 fn hyper_headers_set(headers: *mut hyper_headers, name: *const u8, name_len: size_t, value: *const u8, value_len: size_t) -> hyper_code {
515 let headers = non_null!(&mut *headers ?= hyper_code::HYPERE_INVALID_ARG);
516 match unsafe { raw_name_value(name, name_len, value, value_len) } {
517 Ok((name, value, orig_name)) => {
518 headers.headers.insert(&name, value);
519 headers.orig_casing.insert(name.clone(), orig_name.clone());
520 headers.orig_order.insert(name);
521 hyper_code::HYPERE_OK
522 }
523 Err(code) => code,
524 }
525 }
526}
527
528ffi_fn! {
529 fn hyper_headers_add(headers: *mut hyper_headers, name: *const u8, name_len: size_t, value: *const u8, value_len: size_t) -> hyper_code {
534 let headers = non_null!(&mut *headers ?= hyper_code::HYPERE_INVALID_ARG);
535
536 match unsafe { raw_name_value(name, name_len, value, value_len) } {
537 Ok((name, value, orig_name)) => {
538 headers.headers.append(&name, value);
539 headers.orig_casing.append(&name, orig_name.clone());
540 headers.orig_order.append(name);
541 hyper_code::HYPERE_OK
542 }
543 Err(code) => code,
544 }
545 }
546}
547
548impl Default for hyper_headers {
549 fn default() -> Self {
550 Self {
551 headers: Default::default(),
552 orig_casing: HeaderCaseMap::default(),
553 orig_order: OriginalHeaderOrder::default(),
554 }
555 }
556}
557
558unsafe fn raw_name_value(
559 name: *const u8,
560 name_len: size_t,
561 value: *const u8,
562 value_len: size_t,
563) -> Result<(HeaderName, HeaderValue, Bytes), hyper_code> {
564 let name = std::slice::from_raw_parts(name, name_len);
565 let orig_name = Bytes::copy_from_slice(name);
566 let name = match HeaderName::from_bytes(name) {
567 Ok(name) => name,
568 Err(_) => return Err(hyper_code::HYPERE_INVALID_ARG),
569 };
570 let value = std::slice::from_raw_parts(value, value_len);
571 let value = match HeaderValue::from_bytes(value) {
572 Ok(val) => val,
573 Err(_) => return Err(hyper_code::HYPERE_INVALID_ARG),
574 };
575
576 Ok((name, value, orig_name))
577}
578
579#[cfg(feature = "client")]
582impl crate::ext::OnInformationalCallback for OnInformational {
583 fn on_informational(&self, res: http::Response<()>) {
584 let res = res.map(|()| IncomingBody::empty());
585 let mut res = hyper_response::wrap(res);
586 (self.func)(self.data.0, &mut res);
587 }
588}
589
590#[cfg(test)]
591mod tests {
592 use super::*;
593
594 #[test]
595 fn test_headers_foreach_cases_preserved() {
596 let mut headers = hyper_headers::default();
597
598 let name1 = b"Set-CookiE";
599 let value1 = b"a=b";
600 hyper_headers_add(
601 &mut headers,
602 name1.as_ptr(),
603 name1.len(),
604 value1.as_ptr(),
605 value1.len(),
606 );
607
608 let name2 = b"SET-COOKIE";
609 let value2 = b"c=d";
610 hyper_headers_add(
611 &mut headers,
612 name2.as_ptr(),
613 name2.len(),
614 value2.as_ptr(),
615 value2.len(),
616 );
617
618 let mut vec = Vec::<u8>::new();
619 hyper_headers_foreach(&headers, concat, &mut vec as *mut _ as *mut c_void);
620
621 assert_eq!(vec, b"Set-CookiE: a=b\r\nSET-COOKIE: c=d\r\n");
622
623 extern "C" fn concat(
624 vec: *mut c_void,
625 name: *const u8,
626 name_len: usize,
627 value: *const u8,
628 value_len: usize,
629 ) -> c_int {
630 unsafe {
631 let vec = &mut *(vec as *mut Vec<u8>);
632 let name = std::slice::from_raw_parts(name, name_len);
633 let value = std::slice::from_raw_parts(value, value_len);
634 vec.extend(name);
635 vec.extend(b": ");
636 vec.extend(value);
637 vec.extend(b"\r\n");
638 }
639 HYPER_ITER_CONTINUE
640 }
641 }
642
643 #[cfg(all(feature = "http1", feature = "ffi"))]
644 #[test]
645 fn test_headers_foreach_order_preserved() {
646 let mut headers = hyper_headers::default();
647
648 let name1 = b"Set-CookiE";
649 let value1 = b"a=b";
650 hyper_headers_add(
651 &mut headers,
652 name1.as_ptr(),
653 name1.len(),
654 value1.as_ptr(),
655 value1.len(),
656 );
657
658 let name2 = b"Content-Encoding";
659 let value2 = b"gzip";
660 hyper_headers_add(
661 &mut headers,
662 name2.as_ptr(),
663 name2.len(),
664 value2.as_ptr(),
665 value2.len(),
666 );
667
668 let name3 = b"SET-COOKIE";
669 let value3 = b"c=d";
670 hyper_headers_add(
671 &mut headers,
672 name3.as_ptr(),
673 name3.len(),
674 value3.as_ptr(),
675 value3.len(),
676 );
677
678 let mut vec = Vec::<u8>::new();
679 hyper_headers_foreach(&headers, concat, &mut vec as *mut _ as *mut c_void);
680
681 println!("{}", std::str::from_utf8(&vec).unwrap());
682 assert_eq!(
683 vec,
684 b"Set-CookiE: a=b\r\nContent-Encoding: gzip\r\nSET-COOKIE: c=d\r\n"
685 );
686
687 extern "C" fn concat(
688 vec: *mut c_void,
689 name: *const u8,
690 name_len: usize,
691 value: *const u8,
692 value_len: usize,
693 ) -> c_int {
694 unsafe {
695 let vec = &mut *(vec as *mut Vec<u8>);
696 let name = std::slice::from_raw_parts(name, name_len);
697 let value = std::slice::from_raw_parts(value, value_len);
698 vec.extend(name);
699 vec.extend(b": ");
700 vec.extend(value);
701 vec.extend(b"\r\n");
702 }
703 HYPER_ITER_CONTINUE
704 }
705 }
706}