From 36b624e014f0725a8904218730f3c6fe74fb3522 Mon Sep 17 00:00:00 2001 From: oylbin Date: Tue, 26 Sep 2023 16:25:44 +0800 Subject: [PATCH] Added support for gzipped request body decoding - Added dependencies on `flate2:1.0.26` in Cargo.toml, (1.0.27 breaks docker build). - Refactored request body reading in `src/serve.rs` to support both gzip-encoded and plain request bodies. To test the new function, use the following shell command: ``` echo '{"mydummy": "json"}' | gzip | curl -v -i --data-binary @- -H "Content-Encoding: gzip" -H 'Content-Type: application/json' http://localhost:8000/test_endpoint ``` --- Cargo.lock | 35 +++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/serve.rs | 34 ++++++++++++++++++++++++++++------ 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a992cb..e189d1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "ahash" version = "0.4.7" @@ -187,6 +193,15 @@ dependencies = [ "syn", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "crossbeam-utils" version = "0.8.1" @@ -244,6 +259,16 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -447,6 +472,15 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -698,6 +732,7 @@ dependencies = [ "chrono", "clap", "env_logger", + "flate2", "log", "rusqlite", "rust-embed", diff --git a/Cargo.toml b/Cargo.toml index 2ff41b7..e7b3c6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,4 @@ rusqlite = {version = "0.24", features = ["bundled"]} rust-embed = "5" log = "^0.4" env_logger = "^0.9" +flate2 = { version = "=1.0.26", features = [] } diff --git a/src/serve.rs b/src/serve.rs index 82c93e3..a4786ec 100644 --- a/src/serve.rs +++ b/src/serve.rs @@ -1,6 +1,6 @@ use tiny_http::{Response, Header, Request}; use tera::{Context}; -use std::io::{Cursor}; +use std::io::{Read, Cursor}; use chrono::{Utc}; use std::collections::HashMap; use url::{Url}; @@ -12,7 +12,7 @@ use rusqlite::{params, Connection}; use rust_embed::RustEmbed; use log::{info}; - +use flate2::read::GzDecoder; #[derive(RustEmbed)] #[folder = "static"] @@ -147,15 +147,37 @@ fn prune_requests(app_ctx: &mut AppContext, pct: f32) { } } +fn get_request_body(request: &mut Request) -> String { + let mut body = String::new(); + + // Check if the content is gzip-encoded + let content_encoding = request.headers() + .iter() + .find(|h| h.field.equiv("Content-Encoding")) + .and_then(|h| Option::from(h.value.as_str())); + + if content_encoding == Some("gzip") { + // Use a GzDecoder to decompress the gzipped content + let mut d = GzDecoder::new(request.as_reader()); + if let Err(e) = d.read_to_string(&mut body) { + body = format!("Could not parse gzipped request body: {:?}", e); + } + } else { + // Handle non-gzipped content + if let Err(e) = request.as_reader().read_to_string(&mut body) { + body = format!("Could not parse request body - is this a binary format? {:?}", e); + } + } + + body +} + pub fn handle_req(request: &mut Request, app_ctx: &mut AppContext) -> Response>> { let base_url: Url = Url::parse("http://reqsink.local/").unwrap(); let url = base_url.join(request.url()).unwrap(); - let mut body = String::new(); - if let Err(e) = request.as_reader().read_to_string(&mut body) { - body = format!("Could not parse request body - is this a binary format? {:?}", e); - } + let body = get_request_body(request); let sr = StoredRequest { time: Utc::now().to_rfc2822(),