1use core::ffi::c_void;
2use core::fmt;
3use core::ptr::NonNull;
4use core::slice;
5use core::str::FromStr;
6
7use crate::core::*;
8use crate::ffi::*;
9use crate::http::status::*;
10
11#[macro_export]
15macro_rules! http_request_handler {
16 ( $name: ident, $handler: expr ) => {
17 extern "C" fn $name(r: *mut $crate::ffi::ngx_http_request_t) -> $crate::ffi::ngx_int_t {
18 let status: $crate::core::Status =
19 $handler(unsafe { &mut $crate::http::Request::from_ngx_http_request(r) });
20 status.0
21 }
22 };
23}
24
25#[macro_export]
29macro_rules! http_subrequest_handler {
30 ( $name: ident, $handler: expr ) => {
31 unsafe extern "C" fn $name(
32 r: *mut $crate::ffi::ngx_http_request_t,
33 data: *mut ::core::ffi::c_void,
34 rc: $crate::ffi::ngx_int_t,
35 ) -> $crate::ffi::ngx_int_t {
36 $handler(r, data, rc)
37 }
38 };
39}
40
41#[macro_export]
47macro_rules! http_variable_set {
48 ( $name: ident, $handler: expr ) => {
49 unsafe extern "C" fn $name(
50 r: *mut $crate::ffi::ngx_http_request_t,
51 v: *mut $crate::ffi::ngx_variable_value_t,
52 data: usize,
53 ) {
54 $handler(
55 unsafe { &mut $crate::http::Request::from_ngx_http_request(r) },
56 v,
57 data,
58 );
59 }
60 };
61}
62
63#[macro_export]
70macro_rules! http_variable_get {
71 ( $name: ident, $handler: expr ) => {
72 unsafe extern "C" fn $name(
73 r: *mut $crate::ffi::ngx_http_request_t,
74 v: *mut $crate::ffi::ngx_variable_value_t,
75 data: usize,
76 ) -> $crate::ffi::ngx_int_t {
77 let status: $crate::core::Status = $handler(
78 unsafe { &mut $crate::http::Request::from_ngx_http_request(r) },
79 v,
80 data,
81 );
82 status.0
83 }
84 };
85}
86
87#[repr(transparent)]
91pub struct Request(ngx_http_request_t);
92
93impl<'a> From<&'a Request> for *const ngx_http_request_t {
94 fn from(request: &'a Request) -> Self {
95 &request.0 as *const _
96 }
97}
98
99impl<'a> From<&'a mut Request> for *mut ngx_http_request_t {
100 fn from(request: &'a mut Request) -> Self {
101 &request.0 as *const _ as *mut _
102 }
103}
104
105impl AsRef<ngx_http_request_t> for Request {
106 fn as_ref(&self) -> &ngx_http_request_t {
107 &self.0
108 }
109}
110
111impl AsMut<ngx_http_request_t> for Request {
112 fn as_mut(&mut self) -> &mut ngx_http_request_t {
113 &mut self.0
114 }
115}
116
117impl Request {
118 pub unsafe fn from_ngx_http_request<'a>(r: *mut ngx_http_request_t) -> &'a mut Request {
125 &mut *r.cast::<Request>()
126 }
127
128 pub fn is_main(&self) -> bool {
130 let main = self.0.main.cast();
131 core::ptr::eq(self, main)
132 }
133
134 pub fn pool(&self) -> Pool {
136 unsafe { Pool::from_ngx_pool(self.0.pool) }
138 }
139
140 pub fn upstream(&self) -> Option<*mut ngx_http_upstream_t> {
148 if self.0.upstream.is_null() {
149 return None;
150 }
151 Some(self.0.upstream)
152 }
153
154 pub fn connection(&self) -> *mut ngx_connection_t {
158 self.0.connection
159 }
160
161 pub fn log(&self) -> *mut ngx_log_t {
165 unsafe { (*self.connection()).log }
166 }
167
168 fn get_module_ctx_ptr(&self, module: &ngx_module_t) -> *mut c_void {
170 unsafe { *self.0.ctx.add(module.ctx_index) }
171 }
172
173 pub fn get_module_ctx<T>(&self, module: &ngx_module_t) -> Option<&T> {
175 let ctx = self.get_module_ctx_ptr(module).cast::<T>();
176 unsafe { ctx.as_ref() }
179 }
180
181 pub fn set_module_ctx(&self, value: *mut c_void, module: &ngx_module_t) {
185 unsafe {
186 *self.0.ctx.add(module.ctx_index) = value;
187 };
188 }
189
190 pub fn get_complex_value(&self, cv: &ngx_http_complex_value_t) -> Option<&NgxStr> {
194 let r = (self as *const Request as *mut Request).cast();
195 let val = cv as *const ngx_http_complex_value_t as *mut ngx_http_complex_value_t;
196 unsafe {
199 let mut value = ngx_str_t::default();
200 if ngx_http_complex_value(r, val, &mut value) != NGX_OK as ngx_int_t {
201 return None;
202 }
203 Some(NgxStr::from_ngx_str(value))
204 }
205 }
206
207 pub fn discard_request_body(&mut self) -> Status {
211 unsafe { Status(ngx_http_discard_request_body(&mut self.0)) }
212 }
213
214 pub fn user_agent(&self) -> Option<&NgxStr> {
218 if !self.0.headers_in.user_agent.is_null() {
219 unsafe { Some(NgxStr::from_ngx_str((*self.0.headers_in.user_agent).value)) }
220 } else {
221 None
222 }
223 }
224
225 pub fn set_status(&mut self, status: HTTPStatus) {
227 self.0.headers_out.status = status.into();
228 }
229
230 pub fn add_header_in(&mut self, key: &str, value: &str) -> Option<()> {
234 let table: *mut ngx_table_elt_t = unsafe { ngx_list_push(&mut self.0.headers_in.headers) as _ };
235 unsafe { add_to_ngx_table(table, self.0.pool, key, value) }
236 }
237
238 pub fn add_header_out(&mut self, key: &str, value: &str) -> Option<()> {
242 let table: *mut ngx_table_elt_t = unsafe { ngx_list_push(&mut self.0.headers_out.headers) as _ };
243 unsafe { add_to_ngx_table(table, self.0.pool, key, value) }
244 }
245
246 pub fn set_content_length_n(&mut self, n: usize) {
250 self.0.headers_out.content_length_n = n as off_t;
251 }
252
253 pub fn send_header(&mut self) -> Status {
257 unsafe { Status(ngx_http_send_header(&mut self.0)) }
258 }
259
260 pub fn header_only(&self) -> bool {
264 self.0.header_only() != 0
265 }
266
267 pub fn method(&self) -> Method {
269 Method::from_ngx(self.0.method)
270 }
271
272 pub fn path(&self) -> &NgxStr {
274 unsafe { NgxStr::from_ngx_str(self.0.uri) }
275 }
276
277 pub fn unparsed_uri(&self) -> &NgxStr {
279 unsafe { NgxStr::from_ngx_str(self.0.unparsed_uri) }
280 }
281
282 pub fn output_filter(&mut self, body: &mut ngx_chain_t) -> Status {
289 unsafe { Status(ngx_http_output_filter(&mut self.0, body)) }
290 }
291
292 pub fn internal_redirect(&self, location: &str) -> Status {
294 assert!(!location.is_empty(), "uri location is empty");
295 let uri_ptr = unsafe { &mut ngx_str_t::from_str(self.0.pool, location) as *mut _ };
296
297 if location.starts_with('@') {
299 unsafe {
300 ngx_http_named_location((self as *const Request as *mut Request).cast(), uri_ptr);
301 }
302 } else {
303 unsafe {
304 ngx_http_internal_redirect(
305 (self as *const Request as *mut Request).cast(),
306 uri_ptr,
307 core::ptr::null_mut(),
308 );
309 }
310 }
311 Status::NGX_DONE
312 }
313
314 pub fn subrequest(
316 &self,
317 uri: &str,
318 module: &ngx_module_t,
319 post_callback: unsafe extern "C" fn(*mut ngx_http_request_t, *mut c_void, ngx_int_t) -> ngx_int_t,
320 ) -> Status {
321 let uri_ptr = unsafe { &mut ngx_str_t::from_str(self.0.pool, uri) as *mut _ };
322 let sub_ptr = self.pool().alloc(core::mem::size_of::<ngx_http_post_subrequest_t>());
325
326 let post_subreq = sub_ptr as *const ngx_http_post_subrequest_t as *mut ngx_http_post_subrequest_t;
328 unsafe {
329 (*post_subreq).handler = Some(post_callback);
330 (*post_subreq).data = self.get_module_ctx_ptr(module); }
332 let mut psr: *mut ngx_http_request_t = core::ptr::null_mut();
335 let r = unsafe {
336 ngx_http_subrequest(
337 (self as *const Request as *mut Request).cast(),
338 uri_ptr,
339 core::ptr::null_mut(),
340 &mut psr as *mut _,
341 sub_ptr as *mut _,
342 NGX_HTTP_SUBREQUEST_WAITED as _,
343 )
344 };
345
346 let sr = unsafe { &mut *psr };
348
349 sr.request_body = self.pool().alloc(core::mem::size_of::<ngx_http_request_body_t>()) as *mut _;
354
355 if sr.request_body.is_null() {
356 return Status::NGX_ERROR;
357 }
358 sr.set_header_only(1 as _);
359 Status(r)
360 }
361
362 pub fn headers_in_iterator(&self) -> NgxListIterator {
365 unsafe { list_iterator(&self.0.headers_in.headers) }
366 }
367
368 pub fn headers_out_iterator(&self) -> NgxListIterator {
371 unsafe { list_iterator(&self.0.headers_out.headers) }
372 }
373}
374
375impl crate::http::HttpModuleConfExt for Request {
376 #[inline]
377 unsafe fn http_main_conf_unchecked<T>(&self, module: &ngx_module_t) -> Option<NonNull<T>> {
378 NonNull::new((*self.0.main_conf.add(module.ctx_index)).cast())
381 }
382
383 #[inline]
384 unsafe fn http_server_conf_unchecked<T>(&self, module: &ngx_module_t) -> Option<NonNull<T>> {
385 NonNull::new((*self.0.srv_conf.add(module.ctx_index)).cast())
388 }
389
390 #[inline]
391 unsafe fn http_location_conf_unchecked<T>(&self, module: &ngx_module_t) -> Option<NonNull<T>> {
392 NonNull::new((*self.0.loc_conf.add(module.ctx_index)).cast())
395 }
396}
397
398impl fmt::Debug for Request {
403 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 f.debug_struct("Request").field("request_", &self.0).finish()
405 }
406}
407
408pub struct NgxListIterator<'a> {
412 part: Option<ListPart<'a>>,
413 i: ngx_uint_t,
414}
415struct ListPart<'a> {
416 raw: &'a ngx_list_part_t,
417 arr: &'a [ngx_table_elt_t],
418}
419impl<'a> From<&'a ngx_list_part_t> for ListPart<'a> {
420 fn from(raw: &'a ngx_list_part_t) -> Self {
421 let arr = if raw.nelts != 0 {
422 unsafe { slice::from_raw_parts(raw.elts.cast(), raw.nelts) }
423 } else {
424 &[]
425 };
426 Self { raw, arr }
427 }
428}
429
430pub unsafe fn list_iterator(list: &ngx_list_t) -> NgxListIterator {
436 NgxListIterator {
437 part: Some((&list.part).into()),
438 i: 0,
439 }
440}
441
442impl<'a> Iterator for NgxListIterator<'a> {
444 type Item = (&'a str, &'a str);
449
450 fn next(&mut self) -> Option<Self::Item> {
451 let part = self.part.as_mut()?;
452 if self.i >= part.arr.len() {
453 if let Some(next_part_raw) = unsafe { part.raw.next.as_ref() } {
454 *part = next_part_raw.into();
456 self.i = 0;
457 } else {
458 self.part = None;
459 return None;
460 }
461 }
462 let header = &part.arr[self.i];
463 self.i += 1;
464 Some((header.key.to_str(), header.value.to_str()))
465 }
466}
467
468pub struct InvalidMethod {
470 _priv: (),
471}
472
473#[derive(Clone, PartialEq, Eq, Hash)]
475pub struct Method(MethodInner);
476
477impl Method {
478 pub const UNKNOWN: Method = Method(MethodInner::Unknown);
480
481 pub const GET: Method = Method(MethodInner::Get);
483
484 pub const HEAD: Method = Method(MethodInner::Head);
486
487 pub const POST: Method = Method(MethodInner::Post);
489
490 pub const PUT: Method = Method(MethodInner::Put);
492
493 pub const DELETE: Method = Method(MethodInner::Delete);
495
496 pub const MKCOL: Method = Method(MethodInner::Mkcol);
498
499 pub const COPY: Method = Method(MethodInner::Copy);
501
502 pub const MOVE: Method = Method(MethodInner::Move);
504
505 pub const OPTIONS: Method = Method(MethodInner::Options);
507
508 pub const PROPFIND: Method = Method(MethodInner::Propfind);
510
511 pub const PROPPATCH: Method = Method(MethodInner::Proppatch);
513
514 pub const LOCK: Method = Method(MethodInner::Lock);
516
517 pub const UNLOCK: Method = Method(MethodInner::Unlock);
519
520 pub const PATCH: Method = Method(MethodInner::Patch);
522
523 pub const TRACE: Method = Method(MethodInner::Trace);
525
526 pub const CONNECT: Method = Method(MethodInner::Connect);
528
529 #[inline]
531 pub fn as_str(&self) -> &str {
532 match self.0 {
533 MethodInner::Unknown => "UNKNOWN",
534 MethodInner::Get => "GET",
535 MethodInner::Head => "HEAD",
536 MethodInner::Post => "POST",
537 MethodInner::Put => "PUT",
538 MethodInner::Delete => "DELETE",
539 MethodInner::Mkcol => "MKCOL",
540 MethodInner::Copy => "COPY",
541 MethodInner::Move => "MOVE",
542 MethodInner::Options => "OPTIONS",
543 MethodInner::Propfind => "PROPFIND",
544 MethodInner::Proppatch => "PROPPATCH",
545 MethodInner::Lock => "LOCK",
546 MethodInner::Unlock => "UNLOCK",
547 MethodInner::Patch => "PATCH",
548 MethodInner::Trace => "TRACE",
549 MethodInner::Connect => "CONNECT",
550 }
551 }
552
553 fn from_bytes(_t: &[u8]) -> Result<Method, InvalidMethod> {
554 todo!()
555 }
556
557 fn from_ngx(t: ngx_uint_t) -> Method {
558 let t = t as _;
559 match t {
560 crate::ffi::NGX_HTTP_GET => Method(MethodInner::Get),
561 crate::ffi::NGX_HTTP_HEAD => Method(MethodInner::Head),
562 crate::ffi::NGX_HTTP_POST => Method(MethodInner::Post),
563 crate::ffi::NGX_HTTP_PUT => Method(MethodInner::Put),
564 crate::ffi::NGX_HTTP_DELETE => Method(MethodInner::Delete),
565 crate::ffi::NGX_HTTP_MKCOL => Method(MethodInner::Mkcol),
566 crate::ffi::NGX_HTTP_COPY => Method(MethodInner::Copy),
567 crate::ffi::NGX_HTTP_MOVE => Method(MethodInner::Move),
568 crate::ffi::NGX_HTTP_OPTIONS => Method(MethodInner::Options),
569 crate::ffi::NGX_HTTP_PROPFIND => Method(MethodInner::Propfind),
570 crate::ffi::NGX_HTTP_PROPPATCH => Method(MethodInner::Proppatch),
571 crate::ffi::NGX_HTTP_LOCK => Method(MethodInner::Lock),
572 crate::ffi::NGX_HTTP_UNLOCK => Method(MethodInner::Unlock),
573 crate::ffi::NGX_HTTP_PATCH => Method(MethodInner::Patch),
574 crate::ffi::NGX_HTTP_TRACE => Method(MethodInner::Trace),
575 #[cfg(nginx1_21_1)]
576 crate::ffi::NGX_HTTP_CONNECT => Method(MethodInner::Connect),
577 _ => Method(MethodInner::Unknown),
578 }
579 }
580}
581
582impl AsRef<str> for Method {
583 #[inline]
584 fn as_ref(&self) -> &str {
585 self.as_str()
586 }
587}
588
589impl<'a> PartialEq<&'a Method> for Method {
590 #[inline]
591 fn eq(&self, other: &&'a Method) -> bool {
592 self == *other
593 }
594}
595
596impl PartialEq<Method> for &Method {
597 #[inline]
598 fn eq(&self, other: &Method) -> bool {
599 *self == other
600 }
601}
602
603impl PartialEq<str> for Method {
604 #[inline]
605 fn eq(&self, other: &str) -> bool {
606 self.as_ref() == other
607 }
608}
609
610impl PartialEq<Method> for str {
611 #[inline]
612 fn eq(&self, other: &Method) -> bool {
613 self == other.as_ref()
614 }
615}
616
617impl<'a> PartialEq<&'a str> for Method {
618 #[inline]
619 fn eq(&self, other: &&'a str) -> bool {
620 self.as_ref() == *other
621 }
622}
623
624impl PartialEq<Method> for &str {
625 #[inline]
626 fn eq(&self, other: &Method) -> bool {
627 *self == other.as_ref()
628 }
629}
630
631impl fmt::Debug for Method {
632 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
633 f.write_str(self.as_ref())
634 }
635}
636
637impl fmt::Display for Method {
638 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
639 fmt.write_str(self.as_ref())
640 }
641}
642
643impl<'a> From<&'a Method> for Method {
644 #[inline]
645 fn from(t: &'a Method) -> Self {
646 t.clone()
647 }
648}
649
650impl<'a> TryFrom<&'a [u8]> for Method {
651 type Error = InvalidMethod;
652
653 #[inline]
654 fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
655 Method::from_bytes(t)
656 }
657}
658
659impl<'a> TryFrom<&'a str> for Method {
660 type Error = InvalidMethod;
661
662 #[inline]
663 fn try_from(t: &'a str) -> Result<Self, Self::Error> {
664 TryFrom::try_from(t.as_bytes())
665 }
666}
667
668impl FromStr for Method {
669 type Err = InvalidMethod;
670
671 #[inline]
672 fn from_str(t: &str) -> Result<Self, Self::Err> {
673 TryFrom::try_from(t)
674 }
675}
676
677impl InvalidMethod {
678 #[allow(dead_code)]
679 fn new() -> InvalidMethod {
680 InvalidMethod { _priv: () }
681 }
682}
683
684impl fmt::Debug for InvalidMethod {
685 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
686 f.debug_struct("InvalidMethod")
687 .finish()
689 }
690}
691
692impl fmt::Display for InvalidMethod {
693 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
694 f.write_str("invalid HTTP method")
695 }
696}
697
698#[cfg(feature = "std")]
699impl std::error::Error for InvalidMethod {}
700
701#[derive(Clone, PartialEq, Eq, Hash)]
702enum MethodInner {
703 Unknown,
704 Get,
705 Head,
706 Post,
707 Put,
708 Delete,
709 Mkcol,
710 Copy,
711 Move,
712 Options,
713 Propfind,
714 Proppatch,
715 Lock,
716 Unlock,
717 Patch,
718 Trace,
719 Connect,
720}