defect_http/
user_agent.rs1use std::task::{Context, Poll};
12
13use http::HeaderValue;
14use http::header::USER_AGENT;
15use tower::{Layer, Service};
16
17pub fn default_user_agent() -> HeaderValue {
25 let pkg = env!("CARGO_PKG_VERSION");
26 let sha = env!("DEFECT_HTTP_GIT_SHA");
27 let raw = format!("defect-http/{pkg} ({sha})");
28 HeaderValue::from_str(&raw).unwrap_or_else(|_| HeaderValue::from_static("defect-http"))
29}
30
31#[derive(Debug, Clone)]
32pub(crate) struct UserAgentLayer {
33 value: HeaderValue,
34}
35
36impl UserAgentLayer {
37 pub(crate) fn new(value: HeaderValue) -> Self {
38 Self { value }
39 }
40}
41
42impl<S> Layer<S> for UserAgentLayer {
43 type Service = UserAgent<S>;
44
45 fn layer(&self, inner: S) -> Self::Service {
46 UserAgent {
47 inner,
48 value: self.value.clone(),
49 }
50 }
51}
52
53#[derive(Debug, Clone)]
54pub(crate) struct UserAgent<S> {
55 inner: S,
56 value: HeaderValue,
57}
58
59impl<S, B> Service<http::Request<B>> for UserAgent<S>
60where
61 S: Service<http::Request<B>>,
62{
63 type Response = S::Response;
64 type Error = S::Error;
65 type Future = S::Future;
66
67 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
68 self.inner.poll_ready(cx)
69 }
70
71 fn call(&mut self, mut req: http::Request<B>) -> Self::Future {
72 req.headers_mut()
73 .entry(USER_AGENT)
74 .or_insert_with(|| self.value.clone());
75 self.inner.call(req)
76 }
77}
78
79#[cfg(test)]
80mod tests;