git-ents.gitmain
⌘K
foforge
commit a15f980
refactor: parse form bodies with form_urlencoded instead of by hand

The hand-rolled percent_decode/hex_value pair reimplemented what form_urlencoded already does, tested, for x-www-form-urlencoded bodies.

deps: add form_urlencoded refactor: replace write.rs’s percent_decode/hex_value with form_urlencoded::parse Assisted-by: Claude:claude-sonnet-5

Joseph D. Carpinelli · 1 month ago

Reviews

No reviews of this commit yet — record a verdict below.

Start a review

verdict

Cargo.lock @@ -1042,6 +1042,7 @@ "clap", "clap_mangen", "facet", + "form_urlencoded", "getrandom", "git-ents", "git-store",
Cargo.toml @@ -38,6 +38,7 @@ facet = { version = "0.50.0-rc.0", features = ["reflect"] } getrandom = "0.4" facet-git-tree = { git = "https://github.com/git-ents/facet-git-tree" } +form_urlencoded = "1" git-store = { path = "crates/git-store" } gix = "0.84" gix-hash = { version = "0.25", features = ["sha1"] }
crates/git-ents-server/Cargo.toml @@ -15,6 +15,7 @@ clap = { workspace = true } clap_mangen = { workspace = true } facet = { workspace = true } +form_urlencoded = { workspace = true } getrandom = { workspace = true } git-store = { workspace = true } gix-actor = { workspace = true }
crates/git-ents-server/src/web/write.rs @@ -473,44 +473,7 @@ /// Parse an `application/x-www-form-urlencoded` body into its fields. fn form(body: &[u8]) -> HashMap<String, String> { - let text = String::from_utf8_lossy(body); - text.split('&') - .filter_map(|pair| { - let (key, value) = pair.split_once('=')?; - Some((percent_decode(key), percent_decode(value))) - }) - .collect() -} - -/// Decode one form field: `+` to space and `%XX` to its byte. -fn percent_decode(input: &str) -> String { - let spaced = input.replace('+', " "); - let mut parts = spaced.split('%'); - let mut out: Vec<u8> = parts.next().unwrap_or_default().as_bytes().to_vec(); - for part in parts { - let bytes = part.as_bytes(); - match ( - bytes.first().copied().and_then(hex_value), - bytes.get(1).copied().and_then(hex_value), - ) { - (Some(hi), Some(lo)) => { - out.push((hi << 4) | lo); - out.extend_from_slice(part.get(2..).unwrap_or_default().as_bytes()); - } - _ => { - out.push(b'%'); - out.extend_from_slice(bytes); - } - } - } - String::from_utf8_lossy(&out).into_owned() -} - -/// A single hex digit's value, `0..=15`. -fn hex_value(byte: u8) -> Option<u8> { - (byte as char) - .to_digit(16) - .and_then(|d| u8::try_from(d).ok()) + form_urlencoded::parse(body).into_owned().collect() } #[cfg(test)]