Skip to content

Commit fe4190e

Browse files
committed
extract docs_rs_headers crate with custom headers:
1 parent 473de74 commit fe4190e

File tree

25 files changed

+145
-78
lines changed

25 files changed

+145
-78
lines changed

Cargo.lock

Lines changed: 21 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ exclude = [
2222

2323
[workspace.dependencies]
2424
anyhow = { version = "1.0.42", features = ["backtrace"]}
25+
axum-extra = { version = "0.12.0", features = ["typed-header", "routing", "middleware"] }
2526
askama = "0.14.0"
2627
bincode = "2.0.1"
2728
chrono = { version = "0.4.11", default-features = false, features = ["clock", "serde"] }
2829
derive_more = { version = "2.0.0", features = ["display", "deref", "from", "into", "from_str"] }
2930
http = "1.0.0"
31+
itertools = { version = "0.14.0" }
3032
opentelemetry = "0.31.0"
3133
opentelemetry-otlp = { version = "0.31.0", features = ["grpc-tonic", "metrics"] }
3234
opentelemetry-resource-detectors = "0.10.0"
@@ -43,6 +45,7 @@ url = { version = "2.1.1", features = ["serde"] }
4345

4446
[dependencies]
4547
docs_rs_env_vars = { path = "crates/lib/docs_rs_env_vars" }
48+
docs_rs_headers = { path = "crates/lib/docs_rs_headers" }
4649
docs_rs_logging = { path = "crates/lib/docs_rs_logging" }
4750
docs_rs_opentelemetry = { path = "crates/lib/docs_rs_opentelemetry" }
4851
docs_rs_types = { path = "crates/lib/docs_rs_types" }
@@ -85,7 +88,7 @@ dashmap = "6.0.0"
8588
zip = {version = "6.0.0", default-features = false, features = ["bzip2"]}
8689
bzip2 = "0.6.0"
8790
getrandom = "0.3.1"
88-
itertools = { version = "0.14.0" }
91+
itertools = { workspace = true }
8992
hex = "0.4.3"
9093
derive_more = { workspace = true }
9194
sysinfo = { version = "0.37.2", default-features = false, features = ["system"] }
@@ -111,7 +114,7 @@ bincode = { workspace = true }
111114
# axum dependencies
112115
async-trait = "0.1.83"
113116
axum = { version = "0.8.1", features = ["macros"] }
114-
axum-extra = { version = "0.12.0", features = ["typed-header", "routing", "middleware"] }
117+
axum-extra = { workspace = true }
115118
tower = "0.5.1"
116119
tower-http = { version = "0.6.0", features = ["fs", "trace", "timeout", "catch-panic"] }
117120
mime = "0.3.16"
@@ -129,11 +132,9 @@ chrono = { workspace = true }
129132

130133
# Transitive dependencies we don't use directly but need to have specific versions of
131134
constant_time_eq = "0.4.2"
132-
md5 = "0.8.0"
133-
134-
crates_io_validation = { path = "crates/lib/crates_io_validation" }
135135

136136
[dev-dependencies]
137+
docs_rs_headers = { path = "crates/lib/docs_rs_headers", features = ["testing"] }
137138
docs_rs_opentelemetry = { path = "crates/lib/docs_rs_opentelemetry", features = ["testing"] }
138139
docs_rs_types = { path = "crates/lib/docs_rs_types", features = ["testing"] }
139140
criterion = "0.8.0"
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[package]
2+
name = "docs_rs_headers"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
anyhow = { workspace = true }
8+
axum-core = "0.5.5"
9+
axum-extra = { workspace = true }
10+
askama = { workspace = true }
11+
derive_more = { workspace = true }
12+
docs_rs_types = { path = "../docs_rs_types" }
13+
docs_rs_uri = { path = "../docs_rs_uri" }
14+
http = { workspace = true }
15+
itertools = { workspace = true }
16+
md5 = "0.8.0"
17+
serde = { workspace = true }
18+
19+
[dev-dependencies]
20+
serde_json = { workspace = true }
21+
test-case = { workspace = true }
22+
tokio = { workspace = true }
23+
24+
[features]
25+
testing = []

src/web/headers/canonical_url.rs renamed to crates/lib/docs_rs_headers/src/canonical_url.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use anyhow::Result;
22
use askama::filters::HtmlSafe;
3-
use axum::http::uri::Uri;
43
use axum_extra::headers::{Header, HeaderName, HeaderValue};
54
use docs_rs_uri::EscapedURI;
5+
use http::uri::Uri;
66
use serde::Serialize;
77
use std::{fmt, ops::Deref};
88

@@ -96,9 +96,8 @@ impl HtmlSafe for CanonicalUrl {}
9696
#[cfg(test)]
9797
mod tests {
9898
use super::*;
99-
100-
use axum::http::HeaderMap;
10199
use axum_extra::headers::HeaderMapExt;
100+
use http::HeaderMap;
102101

103102
#[test]
104103
fn test_serialize_canonical_from_uri() {
Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,6 @@
1-
mod canonical_url;
2-
mod if_none_match;
3-
mod surrogate_key;
4-
51
use axum_extra::headers::ETag;
6-
use http::HeaderName;
72
use std::io::{self, Write};
83

9-
pub use canonical_url::CanonicalUrl;
10-
pub(crate) use if_none_match::IfNoneMatch;
11-
pub use surrogate_key::{SURROGATE_KEY, SurrogateKey, SurrogateKeys};
12-
13-
/// Fastly's Surrogate-Control header
14-
/// https://www.fastly.com/documentation/reference/http/http-headers/Surrogate-Control/
15-
pub static SURROGATE_CONTROL: HeaderName = HeaderName::from_static("surrogate-control");
16-
17-
/// X-Robots-Tag header for search engines.
18-
pub static X_ROBOTS_TAG: HeaderName = HeaderName::from_static("x-robots-tag");
19-
204
/// compute our etag header value from some content
215
///
226
/// Has to match the implementation in our build-script.
@@ -30,7 +14,8 @@ pub fn compute_etag<T: AsRef<[u8]>>(content: T) -> ETag {
3014
///
3115
/// Works the same way as the inner `md5::Context`,
3216
/// but produces an `ETag` when finalized.
33-
pub(crate) struct ETagComputer(md5::Context);
17+
#[derive(Default)]
18+
pub struct ETagComputer(md5::Context);
3419

3520
impl ETagComputer {
3621
pub fn new() -> Self {

src/web/headers/if_none_match.rs renamed to crates/lib/docs_rs_headers/src/if_none_match.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ mod header_impl {
2828
use derive_more::Deref;
2929

3030
#[derive(Debug, Clone, PartialEq, Deref)]
31-
pub(crate) struct IfNoneMatch(pub axum_extra::headers::IfNoneMatch);
31+
pub struct IfNoneMatch(pub axum_extra::headers::IfNoneMatch);
3232

3333
impl Header for IfNoneMatch {
3434
fn name() -> &'static http::HeaderName {
@@ -65,13 +65,13 @@ mod header_impl {
6565
}
6666
}
6767

68-
pub(crate) use header_impl::IfNoneMatch;
68+
pub use header_impl::IfNoneMatch;
6969

7070
#[cfg(test)]
7171
mod tests {
7272
use super::*;
7373
use anyhow::Result;
74-
use axum::{RequestPartsExt, body::Body, extract::Request};
74+
use axum_core::{RequestPartsExt as _, body::Body, extract::Request};
7575
use axum_extra::{
7676
TypedHeader,
7777
headers::{ETag, HeaderMapExt as _},
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
mod canonical_url;
2+
mod etag;
3+
mod if_none_match;
4+
mod surrogate_key;
5+
#[cfg(test)]
6+
mod testing;
7+
8+
pub use axum_extra::headers::ETag;
9+
pub use canonical_url::CanonicalUrl;
10+
pub use etag::{ETagComputer, compute_etag};
11+
pub use if_none_match::IfNoneMatch;
12+
pub use surrogate_key::{SURROGATE_KEY, SurrogateKey, SurrogateKeys};
13+
14+
use http::HeaderName;
15+
16+
/// Fastly's Surrogate-Control header
17+
/// https://www.fastly.com/documentation/reference/http/http-headers/Surrogate-Control/
18+
pub static SURROGATE_CONTROL: HeaderName = HeaderName::from_static("surrogate-control");
19+
20+
/// X-Robots-Tag header for search engines.
21+
pub static X_ROBOTS_TAG: HeaderName = HeaderName::from_static("x-robots-tag");

src/web/headers/surrogate_key.rs renamed to crates/lib/docs_rs_headers/src/surrogate_key.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ impl From<KrateName> for SurrogateKey {
9696
}
9797

9898
/// A full Fastly Surrogate-Key header, containing zero or more keys.
99-
#[derive(Debug, PartialEq, Clone)]
99+
#[derive(Debug, PartialEq, Clone, Default)]
100100
pub struct SurrogateKeys(BTreeSet<SurrogateKey>);
101101

102102
impl IntoIterator for SurrogateKeys {
@@ -239,7 +239,7 @@ impl SurrogateKeys {
239239
Ok(())
240240
}
241241

242-
#[cfg(test)]
242+
#[cfg(feature = "testing")]
243243
pub fn try_from_iter<I>(iter: I) -> anyhow::Result<Self>
244244
where
245245
I: IntoIterator<Item = SurrogateKey>,
@@ -258,7 +258,7 @@ impl SurrogateKeys {
258258
}
259259
}
260260

261-
#[cfg(test)]
261+
#[cfg(feature = "testing")]
262262
impl FromStr for SurrogateKeys {
263263
type Err = anyhow::Error;
264264

@@ -274,7 +274,7 @@ impl FromStr for SurrogateKeys {
274274
#[cfg(test)]
275275
mod tests {
276276
use super::*;
277-
use crate::test::headers::{test_typed_decode, test_typed_encode};
277+
use crate::testing::{test_typed_decode, test_typed_encode};
278278
use std::ops::RangeInclusive;
279279
use test_case::test_case;
280280

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use axum_extra::headers::{self, Header, HeaderMapExt};
2+
use http::{HeaderMap, HeaderValue};
3+
4+
pub(crate) fn test_typed_decode<H, V>(value: V) -> Result<Option<H>, headers::Error>
5+
where
6+
H: Header,
7+
V: TryInto<HeaderValue>,
8+
<V as TryInto<http::HeaderValue>>::Error: std::fmt::Debug,
9+
{
10+
let mut map = HeaderMap::new();
11+
map.append(
12+
H::name(),
13+
// this `.try_into` only generates the `HeaderValue` items.
14+
value.try_into().unwrap(),
15+
);
16+
// parsing errors from the typed header end up here.
17+
map.typed_try_get()
18+
}
19+
20+
pub(crate) fn test_typed_encode<H: Header>(header: H) -> HeaderValue {
21+
let mut map = HeaderMap::new();
22+
map.typed_insert(header);
23+
map.get(H::name()).cloned().unwrap()
24+
}

src/cdn/fastly.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
use crate::{
2-
APP_USER_AGENT,
3-
cdn::CdnMetrics,
4-
config::Config,
5-
web::headers::{SURROGATE_KEY, SurrogateKey, SurrogateKeys},
6-
};
1+
use crate::{APP_USER_AGENT, cdn::CdnMetrics, config::Config};
72
use anyhow::{Result, anyhow, bail};
83
use chrono::{DateTime, TimeZone as _, Utc};
4+
use docs_rs_headers::{SURROGATE_KEY, SurrogateKey, SurrogateKeys};
95
use http::{
106
HeaderMap, HeaderName, HeaderValue,
117
header::{ACCEPT, USER_AGENT},

0 commit comments

Comments
 (0)