ngx/http/
request.rs

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/// Define a static request handler.
13///
14/// Handlers are expected to take a single [`Request`] argument and return a [`Status`].
15#[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/// Define a static post subrequest handler.
27///
28/// Handlers are expected to take a single [`Request`] argument and return a [`Status`].
29#[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/// Define a static variable setter.
43///
44/// The set handler allows setting the property referenced by the variable.
45/// The set handler expects a [`Request`], [`mut ngx_variable_value_t`], and a [`usize`].
46/// Variables: <https://nginx.org/en/docs/dev/development_guide.html#http_variables>
47#[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/// Define a static variable evaluator.
65///
66/// The get handler is responsible for evaluating a variable in the context of a specific request.
67/// Variable evaluators accept a [`Request`] input argument and two output
68/// arguments: [`ngx_variable_value_t`] and [`usize`].
69/// Variables: <https://nginx.org/en/docs/dev/development_guide.html#http_variables>
70#[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/// Wrapper struct for an [`ngx_http_request_t`] pointer, providing methods for working with HTTP
89/// requests.
90///
91/// See <https://nginx.org/en/docs/dev/development_guide.html#http_request>
92#[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    /// Create a [`Request`] from an [`ngx_http_request_t`].
121    ///
122    /// # Safety
123    ///
124    /// The caller has provided a valid non-null pointer to a valid `ngx_http_request_t`
125    /// which shares the same representation as `Request`.
126    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    /// Is this the main request (as opposed to a subrequest)?
131    pub fn is_main(&self) -> bool {
132        let main = self.0.main.cast();
133        core::ptr::eq(self, main)
134    }
135
136    /// Request pool.
137    pub fn pool(&self) -> Pool {
138        // SAFETY: This request is allocated from `pool`, thus must be a valid pool.
139        unsafe { Pool::from_ngx_pool(self.0.pool) }
140    }
141
142    /// Returns the result as an `Option` if it exists, otherwise `None`.
143    ///
144    /// The option wraps an ngx_http_upstream_t instance, it will be none when the underlying NGINX
145    /// request does not have a pointer to a [`ngx_http_upstream_t`] upstream structure.
146    ///
147    /// [`ngx_http_upstream_t`] is best described in
148    /// <https://nginx.org/en/docs/dev/development_guide.html#http_load_balancing>
149    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    /// Pointer to a [`ngx_connection_t`] client connection object.
157    ///
158    /// [`ngx_connection_t`]: https://nginx.org/en/docs/dev/development_guide.html#connection
159    pub fn connection(&self) -> *mut ngx_connection_t {
160        self.0.connection
161    }
162
163    /// Pointer to a [`ngx_log_t`].
164    ///
165    /// [`ngx_log_t`]: https://nginx.org/en/docs/dev/development_guide.html#logging
166    pub fn log(&self) -> *mut ngx_log_t {
167        unsafe { (*self.connection()).log }
168    }
169
170    /// Get Module context pointer
171    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    /// Get Module context
176    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        // SAFETY: ctx is either NULL or allocated with ngx_p(c)alloc and
179        // explicitly initialized by the module
180        unsafe { ctx.as_ref() }
181    }
182
183    /// Sets the value as the module's context.
184    ///
185    /// See <https://nginx.org/en/docs/dev/development_guide.html#http_request>
186    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    /// Get the value of a [complex value].
193    ///
194    /// [complex value]: https://nginx.org/en/docs/dev/development_guide.html#http_complex_values
195    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        // SAFETY: `ngx_http_complex_value` does not mutate `r` or `val` and guarentees that
199        // a valid Nginx string is stored in `value` if it successfully returns.
200        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    /// Discard (read and ignore) the [request body].
210    ///
211    /// [request body]: https://nginx.org/en/docs/dev/development_guide.html#http_request_body
212    pub fn discard_request_body(&mut self) -> Status {
213        unsafe { Status(ngx_http_discard_request_body(&mut self.0)) }
214    }
215
216    /// Client HTTP [User-Agent].
217    ///
218    /// [User-Agent]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent
219    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    /// Set HTTP status of response.
228    pub fn set_status(&mut self, status: HTTPStatus) {
229        self.0.headers_out.status = status.into();
230    }
231
232    /// Add header to the `headers_in` object.
233    ///
234    /// See <https://nginx.org/en/docs/dev/development_guide.html#http_request>
235    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    /// Add header to the `headers_out` object.
242    ///
243    /// See <https://nginx.org/en/docs/dev/development_guide.html#http_request>
244    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    /// Set response body [Content-Length].
251    ///
252    /// [Content-Length]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length
253    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    /// Send the output header.
258    ///
259    /// Do not call this function until all output headers are set.
260    pub fn send_header(&mut self) -> Status {
261        unsafe { Status(ngx_http_send_header(&mut self.0)) }
262    }
263
264    /// Flag indicating that the output does not require a body.
265    ///
266    /// For example, this flag is used by `HTTP HEAD` requests.
267    pub fn header_only(&self) -> bool {
268        self.0.header_only() != 0
269    }
270
271    /// request method
272    pub fn method(&self) -> Method {
273        Method::from_ngx(self.0.method)
274    }
275
276    /// path part of request only
277    pub fn path(&self) -> &NgxStr {
278        unsafe { NgxStr::from_ngx_str(self.0.uri) }
279    }
280
281    /// full uri - containing path and args
282    pub fn unparsed_uri(&self) -> &NgxStr {
283        unsafe { NgxStr::from_ngx_str(self.0.unparsed_uri) }
284    }
285
286    /// Send the [response body].
287    ///
288    /// This function can be called multiple times.
289    /// Set the `last_buf` flag in the last body buffer.
290    ///
291    /// [response body]: https://nginx.org/en/docs/dev/development_guide.html#http_request_body
292    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    /// Perform internal redirect to a location
297    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        // FIXME: check status of ngx_http_named_location or ngx_http_internal_redirect
302        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    /// Send a subrequest
319    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        // -------------
331        // allocate memory and set values for ngx_http_post_subrequest_t
332        let sub_ptr = self
333            .pool()
334            .alloc(core::mem::size_of::<ngx_http_post_subrequest_t>());
335
336        // assert!(sub_ptr.is_null());
337        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); // WARN: safety! ensure that ctx
342                                                                   // is already set
343        }
344        // -------------
345
346        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        // previously call of ngx_http_subrequest() would ensure that the pointer is not null
359        // anymore
360        let sr = unsafe { &mut *psr };
361
362        /*
363         * allocate fake request body to avoid attempts to read it and to make
364         * sure real body file (if already read) won't be closed by upstream
365         */
366        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    /// Iterate over headers_in
378    /// each header item is (&str, &str) (borrowed)
379    pub fn headers_in_iterator(&self) -> NgxListIterator<'_> {
380        unsafe { list_iterator(&self.0.headers_in.headers) }
381    }
382
383    /// Iterate over headers_out
384    /// each header item is (&str, &str) (borrowed)
385    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        // SAFETY: main_conf[module.ctx_index] is either NULL or allocated with ngx_p(c)alloc and
394        // explicitly initialized by the module
395        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        // SAFETY: srv_conf[module.ctx_index] is either NULL or allocated with ngx_p(c)alloc and
401        // explicitly initialized by the module
402        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        // SAFETY: loc_conf[module.ctx_index] is either NULL or allocated with ngx_p(c)alloc and
408        // explicitly initialized by the module
409        NonNull::new((*self.0.loc_conf.add(module.ctx_index)).cast())
410    }
411}
412
413// trait OnSubRequestDone {
414
415// }
416
417impl 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
425/// Iterator for [`ngx_list_t`] types.
426///
427/// Implementes the core::iter::Iterator trait.
428pub 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
447/// Creates new HTTP header iterator
448///
449/// # Safety
450///
451/// The caller has provided a valid [`ngx_str_t`] which can be dereferenced validly.
452pub unsafe fn list_iterator(list: &ngx_list_t) -> NgxListIterator<'_> {
453    NgxListIterator {
454        part: Some((&list.part).into()),
455        i: 0,
456    }
457}
458
459// iterator for ngx_list_t
460impl<'a> Iterator for NgxListIterator<'a> {
461    // TODO: try to use struct instead of &str pair
462    // something like pub struct Header(ngx_table_elt_t);
463    // then header would have key and value
464
465    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                // loop back
472                *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
490/// A possible error value when converting `Method`
491pub struct InvalidMethod {
492    _priv: (),
493}
494
495/// Request method verb
496#[derive(Clone, PartialEq, Eq, Hash)]
497pub struct Method(MethodInner);
498
499impl Method {
500    /// UNKNOWN
501    pub const UNKNOWN: Method = Method(MethodInner::Unknown);
502
503    /// GET
504    pub const GET: Method = Method(MethodInner::Get);
505
506    /// HEAD
507    pub const HEAD: Method = Method(MethodInner::Head);
508
509    /// POST
510    pub const POST: Method = Method(MethodInner::Post);
511
512    /// PUT
513    pub const PUT: Method = Method(MethodInner::Put);
514
515    /// DELETE
516    pub const DELETE: Method = Method(MethodInner::Delete);
517
518    /// MKCOL
519    pub const MKCOL: Method = Method(MethodInner::Mkcol);
520
521    /// COPY
522    pub const COPY: Method = Method(MethodInner::Copy);
523
524    /// MOVE
525    pub const MOVE: Method = Method(MethodInner::Move);
526
527    /// OPTIONS
528    pub const OPTIONS: Method = Method(MethodInner::Options);
529
530    /// PROPFIND
531    pub const PROPFIND: Method = Method(MethodInner::Propfind);
532
533    /// PROPPATCH
534    pub const PROPPATCH: Method = Method(MethodInner::Proppatch);
535
536    /// LOCK
537    pub const LOCK: Method = Method(MethodInner::Lock);
538
539    /// UNLOCK
540    pub const UNLOCK: Method = Method(MethodInner::Unlock);
541
542    /// PATCH
543    pub const PATCH: Method = Method(MethodInner::Patch);
544
545    /// TRACE
546    pub const TRACE: Method = Method(MethodInner::Trace);
547
548    /// CONNECT
549    pub const CONNECT: Method = Method(MethodInner::Connect);
550
551    /// Convert a Method to a &str.
552    #[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            // skip _priv noise
710            .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}