Skip to content

Commit 980dfa5

Browse files
committed
middleware/cargo_compat: Implement feature flag for 200 OK status code enforcement
1 parent 2945bfd commit 980dfa5

File tree

4 files changed

+14
-5
lines changed

4 files changed

+14
-5
lines changed

src/config/server.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ pub struct Server {
5656
pub cdn_user_agent: String,
5757
pub balance_capacity: BalanceCapacityConfig,
5858

59+
/// Instructs the `cargo_compat` middleware to always reply with `200 OK`
60+
/// for all endpoints that are relevant for cargo.
61+
pub use_cargo_compat_status_codes: bool,
62+
5963
/// Should the server serve the frontend assets in the `dist` directory?
6064
pub serve_dist: bool,
6165

@@ -221,6 +225,8 @@ impl Server {
221225
cdn_user_agent: var("WEB_CDN_USER_AGENT")?
222226
.unwrap_or_else(|| "Amazon CloudFront".into()),
223227
balance_capacity: BalanceCapacityConfig::from_environment()?,
228+
use_cargo_compat_status_codes: !var("CARGO_COMPAT_STATUS_CODES")?
229+
.is_some_and(|v| v == "n"),
224230
serve_dist: true,
225231
serve_html: true,
226232
content_security_policy: Some(content_security_policy.parse()?),

src/middleware.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ pub fn apply_axum_middleware(state: AppState, router: Router<()>) -> Router {
6262
from_fn(debug::debug_requests)
6363
}));
6464

65+
let only_200 = state.config.use_cargo_compat_status_codes;
6566
let middlewares_2 = tower::ServiceBuilder::new()
66-
.layer(from_fn(cargo_compat::middleware))
67+
.layer(from_fn_with_state(only_200, cargo_compat::middleware))
6768
.layer(from_fn_with_state(state.clone(), session::attach_session))
6869
.layer(from_fn_with_state(
6970
state.clone(),

src/middleware/cargo_compat.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
use axum::extract::{MatchedPath, Request};
1+
use axum::extract::{MatchedPath, Request, State};
22
use axum::middleware::Next;
33
use axum::response::{IntoResponse, Response};
44
use axum::{Extension, Json};
55
use http::{header, Method, StatusCode};
66

77
/// Convert plain text errors into JSON errors and adjust status codes.
88
pub async fn middleware(
9+
State(use_cargo_compat_status_codes): State<bool>,
910
matched_path: Option<Extension<MatchedPath>>,
1011
req: Request,
1112
next: Next,
@@ -19,7 +20,7 @@ pub async fn middleware(
1920
if is_api_request {
2021
res = ensure_json_errors(res).await;
2122
}
22-
if is_cargo_endpoint {
23+
if use_cargo_compat_status_codes && is_cargo_endpoint {
2324
// cargo until 1.34.0 expected crates.io to always return 200 OK for
2425
// all requests, even if they failed. If a different status code was
2526
// returned, cargo would show the raw JSON response to the user, instead
@@ -95,7 +96,7 @@ async fn convert_to_json_response(res: Response) -> anyhow::Result<Response> {
9596
mod tests {
9697
use super::*;
9798
use axum::body::Body;
98-
use axum::middleware::from_fn;
99+
use axum::middleware::from_fn_with_state;
99100
use axum::routing::{get, put};
100101
use axum::Router;
101102
use bytes::Bytes;
@@ -121,7 +122,7 @@ mod tests {
121122
"/api/v1/crates/:crate_id/owners",
122123
get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
123124
)
124-
.layer(from_fn(middleware))
125+
.layer(from_fn_with_state(true, middleware))
125126
}
126127

127128
async fn request(path: &str) -> anyhow::Result<(Parts, Bytes)> {

src/tests/util/test_app.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ fn simple_config() -> config::Server {
427427
version_id_cache_ttl: Duration::from_secs(5 * 60),
428428
cdn_user_agent: "Amazon CloudFront".to_string(),
429429
balance_capacity,
430+
use_cargo_compat_status_codes: true,
430431

431432
// The frontend code is not needed for the backend tests.
432433
serve_dist: false,

0 commit comments

Comments
 (0)