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)]
73pub(crate) struct 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 match builder.build() {
193 Ok(u) => {
194 *unsafe { &mut *req }.0.uri_mut() = u;
195 hyper_code::HYPERE_OK
196 },
197 Err(_) => {
198 hyper_code::HYPERE_INVALID_ARG
199 }
200 }
201 }
202}
203
204ffi_fn! {
205 fn hyper_request_set_version(req: *mut hyper_request, version: c_int) -> hyper_code {
212 use http::Version;
213
214 let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
215 *req.0.version_mut() = match version {
216 super::HYPER_HTTP_VERSION_NONE => Version::HTTP_11,
217 super::HYPER_HTTP_VERSION_1_0 => Version::HTTP_10,
218 super::HYPER_HTTP_VERSION_1_1 => Version::HTTP_11,
219 super::HYPER_HTTP_VERSION_2 => Version::HTTP_2,
220 _ => {
221 return hyper_code::HYPERE_INVALID_ARG;
223 }
224 };
225 hyper_code::HYPERE_OK
226 }
227}
228
229ffi_fn! {
230 fn hyper_request_headers(req: *mut hyper_request) -> *mut hyper_headers {
235 hyper_headers::get_or_default(unsafe { &mut *req }.0.extensions_mut())
236 } ?= std::ptr::null_mut()
237}
238
239ffi_fn! {
240 fn hyper_request_set_body(req: *mut hyper_request, body: *mut hyper_body) -> hyper_code {
247 let body = non_null!(Box::from_raw(body) ?= hyper_code::HYPERE_INVALID_ARG);
248 let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
249 *req.0.body_mut() = body.0;
250 hyper_code::HYPERE_OK
251 }
252}
253
254ffi_fn! {
255 fn hyper_request_on_informational(req: *mut hyper_request, callback: hyper_request_on_informational_callback, data: *mut c_void) -> hyper_code {
271 let ext = OnInformational {
272 func: callback,
273 data: UserDataPointer(data),
274 };
275 let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
276 req.0.extensions_mut().insert(ext);
277 hyper_code::HYPERE_OK
278 }
279}
280
281impl hyper_request {
282 pub(super) fn finalize_request(&mut self) {
283 if let Some(headers) = self.0.extensions_mut().remove::<hyper_headers>() {
284 *self.0.headers_mut() = headers.headers;
285 self.0.extensions_mut().insert(headers.orig_casing);
286 self.0.extensions_mut().insert(headers.orig_order);
287 }
288 }
289}
290
291ffi_fn! {
294 fn hyper_response_free(resp: *mut hyper_response) {
298 drop(non_null!(Box::from_raw(resp) ?= ()));
299 }
300}
301
302ffi_fn! {
303 fn hyper_response_status(resp: *const hyper_response) -> u16 {
307 non_null!(&*resp ?= 0).0.status().as_u16()
308 }
309}
310
311ffi_fn! {
312 fn hyper_response_reason_phrase(resp: *const hyper_response) -> *const u8 {
322 non_null!(&*resp ?= std::ptr::null()).reason_phrase().as_ptr()
323 } ?= std::ptr::null()
324}
325
326ffi_fn! {
327 fn hyper_response_reason_phrase_len(resp: *const hyper_response) -> size_t {
331 non_null!(&*resp ?= 0).reason_phrase().len()
332 }
333}
334
335ffi_fn! {
336 fn hyper_response_version(resp: *const hyper_response) -> c_int {
345 use http::Version;
346
347 match non_null!(&*resp ?= 0).0.version() {
348 Version::HTTP_10 => super::HYPER_HTTP_VERSION_1_0,
349 Version::HTTP_11 => super::HYPER_HTTP_VERSION_1_1,
350 Version::HTTP_2 => super::HYPER_HTTP_VERSION_2,
351 _ => super::HYPER_HTTP_VERSION_NONE,
352 }
353 }
354}
355
356ffi_fn! {
357 fn hyper_response_headers(resp: *mut hyper_response) -> *mut hyper_headers {
362 hyper_headers::get_or_default(unsafe { &mut *resp }.0.extensions_mut())
363 } ?= std::ptr::null_mut()
364}
365
366ffi_fn! {
367 fn hyper_response_body(resp: *mut hyper_response) -> *mut hyper_body {
374 let body = std::mem::replace(non_null!(&mut *resp ?= std::ptr::null_mut()).0.body_mut(), IncomingBody::empty());
375 Box::into_raw(Box::new(hyper_body(body)))
376 } ?= std::ptr::null_mut()
377}
378
379impl hyper_response {
380 pub(super) fn wrap(mut resp: Response<IncomingBody>) -> hyper_response {
381 let headers = std::mem::take(resp.headers_mut());
382 let orig_casing = resp
383 .extensions_mut()
384 .remove::<HeaderCaseMap>()
385 .unwrap_or_else(HeaderCaseMap::default);
386 let orig_order = resp
387 .extensions_mut()
388 .remove::<OriginalHeaderOrder>()
389 .unwrap_or_else(OriginalHeaderOrder::default);
390 resp.extensions_mut().insert(hyper_headers {
391 headers,
392 orig_casing,
393 orig_order,
394 });
395
396 hyper_response(resp)
397 }
398
399 fn reason_phrase(&self) -> &[u8] {
400 if let Some(reason) = self.0.extensions().get::<ReasonPhrase>() {
401 return reason.as_bytes();
402 }
403
404 if let Some(reason) = self.0.status().canonical_reason() {
405 return reason.as_bytes();
406 }
407
408 &[]
409 }
410}
411
412unsafe impl AsTaskType for hyper_response {
413 fn as_task_type(&self) -> hyper_task_return_type {
414 hyper_task_return_type::HYPER_TASK_RESPONSE
415 }
416}
417
418type hyper_headers_foreach_callback =
421 extern "C" fn(*mut c_void, *const u8, size_t, *const u8, size_t) -> c_int;
422
423impl hyper_headers {
424 pub(super) fn get_or_default(ext: &mut http::Extensions) -> &mut hyper_headers {
425 if let None = ext.get_mut::<hyper_headers>() {
426 ext.insert(hyper_headers::default());
427 }
428
429 ext.get_mut::<hyper_headers>().unwrap()
430 }
431}
432
433ffi_fn! {
434 fn hyper_headers_foreach(headers: *const hyper_headers, func: hyper_headers_foreach_callback, userdata: *mut c_void) {
441 let headers = non_null!(&*headers ?= ());
442 let mut ordered_iter = headers.orig_order.get_in_order().peekable();
448 if ordered_iter.peek().is_some() {
449 for (name, idx) in ordered_iter {
450 let (name_ptr, name_len) = if let Some(orig_name) = headers.orig_casing.get_all(name).nth(*idx) {
451 (orig_name.as_ref().as_ptr(), orig_name.as_ref().len())
452 } else {
453 (
454 name.as_str().as_bytes().as_ptr(),
455 name.as_str().as_bytes().len(),
456 )
457 };
458
459 let val_ptr;
460 let val_len;
461 if let Some(value) = headers.headers.get_all(name).iter().nth(*idx) {
462 val_ptr = value.as_bytes().as_ptr();
463 val_len = value.as_bytes().len();
464 } else {
465 return;
467 }
468
469 if HYPER_ITER_CONTINUE != func(userdata, name_ptr, name_len, val_ptr, val_len) {
470 return;
471 }
472 }
473 } else {
474 for name in headers.headers.keys() {
475 let mut names = headers.orig_casing.get_all(name);
476
477 for value in headers.headers.get_all(name) {
478 let (name_ptr, name_len) = if let Some(orig_name) = names.next() {
479 (orig_name.as_ref().as_ptr(), orig_name.as_ref().len())
480 } else {
481 (
482 name.as_str().as_bytes().as_ptr(),
483 name.as_str().as_bytes().len(),
484 )
485 };
486
487 let val_ptr = value.as_bytes().as_ptr();
488 let val_len = value.as_bytes().len();
489
490 if HYPER_ITER_CONTINUE != func(userdata, name_ptr, name_len, val_ptr, val_len) {
491 return;
492 }
493 }
494 }
495 }
496 }
497}
498
499ffi_fn! {
500 fn hyper_headers_set(headers: *mut hyper_headers, name: *const u8, name_len: size_t, value: *const u8, value_len: size_t) -> hyper_code {
504 let headers = non_null!(&mut *headers ?= hyper_code::HYPERE_INVALID_ARG);
505 match unsafe { raw_name_value(name, name_len, value, value_len) } {
506 Ok((name, value, orig_name)) => {
507 headers.headers.insert(&name, value);
508 headers.orig_casing.insert(name.clone(), orig_name.clone());
509 headers.orig_order.insert(name);
510 hyper_code::HYPERE_OK
511 }
512 Err(code) => code,
513 }
514 }
515}
516
517ffi_fn! {
518 fn hyper_headers_add(headers: *mut hyper_headers, name: *const u8, name_len: size_t, value: *const u8, value_len: size_t) -> hyper_code {
523 let headers = non_null!(&mut *headers ?= hyper_code::HYPERE_INVALID_ARG);
524
525 match unsafe { raw_name_value(name, name_len, value, value_len) } {
526 Ok((name, value, orig_name)) => {
527 headers.headers.append(&name, value);
528 headers.orig_casing.append(&name, orig_name.clone());
529 headers.orig_order.append(name);
530 hyper_code::HYPERE_OK
531 }
532 Err(code) => code,
533 }
534 }
535}
536
537impl Default for hyper_headers {
538 fn default() -> Self {
539 Self {
540 headers: Default::default(),
541 orig_casing: HeaderCaseMap::default(),
542 orig_order: OriginalHeaderOrder::default(),
543 }
544 }
545}
546
547unsafe fn raw_name_value(
548 name: *const u8,
549 name_len: size_t,
550 value: *const u8,
551 value_len: size_t,
552) -> Result<(HeaderName, HeaderValue, Bytes), hyper_code> {
553 let name = std::slice::from_raw_parts(name, name_len);
554 let orig_name = Bytes::copy_from_slice(name);
555 let name = match HeaderName::from_bytes(name) {
556 Ok(name) => name,
557 Err(_) => return Err(hyper_code::HYPERE_INVALID_ARG),
558 };
559 let value = std::slice::from_raw_parts(value, value_len);
560 let value = match HeaderValue::from_bytes(value) {
561 Ok(val) => val,
562 Err(_) => return Err(hyper_code::HYPERE_INVALID_ARG),
563 };
564
565 Ok((name, value, orig_name))
566}
567
568impl OnInformational {
571 pub(crate) fn call(&mut self, resp: Response<IncomingBody>) {
572 let mut resp = hyper_response::wrap(resp);
573 (self.func)(self.data.0, &mut resp);
574 }
575}
576
577#[cfg(test)]
578mod tests {
579 use super::*;
580
581 #[test]
582 fn test_headers_foreach_cases_preserved() {
583 let mut headers = hyper_headers::default();
584
585 let name1 = b"Set-CookiE";
586 let value1 = b"a=b";
587 hyper_headers_add(
588 &mut headers,
589 name1.as_ptr(),
590 name1.len(),
591 value1.as_ptr(),
592 value1.len(),
593 );
594
595 let name2 = b"SET-COOKIE";
596 let value2 = b"c=d";
597 hyper_headers_add(
598 &mut headers,
599 name2.as_ptr(),
600 name2.len(),
601 value2.as_ptr(),
602 value2.len(),
603 );
604
605 let mut vec = Vec::<u8>::new();
606 hyper_headers_foreach(&headers, concat, &mut vec as *mut _ as *mut c_void);
607
608 assert_eq!(vec, b"Set-CookiE: a=b\r\nSET-COOKIE: c=d\r\n");
609
610 extern "C" fn concat(
611 vec: *mut c_void,
612 name: *const u8,
613 name_len: usize,
614 value: *const u8,
615 value_len: usize,
616 ) -> c_int {
617 unsafe {
618 let vec = &mut *(vec as *mut Vec<u8>);
619 let name = std::slice::from_raw_parts(name, name_len);
620 let value = std::slice::from_raw_parts(value, value_len);
621 vec.extend(name);
622 vec.extend(b": ");
623 vec.extend(value);
624 vec.extend(b"\r\n");
625 }
626 HYPER_ITER_CONTINUE
627 }
628 }
629
630 #[cfg(all(feature = "http1", feature = "ffi"))]
631 #[test]
632 fn test_headers_foreach_order_preserved() {
633 let mut headers = hyper_headers::default();
634
635 let name1 = b"Set-CookiE";
636 let value1 = b"a=b";
637 hyper_headers_add(
638 &mut headers,
639 name1.as_ptr(),
640 name1.len(),
641 value1.as_ptr(),
642 value1.len(),
643 );
644
645 let name2 = b"Content-Encoding";
646 let value2 = b"gzip";
647 hyper_headers_add(
648 &mut headers,
649 name2.as_ptr(),
650 name2.len(),
651 value2.as_ptr(),
652 value2.len(),
653 );
654
655 let name3 = b"SET-COOKIE";
656 let value3 = b"c=d";
657 hyper_headers_add(
658 &mut headers,
659 name3.as_ptr(),
660 name3.len(),
661 value3.as_ptr(),
662 value3.len(),
663 );
664
665 let mut vec = Vec::<u8>::new();
666 hyper_headers_foreach(&headers, concat, &mut vec as *mut _ as *mut c_void);
667
668 println!("{}", std::str::from_utf8(&vec).unwrap());
669 assert_eq!(
670 vec,
671 b"Set-CookiE: a=b\r\nContent-Encoding: gzip\r\nSET-COOKIE: c=d\r\n"
672 );
673
674 extern "C" fn concat(
675 vec: *mut c_void,
676 name: *const u8,
677 name_len: usize,
678 value: *const u8,
679 value_len: usize,
680 ) -> c_int {
681 unsafe {
682 let vec = &mut *(vec as *mut Vec<u8>);
683 let name = std::slice::from_raw_parts(name, name_len);
684 let value = std::slice::from_raw_parts(value, value_len);
685 vec.extend(name);
686 vec.extend(b": ");
687 vec.extend(value);
688 vec.extend(b"\r\n");
689 }
690 HYPER_ITER_CONTINUE
691 }
692 }
693}