From 8583dd2b4c4eaa8e3a5d1574a645a6ac8c2f760d Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Tue, 15 Oct 2019 14:54:26 -0700 Subject: [PATCH] Replace uuid dependency with tiny internal RNG (#679) --- Cargo.toml | 1 - src/async_impl/multipart.rs | 48 +++++++++++++++++++++++++++++++++++-- tests/multipart.rs | 5 +++- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 00b0453..e0361a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,6 @@ mime_guess = "2.0" percent-encoding = "2.1" tokio = { version = "=0.2.0-alpha.6", default-features = false, features = ["io", "tcp", "timer"] } tokio-executor = "=0.2.0-alpha.6" -uuid = { version = "0.7", features = ["v4"] } time = "0.1.42" # TODO: candidates for optional features diff --git a/src/async_impl/multipart.rs b/src/async_impl/multipart.rs index 3598dab..4527f41 100644 --- a/src/async_impl/multipart.rs +++ b/src/async_impl/multipart.rs @@ -7,7 +7,6 @@ use bytes::Bytes; use http::HeaderMap; use mime_guess::Mime; use percent_encoding::{self, AsciiSet, NON_ALPHANUMERIC}; -use uuid::Uuid; use futures_core::Stream; use futures_util::{future, stream, StreamExt}; @@ -265,7 +264,7 @@ impl PartProps for Part { impl FormParts

{ pub(crate) fn new() -> Self { FormParts { - boundary: format!("{}", Uuid::new_v4().to_simple()), + boundary: gen_boundary(), computed_headers: Vec::new(), fields: Vec::new(), percent_encoding: PercentEncoding::PathSegment, @@ -481,6 +480,51 @@ impl PercentEncoding { } } +fn gen_boundary() -> String { + let a = random(); + let b = random(); + let c = random(); + let d = random(); + + format!("{:016x}-{:016x}-{:016x}-{:016x}", a, b, c, d) +} + +// xor-shift +fn random() -> u64 { + use std::cell::Cell; + use std::collections::hash_map::RandomState; + use std::hash::{BuildHasher, Hasher}; + use std::num::Wrapping; + + thread_local! { + static RNG: Cell> = Cell::new(Wrapping(seed())); + } + + fn seed() -> u64 { + let seed = RandomState::new(); + + let mut out = 0; + let mut cnt = 0; + while out == 0 { + cnt += 1; + let mut hasher = seed.build_hasher(); + hasher.write_usize(cnt); + out = hasher.finish(); + } + out + } + + RNG.with(|rng| { + let mut n = rng.get(); + debug_assert_ne!(n.0, 0); + n ^= n >> 12; + n ^= n << 25; + n ^= n >> 27; + rng.set(n); + n.0.wrapping_mul(0x2545_f491_4f6c_dd1d) + }) +} + #[cfg(test)] mod tests { use super::*; diff --git a/tests/multipart.rs b/tests/multipart.rs index ad22f82..d2f66e4 100644 --- a/tests/multipart.rs +++ b/tests/multipart.rs @@ -25,7 +25,10 @@ async fn text_part() { async move { assert_eq!(req.method(), "POST"); assert_eq!(req.headers()["content-type"], ct); - assert_eq!(req.headers()["content-length"], "125"); + assert_eq!( + req.headers()["content-length"], + expected_body.len().to_string() + ); let mut full: Vec = Vec::new(); while let Some(item) = req.body_mut().next().await {