I'm currently working with the http_types
crate to provide additional functionality on HTTP headers that currently has not been implemented yet to provide parsing for HTTP Authorization
header data.
The data model looks like this:
-
struct Headers
, which owns aHashMap<HeaderName, HeaderValues>
.-
HeaderValues
which owns aVec<HeaderValue>
-
HeaderValue
which owns aString
-
-
I'm not exactly sure if what I'm looking to do is possible from an API design perspective because of lifetimes, but I'm trying to build a trait which offers a zero-copy method for parsing the data in an Authorization
header.
Here are my data-types for the structured data I will return from my trait method:
pub enum AuthKind<'a> {
Basic,
Unknown(&'a str),
}
pub struct Authorization<'a> {
pub kind: Option<AuthKind<'a>>,
pub data: &'a str,
}
Both of these references are to the underlying HeaderValue
string data and are simple ranges over the header value string.
The trait that I'm trying to build looks like this:
pub trait HeadersExt<'a> {
fn authorization(&self) -> Option<Authorization<'a>>;
}
I'll be implementing this trait for Headers
like this:
impl<'a> HeadersExt<'a> for Headers {
fn authorization(&self) -> Option<Authorization<'a>> {
unimplemented!()
}
}
A dummy implementation I built looks like this:
impl<'a> HeadersExt<'a> for Headers {
fn authorization(&self) -> Option<Authorization<'a>> {
let header_values: &'a HeaderValues = self.get("Authorization").unwrap();
let header_value: &'a HeaderValue = header_values.last();
Some(Authorization {
kind: Some(AuthKind::Basic),
data: header_value.as_str(),
})
}
}
Unfortunately, this does not compile, as it seems pretty clear that rustc
does not know how long things should live:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/utils.rs:31:52
|
31 | let header_values: &'a HeaderValues = self.get("Authorization").unwrap();
| ^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 30:5...
--> src/utils.rs:30:5
|
30 | / fn authorization(&self) -> Option<Authorization<'a>> {
31 | | let header_values: &'a HeaderValues = self.get("Authorization").unwrap();
32 | | let header_value: &'a HeaderValue = header_values.last();
33 | |
... |
37 | | })
38 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/utils.rs:31:47
|
31 | let header_values: &'a HeaderValues = self.get("Authorization").unwrap();
| ^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 29:6...
--> src/utils.rs:29:6
|
29 | impl<'a> HeadersExt<'a> for Headers {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/utils.rs:31:47
|
31 | let header_values: &'a HeaderValues = self.get("Authorization").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Is what I'm trying possible, and if so, how do I tell the compiler that the lifetime of Authorization
is the same as the lifetime of the &str
within the &HeaderValue
within the &HeaderValues
? I haven't done any super advanced lifetime work yet.