Skip to content
This repository has been archived by the owner on Jun 21, 2024. It is now read-only.

Commit

Permalink
Make max_body_size configurable via env, drop custom check, use 413
Browse files Browse the repository at this point in the history
  • Loading branch information
bretthoerner committed May 3, 2024
1 parent cf9b82d commit 1ed0af5
Show file tree
Hide file tree
Showing 7 changed files with 22 additions and 25 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ members = [

[workspace.lints.rust]
# See https://doc.rust-lang.org/stable/rustc/lints/listing/allowed-by-default.html
unsafe_code = "forbid" # forbid cannot be ignored with an annotation
unsafe_code = "forbid" # forbid cannot be ignored with an annotation
unstable_features = "forbid"
macro_use_extern_crate = "forbid"
let_underscore_drop = "deny"
Expand Down Expand Up @@ -69,7 +69,7 @@ time = { version = "0.3.20", features = [
thiserror = { version = "1.0" }
tokio = { version = "1.34.0", features = ["full"] }
tower = "0.4.13"
tower-http = { version = "0.5.2", features = ["cors", "trace"] }
tower-http = { version = "0.5.2", features = ["cors", "limit", "trace"] }
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
url = { version = "2.5.0 " }
Expand Down
1 change: 1 addition & 0 deletions hook-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ serde_json = { workspace = true }
sqlx = { workspace = true }
tokio = { workspace = true }
tower = { workspace = true }
tower-http = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
url = { workspace = true }
3 changes: 3 additions & 0 deletions hook-api/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ pub struct Config {

#[envconfig(default = "100")]
pub max_pg_connections: u32,

#[envconfig(default = "5000000")]
pub max_body_size: usize,
}

impl Config {
Expand Down
9 changes: 5 additions & 4 deletions hook-api/src/handlers/app.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use axum::{extract::DefaultBodyLimit, routing, Router};
use axum::{routing, Router};
use tower_http::limit::RequestBodyLimitLayer;

use hook_common::pgqueue::PgQueue;

use super::webhook;

pub fn add_routes(router: Router, pg_pool: PgQueue) -> Router {
pub fn add_routes(router: Router, pg_pool: PgQueue, max_body_size: usize) -> Router {
router
.route("/", routing::get(index))
.route("/_readiness", routing::get(index))
Expand All @@ -13,7 +14,7 @@ pub fn add_routes(router: Router, pg_pool: PgQueue) -> Router {
"/webhook",
routing::post(webhook::post)
.with_state(pg_pool)
.layer(DefaultBodyLimit::disable()),
.layer(RequestBodyLimitLayer::new(max_body_size)),
)
}

Expand All @@ -37,7 +38,7 @@ mod tests {
async fn index(db: PgPool) {
let pg_queue = PgQueue::new_from_pool("test_index", db).await;

let app = add_routes(Router::new(), pg_queue);
let app = add_routes(Router::new(), pg_queue, 1_000_000);

let response = app
.oneshot(Request::builder().uri("/").body(Body::empty()).unwrap())
Expand Down
27 changes: 9 additions & 18 deletions hook-api/src/handlers/webhook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ use hook_common::pgqueue::{NewJob, PgQueue};
use serde::Serialize;
use tracing::{debug, error};

pub const MAX_BODY_SIZE: usize = 5_000_000;

#[derive(Serialize, Deserialize)]
pub struct WebhookPostResponse {
#[serde(skip_serializing_if = "Option::is_none")]
Expand All @@ -37,15 +35,6 @@ pub async fn post(
) -> Result<Json<WebhookPostResponse>, (StatusCode, Json<WebhookPostResponse>)> {
debug!("received payload: {:?}", payload);

if payload.parameters.body.len() > MAX_BODY_SIZE {
return Err((
StatusCode::BAD_REQUEST,
Json(WebhookPostResponse {
error: Some("body too large".to_owned()),
}),
));
}

let url_hostname = get_hostname(&payload.parameters.url)?;
// We could cast to i32, but this ensures we are not wrapping.
let max_attempts = i32::try_from(payload.max_attempts).map_err(|_| {
Expand Down Expand Up @@ -125,11 +114,13 @@ mod tests {

use crate::handlers::app::add_routes;

const MAX_BODY_SIZE: usize = 1_000_000;

#[sqlx::test(migrations = "../migrations")]
async fn webhook_success(db: PgPool) {
let pg_queue = PgQueue::new_from_pool("test_index", db).await;

let app = add_routes(Router::new(), pg_queue);
let app = add_routes(Router::new(), pg_queue, MAX_BODY_SIZE);

let mut headers = collections::HashMap::new();
headers.insert("Content-Type".to_owned(), "application/json".to_owned());
Expand Down Expand Up @@ -171,7 +162,7 @@ mod tests {
async fn webhook_bad_url(db: PgPool) {
let pg_queue = PgQueue::new_from_pool("test_index", db).await;

let app = add_routes(Router::new(), pg_queue);
let app = add_routes(Router::new(), pg_queue, MAX_BODY_SIZE);

let response = app
.oneshot(
Expand Down Expand Up @@ -208,7 +199,7 @@ mod tests {
async fn webhook_payload_missing_fields(db: PgPool) {
let pg_queue = PgQueue::new_from_pool("test_index", db).await;

let app = add_routes(Router::new(), pg_queue);
let app = add_routes(Router::new(), pg_queue, MAX_BODY_SIZE);

let response = app
.oneshot(
Expand All @@ -229,7 +220,7 @@ mod tests {
async fn webhook_payload_not_json(db: PgPool) {
let pg_queue = PgQueue::new_from_pool("test_index", db).await;

let app = add_routes(Router::new(), pg_queue);
let app = add_routes(Router::new(), pg_queue, MAX_BODY_SIZE);

let response = app
.oneshot(
Expand All @@ -250,9 +241,9 @@ mod tests {
async fn webhook_payload_body_too_large(db: PgPool) {
let pg_queue = PgQueue::new_from_pool("test_index", db).await;

let app = add_routes(Router::new(), pg_queue);
let app = add_routes(Router::new(), pg_queue, MAX_BODY_SIZE);

let bytes: Vec<u8> = vec![b'a'; 5_000_000 * 2];
let bytes: Vec<u8> = vec![b'a'; MAX_BODY_SIZE + 1];
let long_string = String::from_utf8_lossy(&bytes);

let response = app
Expand Down Expand Up @@ -283,6 +274,6 @@ mod tests {
.await
.unwrap();

assert_eq!(response.status(), StatusCode::BAD_REQUEST);
assert_eq!(response.status(), StatusCode::PAYLOAD_TOO_LARGE);
}
}
2 changes: 1 addition & 1 deletion hook-api/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ async fn main() {
.await
.expect("failed to initialize queue");

let app = handlers::add_routes(Router::new(), pg_queue);
let app = handlers::add_routes(Router::new(), pg_queue, config.max_body_size);
let app = setup_metrics_routes(app);

match listen(app, config.bind()).await {
Expand Down

0 comments on commit 1ed0af5

Please sign in to comment.