ngx/http/
request.rs

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/// Define a static request handler.
12///
13/// Handlers are expected to take a single [`Request`] argument and return a [`Status`].
14#[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/// Define a static post subrequest handler.
26///
27/// Handlers are expected to take a single [`Request`] argument and return a [`Status`].
28#[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/// Define a static variable setter.
42///
43/// The set handler allows setting the property referenced by the variable.
44/// The set handler expects a [`Request`], [`mut ngx_variable_value_t`], and a [`usize`].
45/// Variables: <https://nginx.org/en/docs/dev/development_guide.html#http_variables>
46#[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/// Define a static variable evaluator.
64///
65/// The get handler is responsible for evaluating a variable in the context of a specific request.
66/// Variable evaluators accept a [`Request`] input argument and two output
67/// arguments: [`ngx_variable_value_t`] and [`usize`].
68/// Variables: <https://nginx.org/en/docs/dev/development_guide.html#http_variables>
69#[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/// Wrapper struct for an [`ngx_http_request_t`] pointer, providing methods for working with HTTP requests.
88///
89/// See <https://nginx.org/en/docs/dev/development_guide.html#http_request>
90#[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    /// Create a [`Request`] from an [`ngx_http_request_t`].
119    ///
120    /// # Safety
121    ///
122    /// The caller has provided a valid non-null pointer to a valid `ngx_http_request_t`
123    /// which shares the same representation as `Request`.
124    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    /// Is this the main request (as opposed to a subrequest)?
129    pub fn is_main(&self) -> bool {
130        let main = self.0.main.cast();
131        core::ptr::eq(self, main)
132    }
133
134    /// Request pool.
135    pub fn pool(&self) -> Pool {
136        // SAFETY: This request is allocated from `pool`, thus must be a valid pool.
137        unsafe { Pool::from_ngx_pool(self.0.pool) }
138    }
139
140    /// Returns the result as an `Option` if it exists, otherwise `None`.
141    ///
142    /// The option wraps an ngx_http_upstream_t instance, it will be none when the underlying NGINX request
143    /// does not have a pointer to a [`ngx_http_upstream_t`] upstream structure.
144    ///
145    /// [`ngx_http_upstream_t`] is best described in
146    /// <https://nginx.org/en/docs/dev/development_guide.html#http_load_balancing>
147    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    /// Pointer to a [`ngx_connection_t`] client connection object.
155    ///
156    /// [`ngx_connection_t`]: https://nginx.org/en/docs/dev/development_guide.html#connection
157    pub fn connection(&self) -> *mut ngx_connection_t {
158        self.0.connection
159    }
160
161    /// Pointer to a [`ngx_log_t`].
162    ///
163    /// [`ngx_log_t`]: https://nginx.org/en/docs/dev/development_guide.html#logging
164    pub fn log(&self) -> *mut ngx_log_t {
165        unsafe { (*self.connection()).log }
166    }
167
168    /// Get Module context pointer
169    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    /// Get Module context
174    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        // SAFETY: ctx is either NULL or allocated with ngx_p(c)alloc and
177        // explicitly initialized by the module
178        unsafe { ctx.as_ref() }
179    }
180
181    /// Sets the value as the module's context.
182    ///
183    /// See <https://nginx.org/en/docs/dev/development_guide.html#http_request>
184    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    /// Get the value of a [complex value].
191    ///
192    /// [complex value]: https://nginx.org/en/docs/dev/development_guide.html#http_complex_values
193    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        // SAFETY: `ngx_http_complex_value` does not mutate `r` or `val` and guarentees that
197        // a valid Nginx string is stored in `value` if it successfully returns.
198        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    /// Discard (read and ignore) the [request body].
208    ///
209    /// [request body]: https://nginx.org/en/docs/dev/development_guide.html#http_request_body
210    pub fn discard_request_body(&mut self) -> Status {
211        unsafe { Status(ngx_http_discard_request_body(&mut self.0)) }
212    }
213
214    /// Client HTTP [User-Agent].
215    ///
216    /// [User-Agent]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent
217    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    /// Set HTTP status of response.
226    pub fn set_status(&mut self, status: HTTPStatus) {
227        self.0.headers_out.status = status.into();
228    }
229
230    /// Add header to the `headers_in` object.
231    ///
232    /// See <https://nginx.org/en/docs/dev/development_guide.html#http_request>
233    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    /// Add header to the `headers_out` object.
239    ///
240    /// See <https://nginx.org/en/docs/dev/development_guide.html#http_request>
241    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    /// Set response body [Content-Length].
247    ///
248    /// [Content-Length]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length
249    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    /// Send the output header.
254    ///
255    /// Do not call this function until all output headers are set.
256    pub fn send_header(&mut self) -> Status {
257        unsafe { Status(ngx_http_send_header(&mut self.0)) }
258    }
259
260    /// Flag indicating that the output does not require a body.
261    ///
262    /// For example, this flag is used by `HTTP HEAD` requests.
263    pub fn header_only(&self) -> bool {
264        self.0.header_only() != 0
265    }
266
267    /// request method
268    pub fn method(&self) -> Method {
269        Method::from_ngx(self.0.method)
270    }
271
272    /// path part of request only
273    pub fn path(&self) -> &NgxStr {
274        unsafe { NgxStr::from_ngx_str(self.0.uri) }
275    }
276
277    /// full uri - containing path and args
278    pub fn unparsed_uri(&self) -> &NgxStr {
279        unsafe { NgxStr::from_ngx_str(self.0.unparsed_uri) }
280    }
281
282    /// Send the [response body].
283    ///
284    /// This function can be called multiple times.
285    /// Set the `last_buf` flag in the last body buffer.
286    ///
287    /// [response body]: https://nginx.org/en/docs/dev/development_guide.html#http_request_body
288    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    /// Perform internal redirect to a location
293    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        // FIXME: check status of ngx_http_named_location or ngx_http_internal_redirect
298        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    /// Send a subrequest
315    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        // -------------
323        // allocate memory and set values for ngx_http_post_subrequest_t
324        let sub_ptr = self.pool().alloc(core::mem::size_of::<ngx_http_post_subrequest_t>());
325
326        // assert!(sub_ptr.is_null());
327        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); // WARN: safety! ensure that ctx is already set
331        }
332        // -------------
333
334        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        // previously call of ngx_http_subrequest() would ensure that the pointer is not null anymore
347        let sr = unsafe { &mut *psr };
348
349        /*
350         * allocate fake request body to avoid attempts to read it and to make
351         * sure real body file (if already read) won't be closed by upstream
352         */
353        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    /// Iterate over headers_in
363    /// each header item is (&str, &str) (borrowed)
364    pub fn headers_in_iterator(&self) -> NgxListIterator {
365        unsafe { list_iterator(&self.0.headers_in.headers) }
366    }
367
368    /// Iterate over headers_out
369    /// each header item is (&str, &str) (borrowed)
370    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        // SAFETY: main_conf[module.ctx_index] is either NULL or allocated with ngx_p(c)alloc and
379        // explicitly initialized by the module
380        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        // SAFETY: srv_conf[module.ctx_index] is either NULL or allocated with ngx_p(c)alloc and
386        // explicitly initialized by the module
387        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        // SAFETY: loc_conf[module.ctx_index] is either NULL or allocated with ngx_p(c)alloc and
393        // explicitly initialized by the module
394        NonNull::new((*self.0.loc_conf.add(module.ctx_index)).cast())
395    }
396}
397
398// trait OnSubRequestDone {
399
400// }
401
402impl 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
408/// Iterator for [`ngx_list_t`] types.
409///
410/// Implementes the core::iter::Iterator trait.
411pub 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
430/// Creates new HTTP header iterator
431///
432/// # Safety
433///
434/// The caller has provided a valid [`ngx_str_t`] which can be dereferenced validly.
435pub unsafe fn list_iterator(list: &ngx_list_t) -> NgxListIterator {
436    NgxListIterator {
437        part: Some((&list.part).into()),
438        i: 0,
439    }
440}
441
442// iterator for ngx_list_t
443impl<'a> Iterator for NgxListIterator<'a> {
444    // TODO: try to use struct instead of &str pair
445    // something like pub struct Header(ngx_table_elt_t);
446    // then header would have key and value
447
448    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                // loop back
455                *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
468/// A possible error value when converting `Method`
469pub struct InvalidMethod {
470    _priv: (),
471}
472
473/// Request method verb
474#[derive(Clone, PartialEq, Eq, Hash)]
475pub struct Method(MethodInner);
476
477impl Method {
478    /// UNKNOWN
479    pub const UNKNOWN: Method = Method(MethodInner::Unknown);
480
481    /// GET
482    pub const GET: Method = Method(MethodInner::Get);
483
484    /// HEAD
485    pub const HEAD: Method = Method(MethodInner::Head);
486
487    /// POST
488    pub const POST: Method = Method(MethodInner::Post);
489
490    /// PUT
491    pub const PUT: Method = Method(MethodInner::Put);
492
493    /// DELETE
494    pub const DELETE: Method = Method(MethodInner::Delete);
495
496    /// MKCOL
497    pub const MKCOL: Method = Method(MethodInner::Mkcol);
498
499    /// COPY
500    pub const COPY: Method = Method(MethodInner::Copy);
501
502    /// MOVE
503    pub const MOVE: Method = Method(MethodInner::Move);
504
505    /// OPTIONS
506    pub const OPTIONS: Method = Method(MethodInner::Options);
507
508    /// PROPFIND
509    pub const PROPFIND: Method = Method(MethodInner::Propfind);
510
511    /// PROPPATCH
512    pub const PROPPATCH: Method = Method(MethodInner::Proppatch);
513
514    /// LOCK
515    pub const LOCK: Method = Method(MethodInner::Lock);
516
517    /// UNLOCK
518    pub const UNLOCK: Method = Method(MethodInner::Unlock);
519
520    /// PATCH
521    pub const PATCH: Method = Method(MethodInner::Patch);
522
523    /// TRACE
524    pub const TRACE: Method = Method(MethodInner::Trace);
525
526    /// CONNECT
527    pub const CONNECT: Method = Method(MethodInner::Connect);
528
529    /// Convert a Method to a &str.
530    #[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            // skip _priv noise
688            .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}