1use core::error;
2use core::ffi::c_void;
3use core::fmt;
4use core::ptr::NonNull;
5use core::slice;
6use core::str::FromStr;
7
8use crate::core::*;
9use crate::ffi::*;
10use crate::http::status::*;
11
12#[macro_export]
16macro_rules! http_request_handler {
17 ( $name: ident, $handler: expr ) => {
18 extern "C" fn $name(r: *mut $crate::ffi::ngx_http_request_t) -> $crate::ffi::ngx_int_t {
19 let status: $crate::core::Status =
20 $handler(unsafe { &mut $crate::http::Request::from_ngx_http_request(r) });
21 status.0
22 }
23 };
24}
25
26#[macro_export]
30macro_rules! http_subrequest_handler {
31 ( $name: ident, $handler: expr ) => {
32 unsafe extern "C" fn $name(
33 r: *mut $crate::ffi::ngx_http_request_t,
34 data: *mut ::core::ffi::c_void,
35 rc: $crate::ffi::ngx_int_t,
36 ) -> $crate::ffi::ngx_int_t {
37 $handler(r, data, rc)
38 }
39 };
40}
41
42#[macro_export]
48macro_rules! http_variable_set {
49 ( $name: ident, $handler: expr ) => {
50 unsafe extern "C" fn $name(
51 r: *mut $crate::ffi::ngx_http_request_t,
52 v: *mut $crate::ffi::ngx_variable_value_t,
53 data: usize,
54 ) {
55 $handler(
56 unsafe { &mut $crate::http::Request::from_ngx_http_request(r) },
57 v,
58 data,
59 );
60 }
61 };
62}
63
64#[macro_export]
71macro_rules! http_variable_get {
72 ( $name: ident, $handler: expr ) => {
73 unsafe extern "C" fn $name(
74 r: *mut $crate::ffi::ngx_http_request_t,
75 v: *mut $crate::ffi::ngx_variable_value_t,
76 data: usize,
77 ) -> $crate::ffi::ngx_int_t {
78 let status: $crate::core::Status = $handler(
79 unsafe { &mut $crate::http::Request::from_ngx_http_request(r) },
80 v,
81 data,
82 );
83 status.0
84 }
85 };
86}
87
88#[repr(transparent)]
93pub struct Request(ngx_http_request_t);
94
95impl<'a> From<&'a Request> for *const ngx_http_request_t {
96 fn from(request: &'a Request) -> Self {
97 &request.0 as *const _
98 }
99}
100
101impl<'a> From<&'a mut Request> for *mut ngx_http_request_t {
102 fn from(request: &'a mut Request) -> Self {
103 &request.0 as *const _ as *mut _
104 }
105}
106
107impl AsRef<ngx_http_request_t> for Request {
108 fn as_ref(&self) -> &ngx_http_request_t {
109 &self.0
110 }
111}
112
113impl AsMut<ngx_http_request_t> for Request {
114 fn as_mut(&mut self) -> &mut ngx_http_request_t {
115 &mut self.0
116 }
117}
118
119impl Request {
120 pub unsafe fn from_ngx_http_request<'a>(r: *mut ngx_http_request_t) -> &'a mut Request {
127 &mut *r.cast::<Request>()
128 }
129
130 pub fn is_main(&self) -> bool {
132 let main = self.0.main.cast();
133 core::ptr::eq(self, main)
134 }
135
136 pub fn pool(&self) -> Pool {
138 unsafe { Pool::from_ngx_pool(self.0.pool) }
140 }
141
142 pub fn upstream(&self) -> Option<*mut ngx_http_upstream_t> {
150 if self.0.upstream.is_null() {
151 return None;
152 }
153 Some(self.0.upstream)
154 }
155
156 pub fn connection(&self) -> *mut ngx_connection_t {
160 self.0.connection
161 }
162
163 pub fn log(&self) -> *mut ngx_log_t {
167 unsafe { (*self.connection()).log }
168 }
169
170 fn get_module_ctx_ptr(&self, module: &ngx_module_t) -> *mut c_void {
172 unsafe { *self.0.ctx.add(module.ctx_index) }
173 }
174
175 pub fn get_module_ctx<T>(&self, module: &ngx_module_t) -> Option<&T> {
177 let ctx = self.get_module_ctx_ptr(module).cast::<T>();
178 unsafe { ctx.as_ref() }
181 }
182
183 pub fn set_module_ctx(&self, value: *mut c_void, module: &ngx_module_t) {
187 unsafe {
188 *self.0.ctx.add(module.ctx_index) = value;
189 };
190 }
191
192 pub fn get_complex_value(&self, cv: &ngx_http_complex_value_t) -> Option<&NgxStr> {
196 let r = (self as *const Request as *mut Request).cast();
197 let val = cv as *const ngx_http_complex_value_t as *mut ngx_http_complex_value_t;
198 unsafe {
201 let mut value = ngx_str_t::default();
202 if ngx_http_complex_value(r, val, &mut value) != NGX_OK as ngx_int_t {
203 return None;
204 }
205 Some(NgxStr::from_ngx_str(value))
206 }
207 }
208
209 pub fn discard_request_body(&mut self) -> Status {
213 unsafe { Status(ngx_http_discard_request_body(&mut self.0)) }
214 }
215
216 pub fn user_agent(&self) -> Option<&NgxStr> {
220 if !self.0.headers_in.user_agent.is_null() {
221 unsafe { Some(NgxStr::from_ngx_str((*self.0.headers_in.user_agent).value)) }
222 } else {
223 None
224 }
225 }
226
227 pub fn set_status(&mut self, status: HTTPStatus) {
229 self.0.headers_out.status = status.into();
230 }
231
232 pub fn add_header_in(&mut self, key: &str, value: &str) -> Option<()> {
236 let table: *mut ngx_table_elt_t =
237 unsafe { ngx_list_push(&mut self.0.headers_in.headers) as _ };
238 unsafe { add_to_ngx_table(table, self.0.pool, key, value) }
239 }
240
241 pub fn add_header_out(&mut self, key: &str, value: &str) -> Option<()> {
245 let table: *mut ngx_table_elt_t =
246 unsafe { ngx_list_push(&mut self.0.headers_out.headers) as _ };
247 unsafe { add_to_ngx_table(table, self.0.pool, key, value) }
248 }
249
250 pub fn set_content_length_n(&mut self, n: usize) {
254 self.0.headers_out.content_length_n = n as off_t;
255 }
256
257 pub fn send_header(&mut self) -> Status {
261 unsafe { Status(ngx_http_send_header(&mut self.0)) }
262 }
263
264 pub fn header_only(&self) -> bool {
268 self.0.header_only() != 0
269 }
270
271 pub fn method(&self) -> Method {
273 Method::from_ngx(self.0.method)
274 }
275
276 pub fn path(&self) -> &NgxStr {
278 unsafe { NgxStr::from_ngx_str(self.0.uri) }
279 }
280
281 pub fn unparsed_uri(&self) -> &NgxStr {
283 unsafe { NgxStr::from_ngx_str(self.0.unparsed_uri) }
284 }
285
286 pub fn output_filter(&mut self, body: &mut ngx_chain_t) -> Status {
293 unsafe { Status(ngx_http_output_filter(&mut self.0, body)) }
294 }
295
296 pub fn internal_redirect(&self, location: &str) -> Status {
298 assert!(!location.is_empty(), "uri location is empty");
299 let uri_ptr = unsafe { &mut ngx_str_t::from_str(self.0.pool, location) as *mut _ };
300
301 if location.starts_with('@') {
303 unsafe {
304 ngx_http_named_location((self as *const Request as *mut Request).cast(), uri_ptr);
305 }
306 } else {
307 unsafe {
308 ngx_http_internal_redirect(
309 (self as *const Request as *mut Request).cast(),
310 uri_ptr,
311 core::ptr::null_mut(),
312 );
313 }
314 }
315 Status::NGX_DONE
316 }
317
318 pub fn subrequest(
320 &self,
321 uri: &str,
322 module: &ngx_module_t,
323 post_callback: unsafe extern "C" fn(
324 *mut ngx_http_request_t,
325 *mut c_void,
326 ngx_int_t,
327 ) -> ngx_int_t,
328 ) -> Status {
329 let uri_ptr = unsafe { &mut ngx_str_t::from_str(self.0.pool, uri) as *mut _ };
330 let sub_ptr = self
333 .pool()
334 .alloc(core::mem::size_of::<ngx_http_post_subrequest_t>());
335
336 let post_subreq =
338 sub_ptr as *const ngx_http_post_subrequest_t as *mut ngx_http_post_subrequest_t;
339 unsafe {
340 (*post_subreq).handler = Some(post_callback);
341 (*post_subreq).data = self.get_module_ctx_ptr(module); }
344 let mut psr: *mut ngx_http_request_t = core::ptr::null_mut();
347 let r = unsafe {
348 ngx_http_subrequest(
349 (self as *const Request as *mut Request).cast(),
350 uri_ptr,
351 core::ptr::null_mut(),
352 &mut psr as *mut _,
353 sub_ptr as *mut _,
354 NGX_HTTP_SUBREQUEST_WAITED as _,
355 )
356 };
357
358 let sr = unsafe { &mut *psr };
361
362 sr.request_body =
367 self.pool()
368 .alloc(core::mem::size_of::<ngx_http_request_body_t>()) as *mut _;
369
370 if sr.request_body.is_null() {
371 return Status::NGX_ERROR;
372 }
373 sr.set_header_only(1 as _);
374 Status(r)
375 }
376
377 pub fn headers_in_iterator(&self) -> NgxListIterator<'_> {
380 unsafe { list_iterator(&self.0.headers_in.headers) }
381 }
382
383 pub fn headers_out_iterator(&self) -> NgxListIterator<'_> {
386 unsafe { list_iterator(&self.0.headers_out.headers) }
387 }
388}
389
390impl crate::http::HttpModuleConfExt for Request {
391 #[inline]
392 unsafe fn http_main_conf_unchecked<T>(&self, module: &ngx_module_t) -> Option<NonNull<T>> {
393 NonNull::new((*self.0.main_conf.add(module.ctx_index)).cast())
396 }
397
398 #[inline]
399 unsafe fn http_server_conf_unchecked<T>(&self, module: &ngx_module_t) -> Option<NonNull<T>> {
400 NonNull::new((*self.0.srv_conf.add(module.ctx_index)).cast())
403 }
404
405 #[inline]
406 unsafe fn http_location_conf_unchecked<T>(&self, module: &ngx_module_t) -> Option<NonNull<T>> {
407 NonNull::new((*self.0.loc_conf.add(module.ctx_index)).cast())
410 }
411}
412
413impl fmt::Debug for Request {
418 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419 f.debug_struct("Request")
420 .field("request_", &self.0)
421 .finish()
422 }
423}
424
425pub struct NgxListIterator<'a> {
429 part: Option<ListPart<'a>>,
430 i: ngx_uint_t,
431}
432struct ListPart<'a> {
433 raw: &'a ngx_list_part_t,
434 arr: &'a [ngx_table_elt_t],
435}
436impl<'a> From<&'a ngx_list_part_t> for ListPart<'a> {
437 fn from(raw: &'a ngx_list_part_t) -> Self {
438 let arr = if raw.nelts != 0 {
439 unsafe { slice::from_raw_parts(raw.elts.cast(), raw.nelts) }
440 } else {
441 &[]
442 };
443 Self { raw, arr }
444 }
445}
446
447pub unsafe fn list_iterator(list: &ngx_list_t) -> NgxListIterator<'_> {
453 NgxListIterator {
454 part: Some((&list.part).into()),
455 i: 0,
456 }
457}
458
459impl<'a> Iterator for NgxListIterator<'a> {
461 type Item = (&'a NgxStr, &'a NgxStr);
466
467 fn next(&mut self) -> Option<Self::Item> {
468 let part = self.part.as_mut()?;
469 if self.i >= part.arr.len() {
470 if let Some(next_part_raw) = unsafe { part.raw.next.as_ref() } {
471 *part = next_part_raw.into();
473 self.i = 0;
474 } else {
475 self.part = None;
476 return None;
477 }
478 }
479 let header = &part.arr[self.i];
480 self.i += 1;
481 unsafe {
482 Some((
483 NgxStr::from_ngx_str(header.key),
484 NgxStr::from_ngx_str(header.value),
485 ))
486 }
487 }
488}
489
490pub struct InvalidMethod {
492 _priv: (),
493}
494
495#[derive(Clone, PartialEq, Eq, Hash)]
497pub struct Method(MethodInner);
498
499impl Method {
500 pub const UNKNOWN: Method = Method(MethodInner::Unknown);
502
503 pub const GET: Method = Method(MethodInner::Get);
505
506 pub const HEAD: Method = Method(MethodInner::Head);
508
509 pub const POST: Method = Method(MethodInner::Post);
511
512 pub const PUT: Method = Method(MethodInner::Put);
514
515 pub const DELETE: Method = Method(MethodInner::Delete);
517
518 pub const MKCOL: Method = Method(MethodInner::Mkcol);
520
521 pub const COPY: Method = Method(MethodInner::Copy);
523
524 pub const MOVE: Method = Method(MethodInner::Move);
526
527 pub const OPTIONS: Method = Method(MethodInner::Options);
529
530 pub const PROPFIND: Method = Method(MethodInner::Propfind);
532
533 pub const PROPPATCH: Method = Method(MethodInner::Proppatch);
535
536 pub const LOCK: Method = Method(MethodInner::Lock);
538
539 pub const UNLOCK: Method = Method(MethodInner::Unlock);
541
542 pub const PATCH: Method = Method(MethodInner::Patch);
544
545 pub const TRACE: Method = Method(MethodInner::Trace);
547
548 pub const CONNECT: Method = Method(MethodInner::Connect);
550
551 #[inline]
553 pub fn as_str(&self) -> &str {
554 match self.0 {
555 MethodInner::Unknown => "UNKNOWN",
556 MethodInner::Get => "GET",
557 MethodInner::Head => "HEAD",
558 MethodInner::Post => "POST",
559 MethodInner::Put => "PUT",
560 MethodInner::Delete => "DELETE",
561 MethodInner::Mkcol => "MKCOL",
562 MethodInner::Copy => "COPY",
563 MethodInner::Move => "MOVE",
564 MethodInner::Options => "OPTIONS",
565 MethodInner::Propfind => "PROPFIND",
566 MethodInner::Proppatch => "PROPPATCH",
567 MethodInner::Lock => "LOCK",
568 MethodInner::Unlock => "UNLOCK",
569 MethodInner::Patch => "PATCH",
570 MethodInner::Trace => "TRACE",
571 MethodInner::Connect => "CONNECT",
572 }
573 }
574
575 fn from_bytes(_t: &[u8]) -> Result<Method, InvalidMethod> {
576 todo!()
577 }
578
579 fn from_ngx(t: ngx_uint_t) -> Method {
580 let t = t as _;
581 match t {
582 crate::ffi::NGX_HTTP_GET => Method(MethodInner::Get),
583 crate::ffi::NGX_HTTP_HEAD => Method(MethodInner::Head),
584 crate::ffi::NGX_HTTP_POST => Method(MethodInner::Post),
585 crate::ffi::NGX_HTTP_PUT => Method(MethodInner::Put),
586 crate::ffi::NGX_HTTP_DELETE => Method(MethodInner::Delete),
587 crate::ffi::NGX_HTTP_MKCOL => Method(MethodInner::Mkcol),
588 crate::ffi::NGX_HTTP_COPY => Method(MethodInner::Copy),
589 crate::ffi::NGX_HTTP_MOVE => Method(MethodInner::Move),
590 crate::ffi::NGX_HTTP_OPTIONS => Method(MethodInner::Options),
591 crate::ffi::NGX_HTTP_PROPFIND => Method(MethodInner::Propfind),
592 crate::ffi::NGX_HTTP_PROPPATCH => Method(MethodInner::Proppatch),
593 crate::ffi::NGX_HTTP_LOCK => Method(MethodInner::Lock),
594 crate::ffi::NGX_HTTP_UNLOCK => Method(MethodInner::Unlock),
595 crate::ffi::NGX_HTTP_PATCH => Method(MethodInner::Patch),
596 crate::ffi::NGX_HTTP_TRACE => Method(MethodInner::Trace),
597 #[cfg(nginx1_21_1)]
598 crate::ffi::NGX_HTTP_CONNECT => Method(MethodInner::Connect),
599 _ => Method(MethodInner::Unknown),
600 }
601 }
602}
603
604impl AsRef<str> for Method {
605 #[inline]
606 fn as_ref(&self) -> &str {
607 self.as_str()
608 }
609}
610
611impl<'a> PartialEq<&'a Method> for Method {
612 #[inline]
613 fn eq(&self, other: &&'a Method) -> bool {
614 self == *other
615 }
616}
617
618impl PartialEq<Method> for &Method {
619 #[inline]
620 fn eq(&self, other: &Method) -> bool {
621 *self == other
622 }
623}
624
625impl PartialEq<str> for Method {
626 #[inline]
627 fn eq(&self, other: &str) -> bool {
628 self.as_ref() == other
629 }
630}
631
632impl PartialEq<Method> for str {
633 #[inline]
634 fn eq(&self, other: &Method) -> bool {
635 self == other.as_ref()
636 }
637}
638
639impl<'a> PartialEq<&'a str> for Method {
640 #[inline]
641 fn eq(&self, other: &&'a str) -> bool {
642 self.as_ref() == *other
643 }
644}
645
646impl PartialEq<Method> for &str {
647 #[inline]
648 fn eq(&self, other: &Method) -> bool {
649 *self == other.as_ref()
650 }
651}
652
653impl fmt::Debug for Method {
654 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
655 f.write_str(self.as_ref())
656 }
657}
658
659impl fmt::Display for Method {
660 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
661 fmt.write_str(self.as_ref())
662 }
663}
664
665impl<'a> From<&'a Method> for Method {
666 #[inline]
667 fn from(t: &'a Method) -> Self {
668 t.clone()
669 }
670}
671
672impl<'a> TryFrom<&'a [u8]> for Method {
673 type Error = InvalidMethod;
674
675 #[inline]
676 fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
677 Method::from_bytes(t)
678 }
679}
680
681impl<'a> TryFrom<&'a str> for Method {
682 type Error = InvalidMethod;
683
684 #[inline]
685 fn try_from(t: &'a str) -> Result<Self, Self::Error> {
686 TryFrom::try_from(t.as_bytes())
687 }
688}
689
690impl FromStr for Method {
691 type Err = InvalidMethod;
692
693 #[inline]
694 fn from_str(t: &str) -> Result<Self, Self::Err> {
695 TryFrom::try_from(t)
696 }
697}
698
699impl InvalidMethod {
700 #[allow(dead_code)]
701 fn new() -> InvalidMethod {
702 InvalidMethod { _priv: () }
703 }
704}
705
706impl fmt::Debug for InvalidMethod {
707 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
708 f.debug_struct("InvalidMethod")
709 .finish()
711 }
712}
713
714impl fmt::Display for InvalidMethod {
715 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
716 f.write_str("invalid HTTP method")
717 }
718}
719
720impl error::Error for InvalidMethod {}
721
722#[derive(Clone, PartialEq, Eq, Hash)]
723enum MethodInner {
724 Unknown,
725 Get,
726 Head,
727 Post,
728 Put,
729 Delete,
730 Mkcol,
731 Copy,
732 Move,
733 Options,
734 Propfind,
735 Proppatch,
736 Lock,
737 Unlock,
738 Patch,
739 Trace,
740 Connect,
741}