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 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 #[cfg(feature = "client")]
272 {
273 let ext = OnInformational {
274 func: callback,
275 data: UserDataPointer(data),
276 };
277 let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);
278 crate::ext::on_informational_raw(&mut req.0, ext);
279 hyper_code::HYPERE_OK
280 }
281 #[cfg(not(feature = "client"))]
282 {
283 drop((req, callback, data));
284 hyper_code::HYPERE_FEATURE_NOT_ENABLED
285 }
286 }
287}
288
289impl hyper_request {
290 pub(super) fn finalize_request(&mut self) {
291 if let Some(headers) = self.0.extensions_mut().remove::<hyper_headers>() {
292 *self.0.headers_mut() = headers.headers;
293 self.0.extensions_mut().insert(headers.orig_casing);
294 self.0.extensions_mut().insert(headers.orig_order);
295 }
296 }
297}
298
299ffi_fn! {
302 fn hyper_response_free(resp: *mut hyper_response) {
306 drop(non_null!(Box::from_raw(resp) ?= ()));
307 }
308}
309
310ffi_fn! {
311 fn hyper_response_status(resp: *const hyper_response) -> u16 {
315 non_null!(&*resp ?= 0).0.status().as_u16()
316 }
317}
318
319ffi_fn! {
320 fn hyper_response_reason_phrase(resp: *const hyper_response) -> *const u8 {
330 non_null!(&*resp ?= std::ptr::null()).reason_phrase().as_ptr()
331 } ?= std::ptr::null()
332}
333
334ffi_fn! {
335 fn hyper_response_reason_phrase_len(resp: *const hyper_response) -> size_t {
339 non_null!(&*resp ?= 0).reason_phrase().len()
340 }
341}
342
343ffi_fn! {
344 fn hyper_response_version(resp: *const hyper_response) -> c_int {
353 use http::Version;
354
355 match non_null!(&*resp ?= 0).0.version() {
356 Version::HTTP_10 => super::HYPER_HTTP_VERSION_1_0,
357 Version::HTTP_11 => super::HYPER_HTTP_VERSION_1_1,
358 Version::HTTP_2 => super::HYPER_HTTP_VERSION_2,
359 _ => super::HYPER_HTTP_VERSION_NONE,
360 }
361 }
362}
363
364ffi_fn! {
365 fn hyper_response_headers(resp: *mut hyper_response) -> *mut hyper_headers {
370 hyper_headers::get_or_default(unsafe { &mut *resp }.0.extensions_mut())
371 } ?= std::ptr::null_mut()
372}
373
374ffi_fn! {
375 fn hyper_response_body(resp: *mut hyper_response) -> *mut hyper_body {
382 let body = std::mem::replace(non_null!(&mut *resp ?= std::ptr::null_mut()).0.body_mut(), IncomingBody::empty());
383 Box::into_raw(Box::new(hyper_body(body)))
384 } ?= std::ptr::null_mut()
385}
386
387impl hyper_response {
388 pub(super) fn wrap(mut resp: Response<IncomingBody>) -> hyper_response {
389 let headers = std::mem::take(resp.headers_mut());
390 let orig_casing = resp
391 .extensions_mut()
392 .remove::<HeaderCaseMap>()
393 .unwrap_or_else(HeaderCaseMap::default);
394 let orig_order = resp
395 .extensions_mut()
396 .remove::<OriginalHeaderOrder>()
397 .unwrap_or_else(OriginalHeaderOrder::default);
398 resp.extensions_mut().insert(hyper_headers {
399 headers,
400 orig_casing,
401 orig_order,
402 });
403
404 hyper_response(resp)
405 }
406
407 fn reason_phrase(&self) -> &[u8] {
408 if let Some(reason) = self.0.extensions().get::<ReasonPhrase>() {
409 return reason.as_bytes();
410 }
411
412 if let Some(reason) = self.0.status().canonical_reason() {
413 return reason.as_bytes();
414 }
415
416 &[]
417 }
418}
419
420unsafe impl AsTaskType for hyper_response {
421 fn as_task_type(&self) -> hyper_task_return_type {
422 hyper_task_return_type::HYPER_TASK_RESPONSE
423 }
424}
425
426type hyper_headers_foreach_callback =
429 extern "C" fn(*mut c_void, *const u8, size_t, *const u8, size_t) -> c_int;
430
431impl hyper_headers {
432 pub(super) fn get_or_default(ext: &mut http::Extensions) -> &mut hyper_headers {
433 if let None = ext.get_mut::<hyper_headers>() {
434 ext.insert(hyper_headers::default());
435 }
436
437 ext.get_mut::<hyper_headers>().unwrap()
438 }
439}
440
441ffi_fn! {
442 fn hyper_headers_foreach(headers: *const hyper_headers, func: hyper_headers_foreach_callback, userdata: *mut c_void) {
449 let headers = non_null!(&*headers ?= ());
450 let mut ordered_iter = headers.orig_order.get_in_order().peekable();
456 if ordered_iter.peek().is_some() {
457 for (name, idx) in ordered_iter {
458 let (name_ptr, name_len) = if let Some(orig_name) = headers.orig_casing.get_all(name).nth(*idx) {
459 (orig_name.as_ref().as_ptr(), orig_name.as_ref().len())
460 } else {
461 (
462 name.as_str().as_bytes().as_ptr(),
463 name.as_str().as_bytes().len(),
464 )
465 };
466
467 let val_ptr;
468 let val_len;
469 if let Some(value) = headers.headers.get_all(name).iter().nth(*idx) {
470 val_ptr = value.as_bytes().as_ptr();
471 val_len = value.as_bytes().len();
472 } else {
473 return;
475 }
476
477 if HYPER_ITER_CONTINUE != func(userdata, name_ptr, name_len, val_ptr, val_len) {
478 return;
479 }
480 }
481 } else {
482 for name in headers.headers.keys() {
483 let mut names = headers.orig_casing.get_all(name);
484
485 for value in headers.headers.get_all(name) {
486 let (name_ptr, name_len) = if let Some(orig_name) = names.next() {
487 (orig_name.as_ref().as_ptr(), orig_name.as_ref().len())
488 } else {
489 (
490 name.as_str().as_bytes().as_ptr(),
491 name.as_str().as_bytes().len(),
492 )
493 };
494
495 let val_ptr = value.as_bytes().as_ptr();
496 let val_len = value.as_bytes().len();
497
498 if HYPER_ITER_CONTINUE != func(userdata, name_ptr, name_len, val_ptr, val_len) {
499 return;
500 }
501 }
502 }
503 }
504 }
505}
506
507ffi_fn! {
508 fn hyper_headers_set(headers: *mut hyper_headers, name: *const u8, name_len: size_t, value: *const u8, value_len: size_t) -> hyper_code {
512 let headers = non_null!(&mut *headers ?= hyper_code::HYPERE_INVALID_ARG);
513 match unsafe { raw_name_value(name, name_len, value, value_len) } {
514 Ok((name, value, orig_name)) => {
515 headers.headers.insert(&name, value);
516 headers.orig_casing.insert(name.clone(), orig_name.clone());
517 headers.orig_order.insert(name);
518 hyper_code::HYPERE_OK
519 }
520 Err(code) => code,
521 }
522 }
523}
524
525ffi_fn! {
526 fn hyper_headers_add(headers: *mut hyper_headers, name: *const u8, name_len: size_t, value: *const u8, value_len: size_t) -> hyper_code {
531 let headers = non_null!(&mut *headers ?= hyper_code::HYPERE_INVALID_ARG);
532
533 match unsafe { raw_name_value(name, name_len, value, value_len) } {
534 Ok((name, value, orig_name)) => {
535 headers.headers.append(&name, value);
536 headers.orig_casing.append(&name, orig_name.clone());
537 headers.orig_order.append(name);
538 hyper_code::HYPERE_OK
539 }
540 Err(code) => code,
541 }
542 }
543}
544
545impl Default for hyper_headers {
546 fn default() -> Self {
547 Self {
548 headers: Default::default(),
549 orig_casing: HeaderCaseMap::default(),
550 orig_order: OriginalHeaderOrder::default(),
551 }
552 }
553}
554
555unsafe fn raw_name_value(
556 name: *const u8,
557 name_len: size_t,
558 value: *const u8,
559 value_len: size_t,
560) -> Result<(HeaderName, HeaderValue, Bytes), hyper_code> {
561 let name = std::slice::from_raw_parts(name, name_len);
562 let orig_name = Bytes::copy_from_slice(name);
563 let name = match HeaderName::from_bytes(name) {
564 Ok(name) => name,
565 Err(_) => return Err(hyper_code::HYPERE_INVALID_ARG),
566 };
567 let value = std::slice::from_raw_parts(value, value_len);
568 let value = match HeaderValue::from_bytes(value) {
569 Ok(val) => val,
570 Err(_) => return Err(hyper_code::HYPERE_INVALID_ARG),
571 };
572
573 Ok((name, value, orig_name))
574}
575
576#[cfg(feature = "client")]
579impl crate::ext::OnInformationalCallback for OnInformational {
580 fn on_informational(&self, res: http::Response<()>) {
581 let res = res.map(|()| IncomingBody::empty());
582 let mut res = hyper_response::wrap(res);
583 (self.func)(self.data.0, &mut res);
584 }
585}
586
587#[cfg(test)]
588mod tests {
589 use super::*;
590
591 #[test]
592 fn test_headers_foreach_cases_preserved() {
593 let mut headers = hyper_headers::default();
594
595 let name1 = b"Set-CookiE";
596 let value1 = b"a=b";
597 hyper_headers_add(
598 &mut headers,
599 name1.as_ptr(),
600 name1.len(),
601 value1.as_ptr(),
602 value1.len(),
603 );
604
605 let name2 = b"SET-COOKIE";
606 let value2 = b"c=d";
607 hyper_headers_add(
608 &mut headers,
609 name2.as_ptr(),
610 name2.len(),
611 value2.as_ptr(),
612 value2.len(),
613 );
614
615 let mut vec = Vec::<u8>::new();
616 hyper_headers_foreach(&headers, concat, &mut vec as *mut _ as *mut c_void);
617
618 assert_eq!(vec, b"Set-CookiE: a=b\r\nSET-COOKIE: c=d\r\n");
619
620 extern "C" fn concat(
621 vec: *mut c_void,
622 name: *const u8,
623 name_len: usize,
624 value: *const u8,
625 value_len: usize,
626 ) -> c_int {
627 unsafe {
628 let vec = &mut *(vec as *mut Vec<u8>);
629 let name = std::slice::from_raw_parts(name, name_len);
630 let value = std::slice::from_raw_parts(value, value_len);
631 vec.extend(name);
632 vec.extend(b": ");
633 vec.extend(value);
634 vec.extend(b"\r\n");
635 }
636 HYPER_ITER_CONTINUE
637 }
638 }
639
640 #[cfg(all(feature = "http1"))]
641 #[test]
642 fn test_headers_foreach_order_preserved() {
643 let mut headers = hyper_headers::default();
644
645 let name1 = b"Set-CookiE";
646 let value1 = b"a=b";
647 hyper_headers_add(
648 &mut headers,
649 name1.as_ptr(),
650 name1.len(),
651 value1.as_ptr(),
652 value1.len(),
653 );
654
655 let name2 = b"Content-Encoding";
656 let value2 = b"gzip";
657 hyper_headers_add(
658 &mut headers,
659 name2.as_ptr(),
660 name2.len(),
661 value2.as_ptr(),
662 value2.len(),
663 );
664
665 let name3 = b"SET-COOKIE";
666 let value3 = b"c=d";
667 hyper_headers_add(
668 &mut headers,
669 name3.as_ptr(),
670 name3.len(),
671 value3.as_ptr(),
672 value3.len(),
673 );
674
675 let mut vec = Vec::<u8>::new();
676 hyper_headers_foreach(&headers, concat, &mut vec as *mut _ as *mut c_void);
677
678 println!("{}", std::str::from_utf8(&vec).unwrap());
679 assert_eq!(
680 vec,
681 b"Set-CookiE: a=b\r\nContent-Encoding: gzip\r\nSET-COOKIE: c=d\r\n"
682 );
683
684 extern "C" fn concat(
685 vec: *mut c_void,
686 name: *const u8,
687 name_len: usize,
688 value: *const u8,
689 value_len: usize,
690 ) -> c_int {
691 unsafe {
692 let vec = &mut *(vec as *mut Vec<u8>);
693 let name = std::slice::from_raw_parts(name, name_len);
694 let value = std::slice::from_raw_parts(value, value_len);
695 vec.extend(name);
696 vec.extend(b": ");
697 vec.extend(value);
698 vec.extend(b"\r\n");
699 }
700 HYPER_ITER_CONTINUE
701 }
702 }
703}