use std::fmt;
use serve_net::{ClientInfo, Envelope, HttpRequest, Method, Scheme};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct RequestId {
connection: u64,
seq: u32,
}
impl RequestId {
pub(crate) fn of(env: &Envelope) -> Self {
Self {
connection: env.connection().get(),
seq: env.seq().get(),
}
}
#[must_use]
pub const fn connection(&self) -> u64 {
self.connection
}
#[must_use]
pub const fn seq(&self) -> u32 {
self.seq
}
}
impl fmt::Display for RequestId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:x}-{}", self.connection, self.seq)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Ambiguous;
impl fmt::Display for Ambiguous {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("the cookie appears more than once")
}
}
impl std::error::Error for Ambiguous {}
#[derive(Clone, Copy)]
pub struct Request<'r> {
pub(crate) http: &'r HttpRequest<'r>,
pub(crate) env: &'r Envelope,
pub(crate) path: &'r str,
pub(crate) host: &'r str,
pub(crate) route: Option<&'r str>,
}
impl<'r> Request<'r> {
#[must_use]
pub fn method(&self) -> Method {
self.http.method()
}
#[must_use]
pub fn path(&self) -> &'r str {
self.path
}
#[must_use]
pub fn query(&self) -> Option<&'r str> {
self.http.query()
}
#[must_use]
pub fn host(&self) -> &'r str {
self.host
}
#[must_use]
pub fn header(&self, name: &str) -> Option<&'r [u8]> {
self.http.header(name)
}
#[must_use]
pub fn header_str(&self, name: &str) -> Option<&'r str> {
self.http
.header(name)
.and_then(|v| core::str::from_utf8(v).ok())
}
pub fn cookie(&self, name: &str) -> Result<Option<&'r str>, Ambiguous> {
let mut fields = self.http.head().header_all("cookie");
let Some(first) = fields.next() else {
return Ok(None);
};
if fields.next().is_some() {
return Err(Ambiguous);
}
cookie_net::get_unique(first, name).map_err(|_| Ambiguous)
}
#[must_use]
pub fn client(&self) -> &'r ClientInfo {
self.env.client()
}
#[must_use]
pub fn scheme(&self) -> Scheme {
self.env.client().scheme()
}
#[must_use]
pub fn route(&self) -> Option<&'r str> {
self.route
}
#[must_use]
pub fn id(&self) -> RequestId {
RequestId::of(self.env)
}
#[must_use]
pub fn envelope(&self) -> &'r Envelope {
self.env
}
#[must_use]
pub fn raw(&self) -> &'r HttpRequest<'r> {
self.http
}
}
impl fmt::Debug for Request<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Request")
.field("method", &self.method())
.field("path", &self.path)
.field("route", &self.route)
.field("id", &self.id())
.finish_non_exhaustive()
}
}