Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serve /crate/latest/crate rather than redirect #1527

Merged
merged 1 commit into from
Nov 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/web/build_details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub fn build_details_handler(req: &mut Request) -> IronResult<Response> {
};

BuildDetailsPage {
metadata: cexpect!(req, MetaData::from_crate(&mut conn, name, version)),
metadata: cexpect!(req, MetaData::from_crate(&mut conn, name, version, version)),
build_details,
}
.into_response(req)
Expand Down
21 changes: 15 additions & 6 deletions src/web/builds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ pub fn build_list_handler(req: &mut Request) -> IronResult<Response> {
.last()
.map_or(false, |segment| segment.ends_with(".json"));

let version =
let (version, version_or_latest) =
match match_version(&mut conn, name, req_version).and_then(|m| m.assume_exact())? {
MatchSemver::Exact((version, _)) => version,
MatchSemver::Exact((version, _)) => (version.clone(), version),
MatchSemver::Latest((version, _)) => (version, "latest".to_string()),

MatchSemver::Semver((version, _)) => {
let ext = if is_json { ".json" } else { "" };
Expand Down Expand Up @@ -117,7 +118,10 @@ pub fn build_list_handler(req: &mut Request) -> IronResult<Response> {
Ok(resp)
} else {
BuildsPage {
metadata: cexpect!(req, MetaData::from_crate(&mut conn, name, &version)),
metadata: cexpect!(
req,
MetaData::from_crate(&mut conn, name, &version, &version_or_latest)
),
builds,
limits,
}
Expand Down Expand Up @@ -307,7 +311,7 @@ mod tests {
}

#[test]
fn latest_redirect() {
fn latest_200() {
wrapper(|env| {
env.fake_release()
.name("aquarelle")
Expand All @@ -332,7 +336,12 @@ mod tests {
assert!(resp
.url()
.as_str()
.ends_with("/crate/aquarelle/0.2.0/builds"));
.ends_with("/crate/aquarelle/latest/builds"));
let body = String::from_utf8(resp.bytes().unwrap().to_vec()).unwrap();
assert!(body.contains("<a href=\"/crate/aquarelle/latest/features\""));
assert!(body.contains("<a href=\"/crate/aquarelle/latest/builds\""));
assert!(body.contains("<a href=\"/crate/aquarelle/latest/source/\""));
assert!(body.contains("<a href=\"/crate/aquarelle/latest\""));

let resp_json = env
.frontend()
Expand All @@ -341,7 +350,7 @@ mod tests {
assert!(resp_json
.url()
.as_str()
.ends_with("/crate/aquarelle/0.2.0/builds.json"));
.ends_with("/crate/aquarelle/latest/builds.json"));

Ok(())
});
Expand Down
85 changes: 74 additions & 11 deletions src/web/crate_details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ impl CrateDetails {
conn: &mut Client,
name: &str,
version: &str,
version_or_latest: &str,
up: &RepositoryStatsUpdater,
) -> Option<CrateDetails> {
// get all stuff, I love you rustfmt
Expand Down Expand Up @@ -150,6 +151,7 @@ impl CrateDetails {
let metadata = MetaData {
name: krate.get("name"),
version: krate.get("version"),
version_or_latest: version_or_latest.to_string(),
description: krate.get("description"),
rustdoc_status: krate.get("rustdoc_status"),
target_name: krate.get("target_name"),
Expand Down Expand Up @@ -281,16 +283,21 @@ pub fn crate_details_handler(req: &mut Request) -> IronResult<Response> {
let name = cexpect!(req, router.find("name"));
let req_version = router.find("version");

let mut conn = extension!(req, Pool).get()?;

match match_version(&mut conn, name, req_version).and_then(|m| m.assume_exact())? {
MatchSemver::Exact((version, _)) => {
let updater = extension!(req, RepositoryStatsUpdater);
let details = cexpect!(req, CrateDetails::new(&mut conn, name, &version, updater));
if req_version == None {
let url = ctry!(
req,
Url::parse(&format!("{}/crate/{}/latest", redirect_base(req), name,)),
);
return Ok(super::redirect(url));
}

CrateDetailsPage { details }.into_response(req)
}
let mut conn = extension!(req, Pool).get()?;

let found_version =
match_version(&mut conn, name, req_version).and_then(|m| m.assume_exact())?;
let (version, version_or_latest) = match found_version {
MatchSemver::Exact((version, _)) => (version.clone(), version),
MatchSemver::Latest((version, _)) => (version, "latest".to_string()),
MatchSemver::Semver((version, _)) => {
let url = ctry!(
req,
Expand All @@ -302,16 +309,24 @@ pub fn crate_details_handler(req: &mut Request) -> IronResult<Response> {
)),
);

Ok(super::redirect(url))
return Ok(super::redirect(url));
}
}
};

let updater = extension!(req, RepositoryStatsUpdater);
let details = cexpect!(
req,
CrateDetails::new(&mut conn, name, &version, &version_or_latest, updater)
);

CrateDetailsPage { details }.into_response(req)
}

#[cfg(test)]
mod tests {
use super::*;
use crate::index::api::CrateOwner;
use crate::test::{wrapper, TestDatabase};
use crate::test::{assert_redirect, wrapper, TestDatabase};
use anyhow::{Context, Error};
use kuchiki::traits::TendrilSink;
use std::collections::HashMap;
Expand All @@ -326,6 +341,7 @@ mod tests {
&mut db.conn(),
package,
version,
version,
db.repository_stats_updater(),
)
.with_context(|| anyhow::anyhow!("could not fetch crate details"))?;
Expand Down Expand Up @@ -459,6 +475,7 @@ mod tests {
&mut db.conn(),
"foo",
"0.2.0",
"0.2.0",
db.repository_stats_updater(),
)
.unwrap();
Expand Down Expand Up @@ -534,6 +551,7 @@ mod tests {
&mut db.conn(),
"foo",
version,
version,
db.repository_stats_updater(),
)
.unwrap();
Expand Down Expand Up @@ -564,6 +582,7 @@ mod tests {
&mut db.conn(),
"foo",
version,
version,
db.repository_stats_updater(),
)
.unwrap();
Expand Down Expand Up @@ -595,6 +614,7 @@ mod tests {
&mut db.conn(),
"foo",
version,
version,
db.repository_stats_updater(),
)
.unwrap();
Expand Down Expand Up @@ -634,6 +654,7 @@ mod tests {
&mut db.conn(),
"foo",
version,
version,
db.repository_stats_updater(),
)
.unwrap();
Expand Down Expand Up @@ -696,6 +717,7 @@ mod tests {
&mut db.conn(),
"foo",
"0.0.1",
"0.0.1",
db.repository_stats_updater(),
)
.unwrap();
Expand Down Expand Up @@ -726,6 +748,7 @@ mod tests {
&mut db.conn(),
"foo",
"0.0.1",
"0.0.1",
db.repository_stats_updater(),
)
.unwrap();
Expand Down Expand Up @@ -755,6 +778,7 @@ mod tests {
&mut db.conn(),
"foo",
"0.0.1",
"0.0.1",
db.repository_stats_updater(),
)
.unwrap();
Expand All @@ -779,6 +803,7 @@ mod tests {
&mut db.conn(),
"foo",
"0.0.1",
"0.0.1",
db.repository_stats_updater(),
)
.unwrap();
Expand Down Expand Up @@ -956,4 +981,42 @@ mod tests {
Ok(())
});
}

#[test]
fn latest_url() {
wrapper(|env| {
env.fake_release()
.name("dummy")
.version("0.4.0")
.rustdoc_file("dummy/index.html")
.rustdoc_file("x86_64-pc-windows-msvc/dummy/index.html")
.default_target("x86_64-unknown-linux-gnu")
.add_target("x86_64-pc-windows-msvc")
.create()?;
let web = env.frontend();

let resp = env.frontend().get("/crate/dummy/latest").send()?;
assert!(resp.status().is_success());
assert!(resp.url().as_str().ends_with("/crate/dummy/latest"));
let body = String::from_utf8(resp.bytes().unwrap().to_vec()).unwrap();
assert!(body.contains("<a href=\"/crate/dummy/latest/features\""));
assert!(body.contains("<a href=\"/crate/dummy/latest/builds\""));
assert!(body.contains("<a href=\"/crate/dummy/latest/source/\""));
assert!(body.contains("<a href=\"/crate/dummy/latest\""));

assert_redirect("/crate/dummy/latest/", "/crate/dummy/latest", web)?;
assert_redirect("/crate/dummy", "/crate/dummy/latest", web)?;

let resp_json = env
.frontend()
.get("/crate/aquarelle/latest/builds.json")
.send()?;
assert!(resp_json
.url()
.as_str()
.ends_with("/crate/aquarelle/latest/builds.json"));

Ok(())
});
}
}
18 changes: 13 additions & 5 deletions src/web/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ pub fn build_features_handler(req: &mut Request) -> IronResult<Response> {
let req_version = router.find("version");

let mut conn = extension!(req, Pool).get()?;
let version =
let (version, version_or_latest) =
match match_version(&mut conn, name, req_version).and_then(|m| m.assume_exact())? {
MatchSemver::Exact((version, _)) => version,
MatchSemver::Exact((version, _)) => (version.clone(), version),
MatchSemver::Latest((version, _)) => (version, "latest".to_string()),

MatchSemver::Semver((version, _)) => {
let url = ctry!(
Expand Down Expand Up @@ -69,7 +70,10 @@ pub fn build_features_handler(req: &mut Request) -> IronResult<Response> {
}

FeaturesPage {
metadata: cexpect!(req, MetaData::from_crate(&mut conn, name, &version)),
metadata: cexpect!(
req,
MetaData::from_crate(&mut conn, name, &version, &version_or_latest)
),
features,
default_len,
}
Expand Down Expand Up @@ -244,7 +248,7 @@ mod tests {
}

#[test]
fn latest_redirect() {
fn latest_200() {
wrapper(|env| {
env.fake_release()
.name("foo")
Expand All @@ -259,7 +263,11 @@ mod tests {
.create()?;

let resp = env.frontend().get("/crate/foo/latest/features").send()?;
assert!(resp.url().as_str().ends_with("/crate/foo/0.2.0/features"));
assert!(resp.url().as_str().ends_with("/crate/foo/latest/features"));
let body = String::from_utf8(resp.bytes().unwrap().to_vec()).unwrap();
assert!(body.contains("<a href=\"/crate/foo/latest/builds\""));
assert!(body.contains("<a href=\"/crate/foo/latest/source/\""));
assert!(body.contains("<a href=\"/crate/foo/latest\""));
Ok(())
});
}
Expand Down
Loading