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