Skip to content

Commit 50cb808

Browse files
committed
add krate-name validation to rustdoc parameter extraction
1 parent 616d9bb commit 50cb808

File tree

17 files changed

+324
-293
lines changed

17 files changed

+324
-293
lines changed

src/db/types/krate_name.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ use sqlx::{
66
Decode, Encode, Postgres,
77
encode::IsNull,
88
error::BoxDynError,
9-
postgres::{PgArgumentBuffer, PgTypeInfo, PgValueRef},
9+
postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef},
1010
prelude::*,
1111
};
12-
use std::{io::Write, str::FromStr};
12+
use std::{borrow::Cow, io::Write, str::FromStr};
1313

1414
/// validated crate name
1515
///
@@ -31,7 +31,14 @@ use std::{io::Write, str::FromStr};
3131
SerializeDisplay,
3232
bincode::Encode,
3333
)]
34-
pub struct KrateName(String);
34+
pub struct KrateName(Cow<'static, str>);
35+
36+
impl KrateName {
37+
#[cfg(test)]
38+
pub(crate) const fn from_static(s: &'static str) -> Self {
39+
KrateName(Cow::Borrowed(s))
40+
}
41+
}
3542

3643
impl From<&KrateName> for KrateName {
3744
fn from(krate_name: &KrateName) -> Self {
@@ -44,7 +51,7 @@ impl FromStr for KrateName {
4451

4552
fn from_str(s: &str) -> Result<Self, Self::Err> {
4653
validate_crate_name("crate", s)?;
47-
Ok(KrateName(s.to_string()))
54+
Ok(KrateName(Cow::Owned(s.to_string())))
4855
}
4956
}
5057

@@ -67,8 +74,21 @@ impl<'q> Encode<'q, Postgres> for KrateName {
6774

6875
impl<'r> Decode<'r, Postgres> for KrateName {
6976
fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
77+
// future improvement: we could also avoid the allocation here
78+
// and return a Cow::Borrowed while reading from the DB.
79+
// But this would mean the lifetime leaks into the whole codebase.
7080
let s: &str = Decode::<Postgres>::decode(value)?;
71-
Ok(Self(s.parse()?))
81+
Ok(Self(Cow::Owned(s.parse()?)))
82+
}
83+
}
84+
85+
impl PgHasArrayType for KrateName {
86+
fn array_type_info() -> PgTypeInfo {
87+
<&str as PgHasArrayType>::array_type_info()
88+
}
89+
90+
fn array_compatible(ty: &PgTypeInfo) -> bool {
91+
<&str as PgHasArrayType>::array_compatible(ty)
7292
}
7393
}
7494

src/storage/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use tokio::{
4545
runtime,
4646
sync::Mutex,
4747
};
48-
use tracing::{debug, error, info_span, instrument, trace, warn};
48+
use tracing::{debug, info_span, instrument, trace, warn};
4949
use walkdir::WalkDir;
5050

5151
const ARCHIVE_INDEX_FILE_EXTENSION: &str = "index";

src/utils/cargo_metadata.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use crate::{db::types::version::Version, error::Result};
1+
use crate::db::types::krate_name::KrateName;
2+
use crate::web::ReqVersion;
3+
use crate::{db::types::version::Version, error::Result, web::extractors::rustdoc::RustdocParams};
24
use anyhow::{Context, bail};
35
use rustwide::{Toolchain, Workspace, cmd::Command};
46
use semver::VersionReq;
@@ -135,6 +137,19 @@ pub(crate) struct Dependency {
135137
pub(crate) optional: bool,
136138
}
137139

140+
impl Dependency {
141+
pub(crate) fn rustdoc_params(&self) -> RustdocParams {
142+
RustdocParams::new(
143+
// I validated in the database, which makes me assume that renames are
144+
// handled before storing the deps into the column.
145+
self.name
146+
.parse::<KrateName>()
147+
.expect("we validated that the dep name is always a valid KrateName"),
148+
)
149+
.with_req_version(ReqVersion::Semver(self.req.clone()))
150+
}
151+
}
152+
138153
impl bincode::Encode for Dependency {
139154
fn encode<E: bincode::enc::Encoder>(
140155
&self,

src/utils/html.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use lol_html::{element, errors::RewritingError};
1818
use std::sync::Arc;
1919
use tokio::{io::AsyncRead, task::JoinHandle};
2020
use tokio_util::io::ReaderStream;
21-
use tracing::{Span, error, instrument};
21+
use tracing::{Span, instrument};
2222
use tracing_futures::Instrument as _;
2323

2424
const CHANNEL_SIZE: usize = 64;

src/web/build_details.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ pub(crate) async fn build_details_handler(
7676
.into_canonical_req_version_or_else(|confirmed_name, version| {
7777
let params = params
7878
.clone()
79-
.with_confirmed_name(Some(confirmed_name))
79+
.with_name(confirmed_name)
8080
.with_req_version(version);
8181
AxumNope::Redirect(
8282
params.build_details_url(id, build_params.filename.as_deref()),

src/web/builds.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::build_queue::PRIORITY_MANUAL_FROM_CRATES_IO;
2+
use crate::db::types::krate_name::KrateName;
23
use crate::{
34
AsyncBuildQueue, Config,
45
db::{
@@ -70,7 +71,7 @@ pub(crate) async fn build_list_handler(
7071
.into_canonical_req_version_or_else(|confirmed_name, version| {
7172
let params = params
7273
.clone()
73-
.with_confirmed_name(Some(confirmed_name))
74+
.with_name(confirmed_name)
7475
.with_req_version(version);
7576
AxumNope::Redirect(
7677
params.builds_url(),
@@ -105,7 +106,7 @@ pub(crate) async fn build_list_handler(
105106

106107
async fn crate_version_exists(
107108
conn: &mut sqlx::PgConnection,
108-
name: &String,
109+
name: &KrateName,
109110
version: &Version,
110111
) -> Result<bool, anyhow::Error> {
111112
let row = sqlx::query!(
@@ -125,7 +126,7 @@ async fn crate_version_exists(
125126

126127
async fn build_trigger_check(
127128
conn: &mut sqlx::PgConnection,
128-
name: &String,
129+
name: &KrateName,
129130
version: &Version,
130131
build_queue: &Arc<AsyncBuildQueue>,
131132
) -> AxumResult<impl IntoResponse> {
@@ -145,7 +146,7 @@ async fn build_trigger_check(
145146
}
146147

147148
pub(crate) async fn build_trigger_rebuild_handler(
148-
Path((name, version)): Path<(String, Version)>,
149+
Path((name, version)): Path<(KrateName, Version)>,
149150
mut conn: DbConnection,
150151
Extension(build_queue): Extension<Arc<AsyncBuildQueue>>,
151152
Extension(config): Extension<Arc<Config>>,

src/web/crate_details.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ pub(crate) async fn crate_details_handler(
489489
.into_canonical_req_version_or_else(|confirmed_name, version| {
490490
let params = params
491491
.clone()
492-
.with_confirmed_name(Some(confirmed_name))
492+
.with_name(confirmed_name)
493493
.with_req_version(version);
494494
AxumNope::Redirect(
495495
params.crate_details_url(),
@@ -660,7 +660,7 @@ pub(crate) async fn get_all_platforms_inner(
660660
AxumNope::Redirect(
661661
params
662662
.clone()
663-
.with_confirmed_name(Some(corrected_name))
663+
.with_name(corrected_name)
664664
.with_req_version(req_version)
665665
.platforms_partial_url(),
666666
CachePolicy::NoCaching,
@@ -669,7 +669,7 @@ pub(crate) async fn get_all_platforms_inner(
669669
.into_canonical_req_version_or_else(|confirmed_name, version| {
670670
let params = params
671671
.clone()
672-
.with_confirmed_name(Some(confirmed_name))
672+
.with_name(confirmed_name)
673673
.with_req_version(version);
674674
AxumNope::Redirect(
675675
params.platforms_partial_url(),
@@ -2254,7 +2254,7 @@ path = "src/lib.rs"
22542254
.await?;
22552255

22562256
let resp = env.web_app().await.get("/crate/dummy%3E").await?;
2257-
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
2257+
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
22582258

22592259
Ok(())
22602260
})

src/web/error.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use axum::{
1010
response::{IntoResponse, Response as AxumResponse},
1111
};
1212
use std::borrow::Cow;
13-
use tracing::error;
1413

1514
#[derive(Debug, thiserror::Error)]
1615
pub enum AxumNope {

0 commit comments

Comments
 (0)