Skip to content

Commit 3712958

Browse files
committed
extract EscapedURI into subcrate
1 parent cb9dbe4 commit 3712958

File tree

13 files changed

+71
-47
lines changed

13 files changed

+71
-47
lines changed

Cargo.lock

Lines changed: 14 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: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ exclude = [
2222

2323
[workspace.dependencies]
2424
anyhow = { version = "1.0.42", features = ["backtrace"]}
25+
askama = "0.14.0"
2526
bincode = "2.0.1"
2627
chrono = { version = "0.4.11", default-features = false, features = ["clock", "serde"] }
2728
derive_more = { version = "2.0.0", features = ["display", "deref", "from", "into", "from_str"] }
29+
http = "1.0.0"
2830
opentelemetry = "0.31.0"
2931
opentelemetry-otlp = { version = "0.31.0", features = ["grpc-tonic", "metrics"] }
3032
opentelemetry-resource-detectors = "0.10.0"
@@ -44,6 +46,7 @@ docs_rs_env_vars = { path = "crates/lib/docs_rs_env_vars" }
4446
docs_rs_logging = { path = "crates/lib/docs_rs_logging" }
4547
docs_rs_opentelemetry = { path = "crates/lib/docs_rs_opentelemetry" }
4648
docs_rs_types = { path = "crates/lib/docs_rs_types" }
49+
docs_rs_uri = { path = "crates/lib/docs_rs_uri" }
4750
docs_rs_utils = { path = "crates/lib/docs_rs_utils" }
4851
sentry = { workspace = true }
4952
log = "0.4"
@@ -98,7 +101,7 @@ async-stream = "0.3.5"
98101
aws-config = { version = "1.0.0", default-features = false, features = ["rt-tokio", "default-https-client"] }
99102
aws-sdk-s3 = "1.3.0"
100103
aws-smithy-types-convert = { version = "0.60.0", features = ["convert-chrono"] }
101-
http = "1.0.0"
104+
http = { workspace = true }
102105

103106
# Data serialization and deserialization
104107
serde = { workspace = true }
@@ -112,13 +115,12 @@ axum-extra = { version = "0.12.0", features = ["typed-header", "routing", "middl
112115
tower = "0.5.1"
113116
tower-http = { version = "0.6.0", features = ["fs", "trace", "timeout", "catch-panic"] }
114117
mime = "0.3.16"
115-
percent-encoding = "2.2.0"
116118

117119
tempfile = "3.1.0"
118120
fn-error-context = "0.2.0"
119121

120122
# Templating
121-
askama = "0.14.0"
123+
askama = { workspace = true }
122124
walkdir = "2"
123125
phf = "0.13.1"
124126

crates/lib/docs_rs_uri/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "docs_rs_uri"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
anyhow = { workspace = true }
8+
askama = { workspace = true }
9+
bincode = { workspace = true }
10+
http = { workspace = true }
11+
percent-encoding = "2.2.0"
12+
url = { workspace = true }
13+
14+
[dev-dependencies]
15+
test-case = { workspace = true }
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use std::borrow::Cow;
2+
3+
use anyhow::Result;
4+
use percent_encoding::{AsciiSet, CONTROLS, utf8_percent_encode};
5+
6+
// from https://github.com/servo/rust-url/blob/master/url/src/parser.rs
7+
// and https://github.com/tokio-rs/axum/blob/main/axum-extra/src/lib.rs
8+
const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');
9+
const PATH: &AsciiSet = &FRAGMENT.add(b'#').add(b'?').add(b'{').add(b'}');
10+
11+
pub fn encode_url_path(path: &str) -> String {
12+
utf8_percent_encode(path, PATH).to_string()
13+
}
14+
15+
pub fn url_decode<'a>(input: &'a str) -> Result<Cow<'a, str>> {
16+
Ok(percent_encoding::percent_decode(input.as_bytes()).decode_utf8()?)
17+
}
Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::web::{encode_url_path, url_decode};
1+
use crate::encode::{encode_url_path, url_decode};
22
use askama::filters::HtmlSafe;
33
use http::{Uri, uri::PathAndQuery};
44
use std::{borrow::Borrow, fmt::Display, iter, str::FromStr};
@@ -200,7 +200,7 @@ impl EscapedURI {
200200
self.uri
201201
}
202202

203-
pub(crate) fn with_fragment(mut self, fragment: impl AsRef<str>) -> Self {
203+
pub fn with_fragment(mut self, fragment: impl AsRef<str>) -> Self {
204204
self.fragment = Some(encode_url_path(fragment.as_ref()));
205205
self
206206
}
@@ -298,8 +298,6 @@ impl PartialEq<str> for EscapedURI {
298298
#[cfg(test)]
299299
mod tests {
300300
use super::EscapedURI;
301-
use crate::web::{cache::CachePolicy, error::AxumNope};
302-
use axum::response::IntoResponse as _;
303301
use http::Uri;
304302
use test_case::test_case;
305303

@@ -309,18 +307,6 @@ mod tests {
309307
assert_eq!(s.parse::<EscapedURI>().unwrap(), *input);
310308
}
311309

312-
#[test]
313-
fn test_redirect_error_encodes_url_path() {
314-
let response = AxumNope::Redirect(
315-
EscapedURI::from_path("/something>"),
316-
CachePolicy::ForeverInCdnAndBrowser,
317-
)
318-
.into_response();
319-
320-
assert_eq!(response.status(), 302);
321-
assert_eq!(response.headers().get("Location").unwrap(), "/something%3E");
322-
}
323-
324310
#[test_case("/something" => "/something")]
325311
#[test_case("/something>" => "/something%3E")]
326312
fn test_escaped_uri_encodes_from_path(input: &str) -> String {

crates/lib/docs_rs_uri/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
mod encode;
2+
mod escaped_uri;
3+
4+
pub use encode::{encode_url_path, url_decode};
5+
pub use escaped_uri::EscapedURI;

src/web/error.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use crate::{
22
db::PoolError,
33
storage::PathNotFoundError,
4-
web::{AxumErrorPage, cache::CachePolicy, escaped_uri::EscapedURI, releases::Search},
4+
web::{AxumErrorPage, cache::CachePolicy, releases::Search},
55
};
66
use anyhow::{Result, anyhow};
77
use axum::{
88
Json,
99
http::StatusCode,
1010
response::{IntoResponse, Response as AxumResponse},
1111
};
12+
use docs_rs_uri::EscapedURI;
1213
use std::borrow::Cow;
1314

1415
#[derive(Debug, thiserror::Error)]

src/web/extractors/rustdoc.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22
33
use crate::{
44
storage::CompressionAlgorithm,
5-
web::{
6-
MatchedRelease, MetaData, error::AxumNope, escaped_uri::EscapedURI, extractors::Path,
7-
url_decode,
8-
},
5+
web::{MatchedRelease, MetaData, error::AxumNope, extractors::Path},
96
};
107
use anyhow::Result;
118
use axum::{
@@ -14,6 +11,7 @@ use axum::{
1411
http::{Uri, request::Parts},
1512
};
1613
use docs_rs_types::{BuildId, KrateName, ReqVersion};
14+
use docs_rs_uri::{EscapedURI, url_decode};
1715
use itertools::Itertools as _;
1816
use serde::Deserialize;
1917

src/web/headers/canonical_url.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use crate::web::escaped_uri::EscapedURI;
21
use anyhow::Result;
32
use askama::filters::HtmlSafe;
43
use axum::http::uri::Uri;
54
use axum_extra::headers::{Header, HeaderName, HeaderValue};
5+
use docs_rs_uri::EscapedURI;
66
use serde::Serialize;
77
use std::{fmt, ops::Deref};
88

src/web/mod.rs

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ pub(crate) mod cache;
66
pub(crate) mod crate_details;
77
mod csp;
88
pub(crate) mod error;
9-
mod escaped_uri;
109
pub(crate) mod extractors;
1110
mod features;
1211
mod file;
@@ -48,7 +47,6 @@ use docs_rs_types::{BuildStatus, CrateId, KrateName, ReqVersion, Version, Versio
4847
use docs_rs_utils::rustc_version::parse_rustc_date;
4948
use error::AxumNope;
5049
use page::TemplateData;
51-
use percent_encoding::{AsciiSet, CONTROLS, utf8_percent_encode};
5250
use sentry::integrations::tower as sentry_tower;
5351
use serde::Serialize;
5452
use serde_json::Value;
@@ -61,19 +59,6 @@ use tower::ServiceBuilder;
6159
use tower_http::{catch_panic::CatchPanicLayer, timeout::TimeoutLayer, trace::TraceLayer};
6260
use tracing::{info, instrument};
6361

64-
// from https://github.com/servo/rust-url/blob/master/url/src/parser.rs
65-
// and https://github.com/tokio-rs/axum/blob/main/axum-extra/src/lib.rs
66-
const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');
67-
const PATH: &AsciiSet = &FRAGMENT.add(b'#').add(b'?').add(b'{').add(b'}');
68-
69-
pub(crate) fn encode_url_path(path: &str) -> String {
70-
utf8_percent_encode(path, PATH).to_string()
71-
}
72-
73-
pub(crate) fn url_decode<'a>(input: &'a str) -> Result<Cow<'a, str>> {
74-
Ok(percent_encoding::percent_decode(input.as_bytes()).decode_utf8()?)
75-
}
76-
7762
/// Picks the correct "rustdoc.css" static file depending on which rustdoc version was used to
7863
/// generate this version of this crate.
7964
pub fn get_correct_docsrs_style_file(version: &str) -> Result<String> {
@@ -641,18 +626,18 @@ impl_axum_webpage! {
641626

642627
#[cfg(test)]
643628
mod test {
644-
use std::str::FromStr as _;
645-
646629
use super::*;
647630
use crate::docbuilder::DocCoverage;
648631
use crate::test::{
649632
AxumResponseTestExt, AxumRouterTestExt, FakeBuild, TestDatabase, TestEnvironment,
650633
async_wrapper,
651634
};
652635
use docs_rs_types::ReleaseId;
636+
use docs_rs_uri::encode_url_path;
653637
use kuchikiki::traits::TendrilSink;
654638
use pretty_assertions::assert_eq;
655639
use serde_json::json;
640+
use std::str::FromStr as _;
656641
use test_case::test_case;
657642

658643
async fn release(version: &str, env: &TestEnvironment) -> ReleaseId {

0 commit comments

Comments
 (0)