diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-15 16:37:08 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-17 16:30:22 -0600 |
| commit | 45df4d0d9b577fecee798d672695fe24ff57fb1b (patch) | |
| tree | 1b99bf645035b58e0d6db08c7a83521f41f7a75b /vendor/httparse | |
| parent | f94f79608393d4ab127db63cc41668445ef6b243 (diff) | |
feat: migrate from Cedar to SpiceDB authorization system
This is a major architectural change that replaces the Cedar policy-based
authorization system with SpiceDB's relation-based authorization.
Key changes:
- Migrate from Rust to Go implementation
- Replace Cedar policies with SpiceDB schema and relationships
- Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks
- Update build system and dependencies for Go ecosystem
- Maintain Envoy integration for external authorization
This change enables more flexible permission modeling through SpiceDB's
Google Zanzibar inspired relation-based system, supporting complex
hierarchical permissions that were difficult to express in Cedar.
Breaking change: Existing Cedar policies and Rust-based configuration
will no longer work and need to be migrated to SpiceDB schema.
Diffstat (limited to 'vendor/httparse')
| -rw-r--r-- | vendor/httparse/.cargo-checksum.json | 1 | ||||
| -rw-r--r-- | vendor/httparse/Cargo.lock | 688 | ||||
| -rw-r--r-- | vendor/httparse/Cargo.toml | 77 | ||||
| -rw-r--r-- | vendor/httparse/LICENSE-APACHE | 201 | ||||
| -rw-r--r-- | vendor/httparse/LICENSE-MIT | 20 | ||||
| -rw-r--r-- | vendor/httparse/README.md | 43 | ||||
| -rw-r--r-- | vendor/httparse/benches/parse.rs | 242 | ||||
| -rw-r--r-- | vendor/httparse/build.rs | 133 | ||||
| -rw-r--r-- | vendor/httparse/clippy.toml | 1 | ||||
| -rw-r--r-- | vendor/httparse/src/iter.rs | 199 | ||||
| -rw-r--r-- | vendor/httparse/src/lib.rs | 2798 | ||||
| -rw-r--r-- | vendor/httparse/src/macros.rs | 68 | ||||
| -rw-r--r-- | vendor/httparse/src/simd/avx2.rs | 206 | ||||
| -rw-r--r-- | vendor/httparse/src/simd/mod.rs | 153 | ||||
| -rw-r--r-- | vendor/httparse/src/simd/neon.rs | 258 | ||||
| -rw-r--r-- | vendor/httparse/src/simd/runtime.rs | 57 | ||||
| -rw-r--r-- | vendor/httparse/src/simd/sse42.rs | 142 | ||||
| -rw-r--r-- | vendor/httparse/src/simd/swar.rs | 235 | ||||
| -rw-r--r-- | vendor/httparse/tests/uri.rs | 3692 |
19 files changed, 0 insertions, 9214 deletions
diff --git a/vendor/httparse/.cargo-checksum.json b/vendor/httparse/.cargo-checksum.json deleted file mode 100644 index 3495ea67..00000000 --- a/vendor/httparse/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.lock":"ec51aecd295189c21ca216e1bb6e1f04e9f45d7dfc62da5c00480aebbf87a515","Cargo.toml":"067da5f6334526ce5f080909e5c271dd0968ab4198a65eea51d93b242febb48a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"391a5396cec6230bfabd4ef4eb2350eb895bc5efce377a2218f5702ed020d3e3","README.md":"eb23916ad2e4e904ee31e2af02e71ffd8f2d0c97f9e529f3e02f300a120e2c8b","benches/parse.rs":"1c76d3831410e0c2da0cbbee43431c2d28e2f1969664dea2a6a0e81f0a1c88be","build.rs":"eba8e341d746a6cf54249c62afe9eb237e7c21fcf9937223e894549e3a34d489","clippy.toml":"fd62dce2727b03fd4a8f6f3241e9da1e24ac2ff053d3986b0576c140823ec1ea","src/iter.rs":"630132d2d6fafa80c126b7b20b097c5ac7215575f7b61c8f8d7101b58ca57d0a","src/lib.rs":"a8307ce632f27b095cb84de27cfd8fc237977075d3eed41041f463c6afd9b757","src/macros.rs":"4e152282a120ec322f0873c65d2c334d7161f0085e91c52d45793c87f83e3e5c","src/simd/avx2.rs":"ce35db9ab9783880f44786a9d65727b0c5862a957d845e9f3d8a358b3ca4b01a","src/simd/mod.rs":"4fe941717937542c4c88eb95ffefb26db8492e4b5a1d46696fce0b5329702a21","src/simd/neon.rs":"fed66a5d37873dbf901ad2b69e9d08711c570a4a5fc958e13539808501ec9ac3","src/simd/runtime.rs":"fec921120b04042d9c3dbc78ced3477e112f16e4d06be68ac8d50ddce54b8da7","src/simd/sse42.rs":"04c1c6f29375eb87d0e7712deadd9ba3c94d20525b67ff869a266cc6b75cedf6","src/simd/swar.rs":"24d15cfaa7b1ac8f2a5ff74a590eb0e9f0c87de6058c2c65919e33f9f1923080","tests/uri.rs":"62664aa2db82b2b24174ef74b7b00b675806608bfcb64763f97b639b62dd3701"},"package":"6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"}
\ No newline at end of file diff --git a/vendor/httparse/Cargo.lock b/vendor/httparse/Cargo.lock deleted file mode 100644 index e898732e..00000000 --- a/vendor/httparse/Cargo.lock +++ /dev/null @@ -1,688 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "bitflags", - "textwrap", - "unicode-width", -] - -[[package]] -name = "criterion" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" -dependencies = [ - "atty", - "cast", - "clap", - "criterion-plot", - "csv", - "itertools", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_cbor", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" -dependencies = [ - "cast", - "itertools", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "once_cell", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr", - "csv-core", - "itoa 0.4.8", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - -[[package]] -name = "either" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "httparse" -version = "1.10.1" -dependencies = [ - "criterion", - "rand", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" - -[[package]] -name = "js-sys" -version = "0.3.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.169" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" - -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - -[[package]] -name = "plotters" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9428003b84df1496fb9d6eeee9c5f8145cb41ca375eb0dad204328888832811f" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" - -[[package]] -name = "plotters-svg" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0918736323d1baff32ee0eade54984f6f201ad7e97d5cfb5d6ab4a358529615" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro2" -version = "1.0.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rayon" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" -dependencies = [ - "autocfg", - "crossbeam-deque", - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "regex" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - -[[package]] -name = "regex-syntax" -version = "0.6.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "ryu" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "serde" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" - -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", -] - -[[package]] -name = "serde_json" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" -dependencies = [ - "itoa 1.0.2", - "ryu", - "serde", -] - -[[package]] -name = "syn" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "unicode-ident" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 1.0.98", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.98", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" - -[[package]] -name = "web-sys" -version = "0.3.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.96", -] diff --git a/vendor/httparse/Cargo.toml b/vendor/httparse/Cargo.toml deleted file mode 100644 index 6b7abb2c..00000000 --- a/vendor/httparse/Cargo.toml +++ /dev/null @@ -1,77 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2018" -name = "httparse" -version = "1.10.1" -authors = ["Sean McArthur <sean@seanmonstar.com>"] -build = "build.rs" -autolib = false -autobins = false -autoexamples = false -autotests = false -autobenches = false -description = "A tiny, safe, speedy, zero-copy HTTP/1.x parser." -documentation = "https://docs.rs/httparse" -readme = "README.md" -keywords = [ - "http", - "parser", - "no_std", -] -categories = [ - "network-programming", - "no-std", - "parser-implementations", - "web-programming", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/seanmonstar/httparse" - -[features] -default = ["std"] -std = [] - -[lib] -name = "httparse" -path = "src/lib.rs" -bench = false - -[[test]] -name = "uri" -path = "tests/uri.rs" - -[[bench]] -name = "parse" -path = "benches/parse.rs" -harness = false - -[dev-dependencies.criterion] -version = "0.3.5" - -[dev-dependencies.rand] -version = "0.8.5" - -[lints.rust.unexpected_cfgs] -level = "warn" -priority = 0 -check-cfg = [ - "cfg(httparse_simd)", - "cfg(httparse_simd_target_feature_avx2)", - "cfg(httparse_simd_target_feature_sse42)", - "cfg(httparse_simd_neon_intrinsics)", -] - -[profile.bench] -opt-level = 3 -lto = true -codegen-units = 1 diff --git a/vendor/httparse/LICENSE-APACHE b/vendor/httparse/LICENSE-APACHE deleted file mode 100644 index 16fe87b0..00000000 --- a/vendor/httparse/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/httparse/LICENSE-MIT b/vendor/httparse/LICENSE-MIT deleted file mode 100644 index 5e854c5f..00000000 --- a/vendor/httparse/LICENSE-MIT +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2015-2025 Sean McArthur - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/vendor/httparse/README.md b/vendor/httparse/README.md deleted file mode 100644 index ce79aa60..00000000 --- a/vendor/httparse/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# httparse - -[](https://crates.io/crates/httparse) -[](https://docs.rs/httparse) -[](./LICENSE-MIT) -[](https://github.com/seanmonstar/httparse/actions?query=workflow%3ACI) -[![Discord chat][discord-badge]][discord-url] - -A push parser for the HTTP 1.x protocol. Avoids allocations. No copy. **Fast.** - -Works with `no_std`, simply disable the `std` Cargo feature. - -[Changelog](https://github.com/seanmonstar/httparse/releases) - - -[discord-badge]: https://img.shields.io/discord/500028886025895936.svg?logo=discord -[discord-url]: https://discord.gg/kkwpueZ - -## Usage - -```rust -let mut headers = [httparse::EMPTY_HEADER; 64]; -let mut req = httparse::Request::new(&mut headers); - -let buf = b"GET /index.html HTTP/1.1\r\nHost"; -assert!(req.parse(buf)?.is_partial()); - -// a partial request, so we try again once we have more data - -let buf = b"GET /index.html HTTP/1.1\r\nHost: example.domain\r\n\r\n"; -assert!(req.parse(buf)?.is_complete()); -``` - -## License - -Licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or https://apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT) - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/vendor/httparse/benches/parse.rs b/vendor/httparse/benches/parse.rs deleted file mode 100644 index 7794d31d..00000000 --- a/vendor/httparse/benches/parse.rs +++ /dev/null @@ -1,242 +0,0 @@ -use std::time::Duration; - -use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput, BatchSize}; - -const REQ_SHORT: &[u8] = b"\ -GET / HTTP/1.0\r\n\ -Host: example.com\r\n\ -Cookie: session=60; user_id=1\r\n\r\n"; - -const REQ: &[u8] = b"\ -GET /wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg HTTP/1.1\r\n\ -Host: www.kittyhell.com\r\n\ -User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; ja-JP-mac; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 Pathtraq/0.9\r\n\ -Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n\ -Accept-Language: ja,en-us;q=0.7,en;q=0.3\r\n\ -Accept-Encoding: gzip,deflate\r\n\ -Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\r\n\ -Keep-Alive: 115\r\n\ -Connection: keep-alive\r\n\ -Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; __utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; __utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral|padding=under256\r\n\r\n"; - -fn req(c: &mut Criterion) { - c.benchmark_group("req") - .throughput(Throughput::Bytes(REQ.len() as u64)) - .bench_function("req", |b| b.iter_batched_ref(|| { - [httparse::Header { - name: "", - value: &[], - }; 16] - },|headers| { - let mut req = httparse::Request::new(headers); - assert_eq!( - black_box(req.parse(REQ).unwrap()), - httparse::Status::Complete(REQ.len()) - ); - }, BatchSize::SmallInput)); -} - -fn req_short(c: &mut Criterion) { - c.benchmark_group("req_short") - .throughput(Throughput::Bytes(REQ_SHORT.len() as u64)) - .bench_function("req_short", |b| b.iter_batched_ref(|| { - [httparse::Header { - name: "", - value: &[], - }; 16] - },|headers| { - let mut req = httparse::Request::new(headers); - assert_eq!( - req.parse(black_box(REQ_SHORT)).unwrap(), - httparse::Status::Complete(REQ_SHORT.len()) - ); - }, BatchSize::SmallInput)); -} - -const RESP_SHORT: &[u8] = b"\ -HTTP/1.0 200 OK\r\n\ -Date: Wed, 21 Oct 2015 07:28:00 GMT\r\n\ -Set-Cookie: session=60; user_id=1\r\n\r\n"; - -// These particular headers don't all make semantic sense for a response, but they're syntactically valid. -const RESP: &[u8] = b"\ -HTTP/1.1 200 OK\r\n\ -Date: Wed, 21 Oct 2015 07:28:00 GMT\r\n\ -Host: www.kittyhell.com\r\n\ -User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; ja-JP-mac; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 Pathtraq/0.9\r\n\ -Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n\ -Accept-Language: ja,en-us;q=0.7,en;q=0.3\r\n\ -Accept-Encoding: gzip,deflate\r\n\ -Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\r\n\ -Keep-Alive: 115\r\n\ -Connection: keep-alive\r\n\ -Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; __utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; __utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral|padding=under256\r\n\r\n"; - -fn resp(c: &mut Criterion) { - c.benchmark_group("resp") - .throughput(Throughput::Bytes(RESP.len() as u64)) - .bench_function("resp", |b| b.iter_batched_ref(|| { - [httparse::Header { - name: "", - value: &[], - }; 16] - }, |headers| { - let mut resp = httparse::Response::new(headers); - assert_eq!( - resp.parse(black_box(RESP)).unwrap(), - httparse::Status::Complete(RESP.len()) - ); - }, BatchSize::SmallInput)); -} - -fn resp_short(c: &mut Criterion) { - c.benchmark_group("resp_short") - .throughput(Throughput::Bytes(RESP_SHORT.len() as u64)) - .bench_function("resp_short", |b| b.iter_batched_ref(|| { - [httparse::Header { - name: "", - value: &[], - }; 16] - }, - |headers| { - let mut resp = httparse::Response::new(headers); - assert_eq!( - resp.parse(black_box(RESP_SHORT)).unwrap(), - httparse::Status::Complete(RESP_SHORT.len()) - ); - }, BatchSize::SmallInput)); -} - -fn uri(c: &mut Criterion) { - fn _uri(c: &mut Criterion, name: &str, input: &'static [u8]) { - c.benchmark_group("uri") - .throughput(Throughput::Bytes(input.len() as u64)) - .bench_function(name, |b| b.iter(|| { - let mut b = httparse::_benchable::Bytes::new(black_box(input)); - httparse::_benchable::parse_uri(&mut b).unwrap() - })); - } - - const S: &[u8] = b" "; - const CHUNK64: &[u8] = b"/wp-content/uploads/2022/08/31/hello-kitty-darth-vader-pink.webp"; - let chunk_4k = CHUNK64.repeat(64); - - // 1b to 4096b - for p in 0..=12 { - let n = 1 << p; - _uri(c, &format!("uri_{:04}b", n), [chunk_4k[..n].to_vec(), S.into()].concat().leak()); - } -} - -fn header(c: &mut Criterion) { - fn _header(c: &mut Criterion, name: &str, input: &'static [u8]) { - c.benchmark_group("header") - .throughput(Throughput::Bytes(input.len() as u64)) - .bench_function(name, |b| b.iter_batched_ref(|| [httparse::EMPTY_HEADER; 128],|headers| { - let status = httparse::parse_headers(black_box(input), headers).unwrap(); - black_box(status.unwrap()).0 - }, BatchSize::SmallInput)); - } - - const RN: &[u8] = b"\r\n"; - const RNRN: &[u8] = b"\r\n\r\n"; - const TINY_RN: &[u8] = b"a: b\r\n"; // minimal header line - const XFOOBAR: &[u8] = b"X-Foobar"; - let xfoobar_4k = XFOOBAR.repeat(4096/XFOOBAR.len()); - - // header names 1b to 4096b - for p in 0..=12 { - let n = 1 << p; - let payload = [&xfoobar_4k[..n], b": b", RNRN].concat().leak(); - _header(c, &format!("name_{:04}b", n), payload); - } - - // header values 1b to 4096b - for p in 0..=12 { - let n = 1 << p; - let payload = [b"a: ", &xfoobar_4k[..n], RNRN].concat().leak(); - _header(c, &format!("value_{:04}b", n), payload); - } - - // 1 to 128 - for p in 0..=7 { - let n = 1 << p; - _header(c, &format!("count_{:03}", n), [TINY_RN.repeat(n), RN.into()].concat().leak()); - } -} - -fn version(c: &mut Criterion) { - fn _version(c: &mut Criterion, name: &str, input: &'static [u8]) { - c.benchmark_group("version") - .throughput(Throughput::Bytes(input.len() as u64)) - .bench_function(name, |b| b.iter(|| { - let mut b = httparse::_benchable::Bytes::new(black_box(input)); - httparse::_benchable::parse_version(&mut b).unwrap() - })); - } - - _version(c, "http10", b"HTTP/1.0\r\n"); - _version(c, "http11", b"HTTP/1.1\r\n"); - _version(c, "partial", b"HTTP/1."); -} - -fn method(c: &mut Criterion) { - fn _method(c: &mut Criterion, name: &str, input: &[u8]) { - c.benchmark_group("method") - .throughput(Throughput::Bytes(input.len() as u64)) - .bench_function(name, |b| b.iter(|| { - let mut b = httparse::_benchable::Bytes::new(black_box(input)); - httparse::_benchable::parse_method(&mut b).unwrap() - })); - } - - // Common methods should be fast-pathed - const COMMON_METHODS: &[&str] = &["GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"]; - for method in COMMON_METHODS { - _method(c, &method.to_lowercase(), format!("{} / HTTP/1.1\r\n", method).as_bytes()); - } - // Custom methods should be infrequent and thus not worth optimizing - _method(c, "custom", b"CUSTOM / HTTP/1.1\r\n"); - _method(c, "w3!rd", b"w3!rd / HTTP/1.1\r\n"); -} - -fn many_requests(c: &mut Criterion) { - use rand::{rngs::StdRng, seq::SliceRandom, SeedableRng}; - let mut requests = [ - ("GET", 500), - ("POST", 300), - ("OPTIONS", 100), - ("HEAD", 50), - ("w3!r`d", 20), - ] - .iter() - .flat_map(|&(method, count)| std::iter::repeat(method).take(count)) - .map(|method| format!("{method} / HTTP/1.1\r\n\r\n")) - .collect::<Vec<_>>(); - SliceRandom::shuffle(&mut *requests, &mut StdRng::seed_from_u64(0)); - - let total_bytes: usize = requests.iter().map(String::len).sum(); - - c.benchmark_group("many_requests") - .throughput(Throughput::Bytes(total_bytes as u64)) - .measurement_time(Duration::from_secs(1)) - .sample_size(1000) - .bench_function("_", |b| { - b.iter(|| { - requests.iter().for_each(|req| { - let mut b = httparse::_benchable::Bytes::new(black_box(req.as_bytes())); - httparse::_benchable::parse_method(&mut b).unwrap(); - }); - }) - }); -} - -const WARMUP: Duration = Duration::from_millis(100); -const MTIME: Duration = Duration::from_millis(100); -const SAMPLES: usize = 200; -criterion_group!{ - name = benches; - config = Criterion::default().sample_size(SAMPLES).warm_up_time(WARMUP).measurement_time(MTIME); - targets = req, req_short, resp, resp_short, uri, header, version, method, many_requests -} -criterion_main!(benches); diff --git a/vendor/httparse/build.rs b/vendor/httparse/build.rs deleted file mode 100644 index bffcedb6..00000000 --- a/vendor/httparse/build.rs +++ /dev/null @@ -1,133 +0,0 @@ -use std::env; -use std::ffi::OsString; -use std::process::Command; - -fn main() { - // We check rustc version to enable features beyond MSRV, such as: - // - 1.59 => neon_intrinsics - let rustc = env::var_os("RUSTC").unwrap_or(OsString::from("rustc")); - let output = Command::new(rustc) - .arg("--version") - .output() - .expect("failed to check 'rustc --version'") - .stdout; - - let raw_version = String::from_utf8(output) - .expect("rustc version output should be utf-8"); - - let version = match Version::parse(&raw_version) { - Ok(version) => version, - Err(err) => { - println!("cargo:warning=failed to parse `rustc --version`: {}", err); - return; - } - }; - - enable_new_features(version); -} - -fn enable_new_features(version: Version) { - enable_simd(version); -} - -fn enable_simd(version: Version) { - if env::var_os("CARGO_FEATURE_STD").is_none() { - println!("cargo:warning=building for no_std disables httparse SIMD"); - return; - } - if env::var_os("CARGO_CFG_MIRI").is_some() { - println!("cargo:warning=building for Miri disables httparse SIMD"); - return; - } - - let env_disable = "CARGO_CFG_HTTPARSE_DISABLE_SIMD"; - if var_is(env_disable, "1") { - println!("cargo:warning=detected {} environment variable, disabling SIMD", env_disable); - return; - } - - // 1.59.0 is the first version to support neon_intrinsics - if version >= Version(1, 59, 0) { - println!("cargo:rustc-cfg=httparse_simd_neon_intrinsics"); - } - - println!("cargo:rustc-cfg=httparse_simd"); - - // cfg(target_feature) isn't stable yet, but CARGO_CFG_TARGET_FEATURE has - // a list... We aren't doing anything unsafe, since the is_x86_feature_detected - // macro still checks in the actual lib, BUT! - // - // By peeking at the list here, we can change up slightly how we do feature - // detection in the lib. If our features aren't in the feature list, we - // stick with a cached runtime detection strategy. - // - // But if the features *are* in the list, we benefit from removing our cache, - // since the compiler will eliminate several branches with its internal - // cfg(target_feature) usage. - - - let env_runtime_only = "CARGO_CFG_HTTPARSE_DISABLE_SIMD_COMPILETIME"; - if var_is(env_runtime_only, "1") { - println!("cargo:warning=detected {} environment variable, using runtime SIMD detection only", env_runtime_only); - return; - } - let feature_list = match env::var_os("CARGO_CFG_TARGET_FEATURE") { - Some(var) => match var.into_string() { - Ok(s) => s, - Err(_) => { - println!("cargo:warning=CARGO_CFG_TARGET_FEATURE was not valid utf-8"); - return; - }, - }, - None => { - println!("cargo:warning=CARGO_CFG_TARGET_FEATURE was not set"); - return - }, - }; - - let features = feature_list.split(',').map(|s| s.trim()); - if features.clone().any(|f| f == "sse4.2") { - println!("cargo:rustc-cfg=httparse_simd_target_feature_sse42"); - } - if features.clone().any(|f| f == "avx2") { - println!("cargo:rustc-cfg=httparse_simd_target_feature_avx2"); - } -} - -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -struct Version (u32, u32, u32); - -impl Version { - fn parse(s: &str) -> Result<Version, String> { - if !s.starts_with("rustc ") { - return Err(format!("unrecognized version string: {}", s)); - } - let s = s.trim_start_matches("rustc "); - - let mut iter = s - .split('.') - .take(3) - .map(|s| match s.find(|c: char| !c.is_ascii_digit()) { - Some(end) => &s[..end], - None => s, - }) - .map(|s| s.parse::<u32>().map_err(|e| e.to_string())); - - if iter.clone().count() != 3 { - return Err(format!("not enough version parts: {:?}", s)); - } - - let major = iter.next().unwrap()?; - let minor = iter.next().unwrap()?; - let patch = iter.next().unwrap()?; - - Ok(Version(major, minor, patch)) - } -} - -fn var_is(key: &str, val: &str) -> bool { - match env::var(key) { - Ok(v) => v == val, - Err(_) => false, - } -} diff --git a/vendor/httparse/clippy.toml b/vendor/httparse/clippy.toml deleted file mode 100644 index 7846a3e0..00000000 --- a/vendor/httparse/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -msrv = "1.47" diff --git a/vendor/httparse/src/iter.rs b/vendor/httparse/src/iter.rs deleted file mode 100644 index 98c1d7bc..00000000 --- a/vendor/httparse/src/iter.rs +++ /dev/null @@ -1,199 +0,0 @@ -use core::convert::TryFrom; -use core::convert::TryInto; - -#[allow(missing_docs)] -pub struct Bytes<'a> { - start: *const u8, - end: *const u8, - /// INVARIANT: start <= cursor && cursor <= end - cursor: *const u8, - phantom: core::marker::PhantomData<&'a ()>, -} - -#[allow(missing_docs)] -impl<'a> Bytes<'a> { - #[inline] - pub fn new(slice: &'a [u8]) -> Bytes<'a> { - let start = slice.as_ptr(); - // SAFETY: obtain pointer to slice end; start points to slice start. - let end = unsafe { start.add(slice.len()) }; - let cursor = start; - Bytes { - start, - end, - cursor, - phantom: core::marker::PhantomData, - } - } - - #[inline] - pub fn pos(&self) -> usize { - self.cursor as usize - self.start as usize - } - - #[inline] - pub fn peek(&self) -> Option<u8> { - if self.cursor < self.end { - // SAFETY: bounds checked - Some(unsafe { *self.cursor }) - } else { - None - } - } - - /// Peek at byte `n` ahead of cursor - /// - /// # Safety - /// - /// Caller must ensure that `n <= self.len()`, otherwise `self.cursor.add(n)` is UB. - /// That means there are at least `n-1` bytes between `self.cursor` and `self.end` - /// and `self.cursor.add(n)` is either `self.end` or points to a valid byte. - #[inline] - pub unsafe fn peek_ahead(&self, n: usize) -> Option<u8> { - debug_assert!(n <= self.len()); - // SAFETY: by preconditions - let p = unsafe { self.cursor.add(n) }; - if p < self.end { - // SAFETY: by preconditions, if this is not `self.end`, - // then it is safe to dereference - Some(unsafe { *p }) - } else { - None - } - } - - #[inline] - pub fn peek_n<'b: 'a, U: TryFrom<&'a [u8]>>(&'b self, n: usize) -> Option<U> { - // TODO: once we bump MSRC, use const generics to allow only [u8; N] reads - // TODO: drop `n` arg in favour of const - // let n = core::mem::size_of::<U>(); - self.as_ref().get(..n)?.try_into().ok() - } - - /// Advance by 1, equivalent to calling `advance(1)`. - /// - /// # Safety - /// - /// Caller must ensure that Bytes hasn't been advanced/bumped by more than [`Bytes::len()`]. - #[inline] - pub unsafe fn bump(&mut self) { - self.advance(1) - } - - /// Advance cursor by `n` - /// - /// # Safety - /// - /// Caller must ensure that Bytes hasn't been advanced/bumped by more than [`Bytes::len()`]. - #[inline] - pub unsafe fn advance(&mut self, n: usize) { - self.cursor = self.cursor.add(n); - debug_assert!(self.cursor <= self.end, "overflow"); - } - - #[inline] - pub fn len(&self) -> usize { - self.end as usize - self.cursor as usize - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - #[inline] - pub fn slice(&mut self) -> &'a [u8] { - // SAFETY: not moving position at all, so it's safe - let slice = unsafe { slice_from_ptr_range(self.start, self.cursor) }; - self.commit(); - slice - } - - // TODO: this is an anti-pattern, should be removed - /// Deprecated. Do not use! - /// # Safety - /// - /// Caller must ensure that `skip` is at most the number of advances (i.e., `bytes.advance(3)` - /// implies a skip of at most 3). - #[inline] - pub unsafe fn slice_skip(&mut self, skip: usize) -> &'a [u8] { - debug_assert!(skip <= self.cursor.offset_from(self.start) as usize); - let head = slice_from_ptr_range(self.start, self.cursor.sub(skip)); - self.commit(); - head - } - - #[inline] - pub fn commit(&mut self) { - self.start = self.cursor - } - - /// # Safety - /// - /// see [`Bytes::advance`] safety comment. - #[inline] - pub unsafe fn advance_and_commit(&mut self, n: usize) { - self.advance(n); - self.commit(); - } - - #[inline] - pub fn as_ptr(&self) -> *const u8 { - self.cursor - } - - #[inline] - pub fn start(&self) -> *const u8 { - self.start - } - - #[inline] - pub fn end(&self) -> *const u8 { - self.end - } - - /// # Safety - /// - /// Must ensure invariant `bytes.start() <= ptr && ptr <= bytes.end()`. - #[inline] - pub unsafe fn set_cursor(&mut self, ptr: *const u8) { - debug_assert!(ptr >= self.start); - debug_assert!(ptr <= self.end); - self.cursor = ptr; - } -} - -impl AsRef<[u8]> for Bytes<'_> { - #[inline] - fn as_ref(&self) -> &[u8] { - // SAFETY: not moving position at all, so it's safe - unsafe { slice_from_ptr_range(self.cursor, self.end) } - } -} - -/// # Safety -/// -/// Must ensure start and end point to the same memory object to uphold memory safety. -#[inline] -unsafe fn slice_from_ptr_range<'a>(start: *const u8, end: *const u8) -> &'a [u8] { - debug_assert!(start <= end); - core::slice::from_raw_parts(start, end as usize - start as usize) -} - -impl Iterator for Bytes<'_> { - type Item = u8; - - #[inline] - fn next(&mut self) -> Option<u8> { - if self.cursor < self.end { - // SAFETY: bounds checked dereference - unsafe { - let b = *self.cursor; - self.bump(); - Some(b) - } - } else { - None - } - } -} diff --git a/vendor/httparse/src/lib.rs b/vendor/httparse/src/lib.rs deleted file mode 100644 index 06bc4df5..00000000 --- a/vendor/httparse/src/lib.rs +++ /dev/null @@ -1,2798 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] -#![deny( - missing_docs, - clippy::missing_safety_doc, - clippy::undocumented_unsafe_blocks -)] -#![cfg_attr(test, deny(warnings))] - -//! # httparse -//! -//! A push library for parsing HTTP/1.x requests and responses. -//! -//! The focus is on speed and safety. Unsafe code is used to keep parsing fast, -//! but unsafety is contained in a submodule, with invariants enforced. The -//! parsing internals use an `Iterator` instead of direct indexing, while -//! skipping bounds checks. -//! -//! With Rust 1.27.0 or later, support for SIMD is enabled automatically. -//! If building an executable to be run on multiple platforms, and thus -//! not passing `target_feature` or `target_cpu` flags to the compiler, -//! runtime detection can still detect SSE4.2 or AVX2 support to provide -//! massive wins. -//! -//! If compiling for a specific target, remembering to include -//! `-C target_cpu=native` allows the detection to become compile time checks, -//! making it *even* faster. - -use core::{fmt, mem, result, str}; -use core::mem::MaybeUninit; - -use crate::iter::Bytes; - -mod iter; -#[macro_use] mod macros; -mod simd; - -#[doc(hidden)] -// Expose some internal functions so we can bench them individually -// WARNING: Exported for internal benchmarks, not fit for public consumption -pub mod _benchable { - pub use super::parse_uri; - pub use super::parse_version; - pub use super::parse_method; - pub use super::iter::Bytes; -} - -/// Determines if byte is a method token char. -/// -/// > ```notrust -/// > token = 1*tchar -/// > -/// > tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" -/// > / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" -/// > / DIGIT / ALPHA -/// > ; any VCHAR, except delimiters -/// > ``` -#[inline] -fn is_method_token(b: u8) -> bool { - match b { - // For the majority case, this can be faster than the table lookup. - b'A'..=b'Z' => true, - _ => TOKEN_MAP[b as usize], - } -} - -// char codes to accept URI string. -// i.e. b'!' <= char and char != 127 -// TODO: Make a stricter checking for URI string? -static URI_MAP: [bool; 256] = byte_map!( - b'!'..=0x7e | 0x80..=0xFF -); - -#[inline] -pub(crate) fn is_uri_token(b: u8) -> bool { - URI_MAP[b as usize] -} - -static TOKEN_MAP: [bool; 256] = byte_map!( - b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | - b'!' | b'#' | b'$' | b'%' | b'&' | b'\'' | b'*' | b'+' | - b'-' | b'.' | b'^' | b'_' | b'`' | b'|' | b'~' -); - -#[inline] -pub(crate) fn is_header_name_token(b: u8) -> bool { - TOKEN_MAP[b as usize] -} - - -static HEADER_VALUE_MAP: [bool; 256] = byte_map!( - b'\t' | b' '..=0x7e | 0x80..=0xFF -); - - -#[inline] -pub(crate) fn is_header_value_token(b: u8) -> bool { - HEADER_VALUE_MAP[b as usize] -} - -/// An error in parsing. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum Error { - /// Invalid byte in header name. - HeaderName, - /// Invalid byte in header value. - HeaderValue, - /// Invalid byte in new line. - NewLine, - /// Invalid byte in Response status. - Status, - /// Invalid byte where token is required. - Token, - /// Parsed more headers than provided buffer can contain. - TooManyHeaders, - /// Invalid byte in HTTP version. - Version, -} - -impl Error { - #[inline] - fn description_str(&self) -> &'static str { - match *self { - Error::HeaderName => "invalid header name", - Error::HeaderValue => "invalid header value", - Error::NewLine => "invalid new line", - Error::Status => "invalid response status", - Error::Token => "invalid token", - Error::TooManyHeaders => "too many headers", - Error::Version => "invalid HTTP version", - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.description_str()) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for Error { - fn description(&self) -> &str { - self.description_str() - } -} - -/// An error in parsing a chunk size. -// Note: Move this into the error enum once v2.0 is released. -#[derive(Debug, PartialEq, Eq)] -pub struct InvalidChunkSize; - -impl fmt::Display for InvalidChunkSize { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("invalid chunk size") - } -} - -/// A Result of any parsing action. -/// -/// If the input is invalid, an `Error` will be returned. Note that incomplete -/// data is not considered invalid, and so will not return an error, but rather -/// a `Ok(Status::Partial)`. -pub type Result<T> = result::Result<Status<T>, Error>; - -/// The result of a successful parse pass. -/// -/// `Complete` is used when the buffer contained the complete value. -/// `Partial` is used when parsing did not reach the end of the expected value, -/// but no invalid data was found. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum Status<T> { - /// The completed result. - Complete(T), - /// A partial result. - Partial -} - -impl<T> Status<T> { - /// Convenience method to check if status is complete. - #[inline] - pub fn is_complete(&self) -> bool { - match *self { - Status::Complete(..) => true, - Status::Partial => false - } - } - - /// Convenience method to check if status is partial. - #[inline] - pub fn is_partial(&self) -> bool { - match *self { - Status::Complete(..) => false, - Status::Partial => true - } - } - - /// Convenience method to unwrap a Complete value. Panics if the status is - /// `Partial`. - #[inline] - pub fn unwrap(self) -> T { - match self { - Status::Complete(t) => t, - Status::Partial => panic!("Tried to unwrap Status::Partial") - } - } -} - -/// Parser configuration. -#[derive(Clone, Debug, Default)] -pub struct ParserConfig { - allow_spaces_after_header_name_in_responses: bool, - allow_obsolete_multiline_headers_in_responses: bool, - allow_multiple_spaces_in_request_line_delimiters: bool, - allow_multiple_spaces_in_response_status_delimiters: bool, - allow_space_before_first_header_name: bool, - ignore_invalid_headers_in_responses: bool, - ignore_invalid_headers_in_requests: bool, -} - -impl ParserConfig { - /// Sets whether spaces and tabs should be allowed after header names in responses. - pub fn allow_spaces_after_header_name_in_responses( - &mut self, - value: bool, - ) -> &mut Self { - self.allow_spaces_after_header_name_in_responses = value; - self - } - - /// Sets whether multiple spaces are allowed as delimiters in request lines. - /// - /// # Background - /// - /// The [latest version of the HTTP/1.1 spec][spec] allows implementations to parse multiple - /// whitespace characters in place of the `SP` delimiters in the request line, including: - /// - /// > SP, HTAB, VT (%x0B), FF (%x0C), or bare CR - /// - /// This option relaxes the parser to allow for multiple spaces, but does *not* allow the - /// request line to contain the other mentioned whitespace characters. - /// - /// [spec]: https://httpwg.org/http-core/draft-ietf-httpbis-messaging-latest.html#rfc.section.3.p.3 - pub fn allow_multiple_spaces_in_request_line_delimiters(&mut self, value: bool) -> &mut Self { - self.allow_multiple_spaces_in_request_line_delimiters = value; - self - } - - /// Whether multiple spaces are allowed as delimiters in request lines. - pub fn multiple_spaces_in_request_line_delimiters_are_allowed(&self) -> bool { - self.allow_multiple_spaces_in_request_line_delimiters - } - - /// Sets whether multiple spaces are allowed as delimiters in response status lines. - /// - /// # Background - /// - /// The [latest version of the HTTP/1.1 spec][spec] allows implementations to parse multiple - /// whitespace characters in place of the `SP` delimiters in the response status line, - /// including: - /// - /// > SP, HTAB, VT (%x0B), FF (%x0C), or bare CR - /// - /// This option relaxes the parser to allow for multiple spaces, but does *not* allow the status - /// line to contain the other mentioned whitespace characters. - /// - /// [spec]: https://httpwg.org/http-core/draft-ietf-httpbis-messaging-latest.html#rfc.section.4.p.3 - pub fn allow_multiple_spaces_in_response_status_delimiters(&mut self, value: bool) -> &mut Self { - self.allow_multiple_spaces_in_response_status_delimiters = value; - self - } - - /// Whether multiple spaces are allowed as delimiters in response status lines. - pub fn multiple_spaces_in_response_status_delimiters_are_allowed(&self) -> bool { - self.allow_multiple_spaces_in_response_status_delimiters - } - - /// Sets whether obsolete multiline headers should be allowed. - /// - /// This is an obsolete part of HTTP/1. Use at your own risk. If you are - /// building an HTTP library, the newlines (`\r` and `\n`) should be - /// replaced by spaces before handing the header value to the user. - /// - /// # Example - /// - /// ```rust - /// let buf = b"HTTP/1.1 200 OK\r\nFolded-Header: hello\r\n there \r\n\r\n"; - /// let mut headers = [httparse::EMPTY_HEADER; 16]; - /// let mut response = httparse::Response::new(&mut headers); - /// - /// let res = httparse::ParserConfig::default() - /// .allow_obsolete_multiline_headers_in_responses(true) - /// .parse_response(&mut response, buf); - /// - /// assert_eq!(res, Ok(httparse::Status::Complete(buf.len()))); - /// - /// assert_eq!(response.headers.len(), 1); - /// assert_eq!(response.headers[0].name, "Folded-Header"); - /// assert_eq!(response.headers[0].value, b"hello\r\n there"); - /// ``` - pub fn allow_obsolete_multiline_headers_in_responses( - &mut self, - value: bool, - ) -> &mut Self { - self.allow_obsolete_multiline_headers_in_responses = value; - self - } - - /// Whether obsolete multiline headers should be allowed. - pub fn obsolete_multiline_headers_in_responses_are_allowed(&self) -> bool { - self.allow_obsolete_multiline_headers_in_responses - } - - /// Sets whether white space before the first header is allowed - /// - /// This is not allowed by spec but some browsers ignore it. So this an option for - /// compatibility. - /// See https://github.com/curl/curl/issues/11605 for reference - /// # Example - /// - /// ```rust - /// let buf = b"HTTP/1.1 200 OK\r\n Space-Before-Header: hello there\r\n\r\n"; - /// let mut headers = [httparse::EMPTY_HEADER; 1]; - /// let mut response = httparse::Response::new(&mut headers[..]); - /// let result = httparse::ParserConfig::default() - /// .allow_space_before_first_header_name(true) - /// .parse_response(&mut response, buf); - /// - /// assert_eq!(result, Ok(httparse::Status::Complete(buf.len()))); - /// assert_eq!(response.version.unwrap(), 1); - /// assert_eq!(response.code.unwrap(), 200); - /// assert_eq!(response.reason.unwrap(), "OK"); - /// assert_eq!(response.headers.len(), 1); - /// assert_eq!(response.headers[0].name, "Space-Before-Header"); - /// assert_eq!(response.headers[0].value, &b"hello there"[..]); - /// ``` - pub fn allow_space_before_first_header_name(&mut self, value: bool) -> &mut Self { - self.allow_space_before_first_header_name = value; - self - } - - /// Whether white space before first header is allowed or not - pub fn space_before_first_header_name_are_allowed(&self) -> bool { - self.allow_space_before_first_header_name - } - - /// Parses a request with the given config. - pub fn parse_request<'buf>( - &self, - request: &mut Request<'_, 'buf>, - buf: &'buf [u8], - ) -> Result<usize> { - request.parse_with_config(buf, self) - } - - /// Parses a request with the given config and buffer for headers - pub fn parse_request_with_uninit_headers<'headers, 'buf>( - &self, - request: &mut Request<'headers, 'buf>, - buf: &'buf [u8], - headers: &'headers mut [MaybeUninit<Header<'buf>>], - ) -> Result<usize> { - request.parse_with_config_and_uninit_headers(buf, self, headers) - } - - /// Sets whether invalid header lines should be silently ignored in responses. - /// - /// This mimicks the behaviour of major browsers. You probably don't want this. - /// You should only want this if you are implementing a proxy whose main - /// purpose is to sit in front of browsers whose users access arbitrary content - /// which may be malformed, and they expect everything that works without - /// the proxy to keep working with the proxy. - /// - /// This option will prevent `ParserConfig::parse_response` from returning - /// an error encountered when parsing a header, except if the error was caused - /// by the character NUL (ASCII code 0), as Chrome specifically always reject - /// those, or if the error was caused by a lone character `\r`, as Firefox and - /// Chrome behave differently in that case. - /// - /// The ignorable errors are: - /// * empty header names; - /// * characters that are not allowed in header names, except for `\0` and `\r`; - /// * when `allow_spaces_after_header_name_in_responses` is not enabled, - /// spaces and tabs between the header name and the colon; - /// * missing colon between header name and value; - /// * when `allow_obsolete_multiline_headers_in_responses` is not enabled, - /// headers using obsolete line folding. - /// * characters that are not allowed in header values except for `\0` and `\r`. - /// - /// If an ignorable error is encountered, the parser tries to find the next - /// line in the input to resume parsing the rest of the headers. As lines - /// contributing to a header using obsolete line folding always start - /// with whitespace, those will be ignored too. An error will be emitted - /// nonetheless if it finds `\0` or a lone `\r` while looking for the - /// next line. - pub fn ignore_invalid_headers_in_responses( - &mut self, - value: bool, - ) -> &mut Self { - self.ignore_invalid_headers_in_responses = value; - self - } - - /// Sets whether invalid header lines should be silently ignored in requests. - pub fn ignore_invalid_headers_in_requests( - &mut self, - value: bool, - ) -> &mut Self { - self.ignore_invalid_headers_in_requests = value; - self - } - - /// Parses a response with the given config. - pub fn parse_response<'buf>( - &self, - response: &mut Response<'_, 'buf>, - buf: &'buf [u8], - ) -> Result<usize> { - response.parse_with_config(buf, self) - } - - /// Parses a response with the given config and buffer for headers - pub fn parse_response_with_uninit_headers<'headers, 'buf>( - &self, - response: &mut Response<'headers, 'buf>, - buf: &'buf [u8], - headers: &'headers mut [MaybeUninit<Header<'buf>>], - ) -> Result<usize> { - response.parse_with_config_and_uninit_headers(buf, self, headers) - } -} - -/// A parsed Request. -/// -/// The optional values will be `None` if a parse was not complete, and did not -/// parse the associated property. This allows you to inspect the parts that -/// could be parsed, before reading more, in case you wish to exit early. -/// -/// # Example -/// -/// ```no_run -/// let buf = b"GET /404 HTTP/1.1\r\nHost:"; -/// let mut headers = [httparse::EMPTY_HEADER; 16]; -/// let mut req = httparse::Request::new(&mut headers); -/// let res = req.parse(buf).unwrap(); -/// if res.is_partial() { -/// match req.path { -/// Some(ref path) => { -/// // check router for path. -/// // /404 doesn't exist? we could stop parsing -/// }, -/// None => { -/// // must read more and parse again -/// } -/// } -/// } -/// ``` -#[derive(Debug, Eq, PartialEq)] -pub struct Request<'headers, 'buf> { - /// The request method, such as `GET`. - pub method: Option<&'buf str>, - /// The request path, such as `/about-us`. - pub path: Option<&'buf str>, - /// The request minor version, such as `1` for `HTTP/1.1`. - pub version: Option<u8>, - /// The request headers. - pub headers: &'headers mut [Header<'buf>] -} - -impl<'h, 'b> Request<'h, 'b> { - /// Creates a new Request, using a slice of headers you allocate. - #[inline] - pub fn new(headers: &'h mut [Header<'b>]) -> Request<'h, 'b> { - Request { - method: None, - path: None, - version: None, - headers, - } - } - - fn parse_with_config_and_uninit_headers( - &mut self, - buf: &'b [u8], - config: &ParserConfig, - mut headers: &'h mut [MaybeUninit<Header<'b>>], - ) -> Result<usize> { - let orig_len = buf.len(); - let mut bytes = Bytes::new(buf); - complete!(skip_empty_lines(&mut bytes)); - let method = complete!(parse_method(&mut bytes)); - self.method = Some(method); - if config.allow_multiple_spaces_in_request_line_delimiters { - complete!(skip_spaces(&mut bytes)); - } - self.path = Some(complete!(parse_uri(&mut bytes))); - if config.allow_multiple_spaces_in_request_line_delimiters { - complete!(skip_spaces(&mut bytes)); - } - self.version = Some(complete!(parse_version(&mut bytes))); - newline!(bytes); - - let len = orig_len - bytes.len(); - let headers_len = complete!(parse_headers_iter_uninit( - &mut headers, - &mut bytes, - &HeaderParserConfig { - allow_spaces_after_header_name: false, - allow_obsolete_multiline_headers: false, - allow_space_before_first_header_name: config.allow_space_before_first_header_name, - ignore_invalid_headers: config.ignore_invalid_headers_in_requests - }, - )); - /* SAFETY: see `parse_headers_iter_uninit` guarantees */ - self.headers = unsafe { assume_init_slice(headers) }; - - Ok(Status::Complete(len + headers_len)) - } - - /// Try to parse a buffer of bytes into the Request, - /// except use an uninitialized slice of `Header`s. - /// - /// For more information, see `parse` - pub fn parse_with_uninit_headers( - &mut self, - buf: &'b [u8], - headers: &'h mut [MaybeUninit<Header<'b>>], - ) -> Result<usize> { - self.parse_with_config_and_uninit_headers(buf, &Default::default(), headers) - } - - fn parse_with_config(&mut self, buf: &'b [u8], config: &ParserConfig) -> Result<usize> { - let headers = mem::take(&mut self.headers); - - /* SAFETY: see `parse_headers_iter_uninit` guarantees */ - unsafe { - let headers: *mut [Header<'_>] = headers; - let headers = headers as *mut [MaybeUninit<Header<'_>>]; - match self.parse_with_config_and_uninit_headers(buf, config, &mut *headers) { - Ok(Status::Complete(idx)) => Ok(Status::Complete(idx)), - other => { - // put the original headers back - self.headers = &mut *(headers as *mut [Header<'_>]); - other - }, - } - } - } - - /// Try to parse a buffer of bytes into the Request. - /// - /// Returns byte offset in `buf` to start of HTTP body. - pub fn parse(&mut self, buf: &'b [u8]) -> Result<usize> { - self.parse_with_config(buf, &Default::default()) - } -} - -#[inline] -fn skip_empty_lines(bytes: &mut Bytes<'_>) -> Result<()> { - loop { - let b = bytes.peek(); - match b { - Some(b'\r') => { - // SAFETY: peeked and found `\r`, so it's safe to bump 1 pos - unsafe { bytes.bump() }; - expect!(bytes.next() == b'\n' => Err(Error::NewLine)); - } - Some(b'\n') => { - // SAFETY: peeked and found `\n`, so it's safe to bump 1 pos - unsafe { - bytes.bump(); - } - } - Some(..) => { - bytes.slice(); - return Ok(Status::Complete(())); - } - None => return Ok(Status::Partial), - } - } -} - -#[inline] -fn skip_spaces(bytes: &mut Bytes<'_>) -> Result<()> { - loop { - let b = bytes.peek(); - match b { - Some(b' ') => { - // SAFETY: peeked and found ` `, so it's safe to bump 1 pos - unsafe { bytes.bump() }; - } - Some(..) => { - bytes.slice(); - return Ok(Status::Complete(())); - } - None => return Ok(Status::Partial), - } - } -} - -/// A parsed Response. -/// -/// See `Request` docs for explanation of optional values. -#[derive(Debug, Eq, PartialEq)] -pub struct Response<'headers, 'buf> { - /// The response minor version, such as `1` for `HTTP/1.1`. - pub version: Option<u8>, - /// The response code, such as `200`. - pub code: Option<u16>, - /// The response reason-phrase, such as `OK`. - /// - /// Contains an empty string if the reason-phrase was missing or contained invalid characters. - pub reason: Option<&'buf str>, - /// The response headers. - pub headers: &'headers mut [Header<'buf>] -} - -impl<'h, 'b> Response<'h, 'b> { - /// Creates a new `Response` using a slice of `Header`s you have allocated. - #[inline] - pub fn new(headers: &'h mut [Header<'b>]) -> Response<'h, 'b> { - Response { - version: None, - code: None, - reason: None, - headers, - } - } - - /// Try to parse a buffer of bytes into this `Response`. - pub fn parse(&mut self, buf: &'b [u8]) -> Result<usize> { - self.parse_with_config(buf, &ParserConfig::default()) - } - - fn parse_with_config(&mut self, buf: &'b [u8], config: &ParserConfig) -> Result<usize> { - let headers = mem::take(&mut self.headers); - - // SAFETY: see guarantees of [`parse_headers_iter_uninit`], which leaves no uninitialized - // headers around. On failure, the original headers are restored. - unsafe { - let headers: *mut [Header<'_>] = headers; - let headers = headers as *mut [MaybeUninit<Header<'_>>]; - match self.parse_with_config_and_uninit_headers(buf, config, &mut *headers) { - Ok(Status::Complete(idx)) => Ok(Status::Complete(idx)), - other => { - // put the original headers back - self.headers = &mut *(headers as *mut [Header<'_>]); - other - }, - } - } - } - - fn parse_with_config_and_uninit_headers( - &mut self, - buf: &'b [u8], - config: &ParserConfig, - mut headers: &'h mut [MaybeUninit<Header<'b>>], - ) -> Result<usize> { - let orig_len = buf.len(); - let mut bytes = Bytes::new(buf); - - complete!(skip_empty_lines(&mut bytes)); - self.version = Some(complete!(parse_version(&mut bytes))); - space!(bytes or Error::Version); - if config.allow_multiple_spaces_in_response_status_delimiters { - complete!(skip_spaces(&mut bytes)); - } - self.code = Some(complete!(parse_code(&mut bytes))); - - // RFC7230 says there must be 'SP' and then reason-phrase, but admits - // its only for legacy reasons. With the reason-phrase completely - // optional (and preferred to be omitted) in HTTP2, we'll just - // handle any response that doesn't include a reason-phrase, because - // it's more lenient, and we don't care anyways. - // - // So, a SP means parse a reason-phrase. - // A newline means go to headers. - // Anything else we'll say is a malformed status. - match next!(bytes) { - b' ' => { - if config.allow_multiple_spaces_in_response_status_delimiters { - complete!(skip_spaces(&mut bytes)); - } - bytes.slice(); - self.reason = Some(complete!(parse_reason(&mut bytes))); - }, - b'\r' => { - expect!(bytes.next() == b'\n' => Err(Error::Status)); - bytes.slice(); - self.reason = Some(""); - }, - b'\n' => { - bytes.slice(); - self.reason = Some(""); - } - _ => return Err(Error::Status), - } - - - let len = orig_len - bytes.len(); - let headers_len = complete!(parse_headers_iter_uninit( - &mut headers, - &mut bytes, - &HeaderParserConfig { - allow_spaces_after_header_name: config.allow_spaces_after_header_name_in_responses, - allow_obsolete_multiline_headers: config.allow_obsolete_multiline_headers_in_responses, - allow_space_before_first_header_name: config.allow_space_before_first_header_name, - ignore_invalid_headers: config.ignore_invalid_headers_in_responses - } - )); - /* SAFETY: see `parse_headers_iter_uninit` guarantees */ - self.headers = unsafe { assume_init_slice(headers) }; - Ok(Status::Complete(len + headers_len)) - } -} - -/// Represents a parsed header. -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct Header<'a> { - /// The name portion of a header. - /// - /// A header name must be valid ASCII-US, so it's safe to store as a `&str`. - pub name: &'a str, - /// The value portion of a header. - /// - /// While headers **should** be ASCII-US, the specification allows for - /// values that may not be, and so the value is stored as bytes. - pub value: &'a [u8], -} - -impl fmt::Debug for Header<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut f = f.debug_struct("Header"); - f.field("name", &self.name); - if let Ok(value) = str::from_utf8(self.value) { - f.field("value", &value); - } else { - f.field("value", &self.value); - } - f.finish() - } -} - -/// An empty header, useful for constructing a `Header` array to pass in for -/// parsing. -/// -/// # Example -/// -/// ``` -/// let headers = [httparse::EMPTY_HEADER; 64]; -/// ``` -pub const EMPTY_HEADER: Header<'static> = Header { name: "", value: b"" }; - -#[inline] -#[doc(hidden)] -#[allow(missing_docs)] -// WARNING: Exported for internal benchmarks, not fit for public consumption -pub fn parse_version(bytes: &mut Bytes) -> Result<u8> { - if let Some(eight) = bytes.peek_n::<[u8; 8]>(8) { - // NOTE: should be const once MSRV >= 1.44 - let h10: u64 = u64::from_ne_bytes(*b"HTTP/1.0"); - let h11: u64 = u64::from_ne_bytes(*b"HTTP/1.1"); - // SAFETY: peek_n(8) before ensure within bounds - unsafe { - bytes.advance(8); - } - let block = u64::from_ne_bytes(eight); - // NOTE: should be match once h10 & h11 are consts - return if block == h10 { - Ok(Status::Complete(0)) - } else if block == h11 { - Ok(Status::Complete(1)) - } else { - Err(Error::Version) - }; - } - - // else (but not in `else` because of borrow checker) - - // If there aren't at least 8 bytes, we still want to detect early - // if this is a valid version or not. If it is, we'll return Partial. - expect!(bytes.next() == b'H' => Err(Error::Version)); - expect!(bytes.next() == b'T' => Err(Error::Version)); - expect!(bytes.next() == b'T' => Err(Error::Version)); - expect!(bytes.next() == b'P' => Err(Error::Version)); - expect!(bytes.next() == b'/' => Err(Error::Version)); - expect!(bytes.next() == b'1' => Err(Error::Version)); - expect!(bytes.next() == b'.' => Err(Error::Version)); - Ok(Status::Partial) -} - -#[inline] -#[doc(hidden)] -#[allow(missing_docs)] -// WARNING: Exported for internal benchmarks, not fit for public consumption -pub fn parse_method<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> { - const GET: [u8; 4] = *b"GET "; - const POST: [u8; 4] = *b"POST"; - match bytes.peek_n::<[u8; 4]>(4) { - Some(GET) => { - // SAFETY: we matched "GET " which has 4 bytes and is ASCII - let method = unsafe { - bytes.advance(4); // advance cursor past "GET " - str::from_utf8_unchecked(bytes.slice_skip(1)) // "GET" without space - }; - Ok(Status::Complete(method)) - } - // SAFETY: - // If `bytes.peek_n...` returns a Some([u8; 4]), - // then we are assured that `bytes` contains at least 4 bytes. - // Thus `bytes.len() >= 4`, - // and it is safe to peek at byte 4 with `bytes.peek_ahead(4)`. - Some(POST) if unsafe { bytes.peek_ahead(4) } == Some(b' ') => { - // SAFETY: we matched "POST " which has 5 bytes - let method = unsafe { - bytes.advance(5); // advance cursor past "POST " - str::from_utf8_unchecked(bytes.slice_skip(1)) // "POST" without space - }; - Ok(Status::Complete(method)) - } - _ => parse_token(bytes), - } -} - -/// From [RFC 7230](https://tools.ietf.org/html/rfc7230): -/// -/// > ```notrust -/// > reason-phrase = *( HTAB / SP / VCHAR / obs-text ) -/// > HTAB = %x09 ; horizontal tab -/// > VCHAR = %x21-7E ; visible (printing) characters -/// > obs-text = %x80-FF -/// > ``` -/// -/// > A.2. Changes from RFC 2616 -/// > -/// > Non-US-ASCII content in header fields and the reason phrase -/// > has been obsoleted and made opaque (the TEXT rule was removed). -#[inline] -fn parse_reason<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> { - let mut seen_obs_text = false; - loop { - let b = next!(bytes); - if b == b'\r' { - expect!(bytes.next() == b'\n' => Err(Error::Status)); - return Ok(Status::Complete( - // SAFETY: (1) calling bytes.slice_skip(2) is safe, because at least two next! calls - // advance the bytes iterator. - // (2) calling from_utf8_unchecked is safe, because the bytes returned by slice_skip - // were validated to be allowed US-ASCII chars by the other arms of the if/else or - // otherwise `seen_obs_text` is true and an empty string is returned instead. - unsafe { - let bytes = bytes.slice_skip(2); - if !seen_obs_text { - // all bytes up till `i` must have been HTAB / SP / VCHAR - str::from_utf8_unchecked(bytes) - } else { - // obs-text characters were found, so return the fallback empty string - "" - } - }, - )); - } else if b == b'\n' { - return Ok(Status::Complete( - // SAFETY: (1) calling bytes.slice_skip(1) is safe, because at least one next! call - // advance the bytes iterator. - // (2) see (2) of safety comment above. - unsafe { - let bytes = bytes.slice_skip(1); - if !seen_obs_text { - // all bytes up till `i` must have been HTAB / SP / VCHAR - str::from_utf8_unchecked(bytes) - } else { - // obs-text characters were found, so return the fallback empty string - "" - } - }, - )); - } else if !(b == 0x09 || b == b' ' || (0x21..=0x7E).contains(&b) || b >= 0x80) { - return Err(Error::Status); - } else if b >= 0x80 { - seen_obs_text = true; - } - } -} - -#[inline] -fn parse_token<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> { - let b = next!(bytes); - if !is_method_token(b) { - // First char must be a token char, it can't be a space which would indicate an empty token. - return Err(Error::Token); - } - - loop { - let b = next!(bytes); - if b == b' ' { - return Ok(Status::Complete( - // SAFETY: all bytes up till `i` must have been `is_method_token` and therefore also utf-8. - unsafe { str::from_utf8_unchecked(bytes.slice_skip(1)) }, - )); - } else if !is_method_token(b) { - return Err(Error::Token); - } - } -} - -#[inline] -#[doc(hidden)] -#[allow(missing_docs)] -// WARNING: Exported for internal benchmarks, not fit for public consumption -pub fn parse_uri<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> { - let start = bytes.pos(); - simd::match_uri_vectored(bytes); - let end = bytes.pos(); - - if next!(bytes) == b' ' { - // URI must have at least one char - if end == start { - return Err(Error::Token); - } - - // SAFETY: all bytes up till `i` must have been `is_token` and therefore also utf-8. - match str::from_utf8(unsafe { bytes.slice_skip(1) }) { - Ok(uri) => Ok(Status::Complete(uri)), - Err(_) => Err(Error::Token), - } - } else { - Err(Error::Token) - } -} - -#[inline] -fn parse_code(bytes: &mut Bytes<'_>) -> Result<u16> { - let hundreds = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status)); - let tens = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status)); - let ones = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status)); - - Ok(Status::Complete((hundreds - b'0') as u16 * 100 + - (tens - b'0') as u16 * 10 + - (ones - b'0') as u16)) -} - -/// Parse a buffer of bytes as headers. -/// -/// The return value, if complete and successful, includes the index of the -/// buffer that parsing stopped at, and a sliced reference to the parsed -/// headers. The length of the slice will be equal to the number of properly -/// parsed headers. -/// -/// # Example -/// -/// ``` -/// let buf = b"Host: foo.bar\nAccept: */*\n\nblah blah"; -/// let mut headers = [httparse::EMPTY_HEADER; 4]; -/// assert_eq!(httparse::parse_headers(buf, &mut headers), -/// Ok(httparse::Status::Complete((27, &[ -/// httparse::Header { name: "Host", value: b"foo.bar" }, -/// httparse::Header { name: "Accept", value: b"*/*" } -/// ][..])))); -/// ``` -pub fn parse_headers<'b: 'h, 'h>( - src: &'b [u8], - mut dst: &'h mut [Header<'b>], -) -> Result<(usize, &'h [Header<'b>])> { - let mut iter = Bytes::new(src); - let pos = complete!(parse_headers_iter(&mut dst, &mut iter, &HeaderParserConfig::default())); - Ok(Status::Complete((pos, dst))) -} - -#[inline] -fn parse_headers_iter<'a>( - headers: &mut &mut [Header<'a>], - bytes: &mut Bytes<'a>, - config: &HeaderParserConfig, -) -> Result<usize> { - parse_headers_iter_uninit( - /* SAFETY: see `parse_headers_iter_uninit` guarantees */ - unsafe { deinit_slice_mut(headers) }, - bytes, - config, - ) -} - -unsafe fn deinit_slice_mut<'a, 'b, T>(s: &'a mut &'b mut [T]) -> &'a mut &'b mut [MaybeUninit<T>] { - let s: *mut &mut [T] = s; - let s = s as *mut &mut [MaybeUninit<T>]; - &mut *s -} -unsafe fn assume_init_slice<T>(s: &mut [MaybeUninit<T>]) -> &mut [T] { - let s: *mut [MaybeUninit<T>] = s; - let s = s as *mut [T]; - &mut *s -} - -#[derive(Clone, Debug, Default)] -struct HeaderParserConfig { - allow_spaces_after_header_name: bool, - allow_obsolete_multiline_headers: bool, - allow_space_before_first_header_name: bool, - ignore_invalid_headers: bool, -} - -/* Function which parsers headers into uninitialized buffer. - * - * Guarantees that it doesn't write garbage, so casting - * &mut &mut [Header] -> &mut &mut [MaybeUninit<Header>] - * is safe here. - * - * Also it promises `headers` get shrunk to number of initialized headers, - * so casting the other way around after calling this function is safe - */ -fn parse_headers_iter_uninit<'a>( - headers: &mut &mut [MaybeUninit<Header<'a>>], - bytes: &mut Bytes<'a>, - config: &HeaderParserConfig -) -> Result<usize> { - - /* Flow of this function is pretty complex, especially with macros, - * so this struct makes sure we shrink `headers` to only parsed ones. - * Comparing to previous code, this only may introduce some additional - * instructions in case of early return */ - struct ShrinkOnDrop<'r1, 'r2, 'a> { - headers: &'r1 mut &'r2 mut [MaybeUninit<Header<'a>>], - num_headers: usize, - } - - impl Drop for ShrinkOnDrop<'_, '_, '_> { - fn drop(&mut self) { - let headers = mem::take(self.headers); - - /* SAFETY: num_headers is the number of initialized headers */ - let headers = unsafe { headers.get_unchecked_mut(..self.num_headers) }; - - *self.headers = headers; - } - } - - let mut autoshrink = ShrinkOnDrop { - headers, - num_headers: 0, - }; - // Track starting pointer to calculate the number of bytes parsed. - let start = bytes.as_ref().as_ptr() as usize; - let mut result = Err(Error::TooManyHeaders); - - let mut iter = autoshrink.headers.iter_mut(); - - macro_rules! maybe_continue_after_obsolete_line_folding { - ($bytes:ident, $label:lifetime) => { - if config.allow_obsolete_multiline_headers { - match $bytes.peek() { - None => { - // Next byte may be a space, in which case that header - // is using obsolete line folding, so we may have more - // whitespace to skip after colon. - return Ok(Status::Partial); - } - Some(b' ') | Some(b'\t') => { - // The space will be consumed next iteration. - continue $label; - } - _ => { - // There is another byte after the end of the line, - // but it's not whitespace, so it's probably another - // header or the final line return. This header is thus - // empty. - }, - } - } - } - } - - 'headers: loop { - // Return the error `$err` if `ignore_invalid_headers_in_responses` - // is false, otherwise find the end of the current line and resume - // parsing on the next one. - macro_rules! handle_invalid_char { - ($bytes:ident, $b:ident, $err:ident) => { - if !config.ignore_invalid_headers { - return Err(Error::$err); - } - - let mut b = $b; - - loop { - if b == b'\r' { - expect!(bytes.next() == b'\n' => Err(Error::$err)); - break; - } - if b == b'\n' { - break; - } - if b == b'\0' { - return Err(Error::$err); - } - b = next!($bytes); - } - - $bytes.slice(); - - continue 'headers; - }; - } - - // a newline here means the head is over! - let b = next!(bytes); - if b == b'\r' { - expect!(bytes.next() == b'\n' => Err(Error::NewLine)); - let end = bytes.as_ref().as_ptr() as usize; - result = Ok(Status::Complete(end - start)); - break; - } - if b == b'\n' { - let end = bytes.as_ref().as_ptr() as usize; - result = Ok(Status::Complete(end - start)); - break; - } - if !is_header_name_token(b) { - if config.allow_space_before_first_header_name - && autoshrink.num_headers == 0 - && (b == b' ' || b == b'\t') - { - //advance past white space and then try parsing header again - while let Some(peek) = bytes.peek() { - if peek == b' ' || peek == b'\t' { - next!(bytes); - } else { - break; - } - } - bytes.slice(); - continue 'headers; - } else { - handle_invalid_char!(bytes, b, HeaderName); - } - } - - #[allow(clippy::never_loop)] - // parse header name until colon - let header_name: &str = 'name: loop { - simd::match_header_name_vectored(bytes); - let mut b = next!(bytes); - - // SAFETY: previously bumped by 1 with next! -> always safe. - let bslice = unsafe { bytes.slice_skip(1) }; - // SAFETY: previous call to match_header_name_vectored ensured all bytes are valid - // header name chars, and as such also valid utf-8. - let name = unsafe { str::from_utf8_unchecked(bslice) }; - - if b == b':' { - break 'name name; - } - - if config.allow_spaces_after_header_name { - while b == b' ' || b == b'\t' { - b = next!(bytes); - - if b == b':' { - bytes.slice(); - break 'name name; - } - } - } - - handle_invalid_char!(bytes, b, HeaderName); - }; - - let mut b; - - #[allow(clippy::never_loop)] - let value_slice = 'value: loop { - // eat white space between colon and value - 'whitespace_after_colon: loop { - b = next!(bytes); - if b == b' ' || b == b'\t' { - bytes.slice(); - continue 'whitespace_after_colon; - } - if is_header_value_token(b) { - break 'whitespace_after_colon; - } - - if b == b'\r' { - expect!(bytes.next() == b'\n' => Err(Error::HeaderValue)); - } else if b != b'\n' { - handle_invalid_char!(bytes, b, HeaderValue); - } - - maybe_continue_after_obsolete_line_folding!(bytes, 'whitespace_after_colon); - - let whitespace_slice = bytes.slice(); - - // This produces an empty slice that points to the beginning - // of the whitespace. - break 'value &whitespace_slice[0..0]; - } - - 'value_lines: loop { - // parse value till EOL - - simd::match_header_value_vectored(bytes); - let b = next!(bytes); - - //found_ctl - let skip = if b == b'\r' { - expect!(bytes.next() == b'\n' => Err(Error::HeaderValue)); - 2 - } else if b == b'\n' { - 1 - } else { - handle_invalid_char!(bytes, b, HeaderValue); - }; - - maybe_continue_after_obsolete_line_folding!(bytes, 'value_lines); - - // SAFETY: having just checked that a newline exists, it's safe to skip it. - unsafe { - break 'value bytes.slice_skip(skip); - } - } - }; - - let uninit_header = match iter.next() { - Some(header) => header, - None => break 'headers - }; - - // trim trailing whitespace in the header - let header_value = if let Some(last_visible) = value_slice - .iter() - .rposition(|b| *b != b' ' && *b != b'\t' && *b != b'\r' && *b != b'\n') - { - // There is at least one non-whitespace character. - &value_slice[0..last_visible+1] - } else { - // There is no non-whitespace character. This can only happen when value_slice is - // empty. - value_slice - }; - - *uninit_header = MaybeUninit::new(Header { - name: header_name, - value: header_value, - }); - autoshrink.num_headers += 1; - } - - result -} - -/// Parse a buffer of bytes as a chunk size. -/// -/// The return value, if complete and successful, includes the index of the -/// buffer that parsing stopped at, and the size of the following chunk. -/// -/// # Example -/// -/// ``` -/// let buf = b"4\r\nRust\r\n0\r\n\r\n"; -/// assert_eq!(httparse::parse_chunk_size(buf), -/// Ok(httparse::Status::Complete((3, 4)))); -/// ``` -pub fn parse_chunk_size(buf: &[u8]) - -> result::Result<Status<(usize, u64)>, InvalidChunkSize> { - const RADIX: u64 = 16; - let mut bytes = Bytes::new(buf); - let mut size = 0; - let mut in_chunk_size = true; - let mut in_ext = false; - let mut count = 0; - loop { - let b = next!(bytes); - match b { - b'0' ..= b'9' if in_chunk_size => { - if count > 15 { - return Err(InvalidChunkSize); - } - count += 1; - if cfg!(debug_assertions) && size > (u64::MAX / RADIX) { - // actually unreachable!(), because count stops the loop at 15 digits before - // we can reach u64::MAX / RADIX == 0xfffffffffffffff, which requires 15 hex - // digits. This stops mirai reporting a false alarm regarding the `size *= - // RADIX` multiplication below. - return Err(InvalidChunkSize); - } - size *= RADIX; - size += (b - b'0') as u64; - }, - b'a' ..= b'f' if in_chunk_size => { - if count > 15 { - return Err(InvalidChunkSize); - } - count += 1; - if cfg!(debug_assertions) && size > (u64::MAX / RADIX) { - return Err(InvalidChunkSize); - } - size *= RADIX; - size += (b + 10 - b'a') as u64; - } - b'A' ..= b'F' if in_chunk_size => { - if count > 15 { - return Err(InvalidChunkSize); - } - count += 1; - if cfg!(debug_assertions) && size > (u64::MAX / RADIX) { - return Err(InvalidChunkSize); - } - size *= RADIX; - size += (b + 10 - b'A') as u64; - } - b'\r' => { - match next!(bytes) { - b'\n' => break, - _ => return Err(InvalidChunkSize), - } - } - // If we weren't in the extension yet, the ";" signals its start - b';' if !in_ext => { - in_ext = true; - in_chunk_size = false; - } - // "Linear white space" is ignored between the chunk size and the - // extension separator token (";") due to the "implied *LWS rule". - b'\t' | b' ' if !in_ext && !in_chunk_size => {} - // LWS can follow the chunk size, but no more digits can come - b'\t' | b' ' if in_chunk_size => in_chunk_size = false, - // We allow any arbitrary octet once we are in the extension, since - // they all get ignored anyway. According to the HTTP spec, valid - // extensions would have a more strict syntax: - // (token ["=" (token | quoted-string)]) - // but we gain nothing by rejecting an otherwise valid chunk size. - _ if in_ext => {} - // Finally, if we aren't in the extension and we're reading any - // other octet, the chunk size line is invalid! - _ => return Err(InvalidChunkSize), - } - } - Ok(Status::Complete((bytes.pos(), size))) -} - -#[cfg(test)] -mod tests { - use super::{Error, Request, Response, Status, EMPTY_HEADER, parse_chunk_size}; - - const NUM_OF_HEADERS: usize = 4; - - macro_rules! req { - ($name:ident, $buf:expr, |$arg:ident| $body:expr) => ( - req! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body } - ); - ($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => ( - #[test] - fn $name() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut req = Request::new(&mut headers[..]); - let status = req.parse($buf.as_ref()); - assert_eq!(status, $len); - closure(req); - - fn closure($arg: Request) { - $body - } - } - ) - } - - req! { - test_request_simple, - b"GET / HTTP/1.1\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 0); - } - } - - req! { - test_request_simple_with_query_params, - b"GET /thing?data=a HTTP/1.1\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/thing?data=a"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 0); - } - } - - req! { - test_request_simple_with_whatwg_query_params, - b"GET /thing?data=a^ HTTP/1.1\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/thing?data=a^"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 0); - } - } - - req! { - test_request_headers, - b"GET / HTTP/1.1\r\nHost: foo.com\r\nCookie: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 2); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo.com"); - assert_eq!(req.headers[1].name, "Cookie"); - assert_eq!(req.headers[1].value, b""); - } - } - - req! { - test_request_headers_optional_whitespace, - b"GET / HTTP/1.1\r\nHost: \tfoo.com\t \r\nCookie: \t \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 2); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo.com"); - assert_eq!(req.headers[1].name, "Cookie"); - assert_eq!(req.headers[1].value, b""); - } - } - - req! { - // test the scalar parsing - test_request_header_value_htab_short, - b"GET / HTTP/1.1\r\nUser-Agent: some\tagent\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "User-Agent"); - assert_eq!(req.headers[0].value, b"some\tagent"); - } - } - - req! { - // test the sse42 parsing - test_request_header_value_htab_med, - b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\tagent\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "User-Agent"); - assert_eq!(req.headers[0].value, b"1234567890some\tagent"); - } - } - - req! { - // test the avx2 parsing - test_request_header_value_htab_long, - b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\t1234567890agent1234567890\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "User-Agent"); - assert_eq!(req.headers[0].value, &b"1234567890some\t1234567890agent1234567890"[..]); - } - } - - req! { - // test the avx2 parsing - test_request_header_no_space_after_colon, - b"GET / HTTP/1.1\r\nUser-Agent:omg-no-space1234567890some1234567890agent1234567890\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "User-Agent"); - assert_eq!(req.headers[0].value, &b"omg-no-space1234567890some1234567890agent1234567890"[..]); - } - } - - req! { - test_request_headers_max, - b"GET / HTTP/1.1\r\nA: A\r\nB: B\r\nC: C\r\nD: D\r\n\r\n", - |req| { - assert_eq!(req.headers.len(), NUM_OF_HEADERS); - } - } - - req! { - test_request_multibyte, - b"GET / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: \xe3\x81\xb2\xe3/1.0\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 2); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo.com"); - assert_eq!(req.headers[1].name, "User-Agent"); - assert_eq!(req.headers[1].value, b"\xe3\x81\xb2\xe3/1.0"); - } - } - - // A single byte which is part of a method is not invalid - req! { - test_request_one_byte_method, - b"G", Ok(Status::Partial), - |_req| {} - } - - // A subset of a method is a partial method, not invalid - req! { - test_request_partial_method, - b"GE", Ok(Status::Partial), - |_req| {} - } - - // A method, without the delimiting space, is a partial request - req! { - test_request_method_no_delimiter, - b"GET", Ok(Status::Partial), - |_req| {} - } - - // Regression test: assert that a partial read with just the method and - // space results in a partial, rather than a token error from uri parsing. - req! { - test_request_method_only, - b"GET ", Ok(Status::Partial), - |_req| {} - } - - req! { - test_request_partial, - b"GET / HTTP/1.1\r\n\r", Ok(Status::Partial), - |_req| {} - } - - req! { - test_request_partial_version, - b"GET / HTTP/1.", Ok(Status::Partial), - |_req| {} - } - - req! { - test_request_method_path_no_delimiter, - b"GET /", Ok(Status::Partial), - |_req| {} - } - - req! { - test_request_method_path_only, - b"GET / ", Ok(Status::Partial), - |_req| {} - } - - req! { - test_request_partial_parses_headers_as_much_as_it_can, - b"GET / HTTP/1.1\r\nHost: yolo\r\n", - Ok(crate::Status::Partial), - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), NUM_OF_HEADERS); // doesn't slice since not Complete - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"yolo"); - } - } - - req! { - test_request_newlines, - b"GET / HTTP/1.1\nHost: foo.bar\n\n", - |_r| {} - } - - req! { - test_request_empty_lines_prefix, - b"\r\n\r\nGET / HTTP/1.1\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 0); - } - } - - req! { - test_request_empty_lines_prefix_lf_only, - b"\n\nGET / HTTP/1.1\n\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 0); - } - } - - req! { - test_request_path_backslash, - b"\n\nGET /\\?wayne\\=5 HTTP/1.1\n\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/\\?wayne\\=5"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 0); - } - } - - req! { - test_request_with_invalid_token_delimiter, - b"GET\n/ HTTP/1.1\r\nHost: foo.bar\r\n\r\n", - Err(crate::Error::Token), - |_r| {} - } - - - req! { - test_request_with_invalid_but_short_version, - b"GET / HTTP/1!", - Err(crate::Error::Version), - |_r| {} - } - - req! { - test_request_with_empty_method, - b" / HTTP/1.1\r\n\r\n", - Err(crate::Error::Token), - |_r| {} - } - - req! { - test_request_with_empty_path, - b"GET HTTP/1.1\r\n\r\n", - Err(crate::Error::Token), - |_r| {} - } - - req! { - test_request_with_empty_method_and_path, - b" HTTP/1.1\r\n\r\n", - Err(crate::Error::Token), - |_r| {} - } - - macro_rules! res { - ($name:ident, $buf:expr, |$arg:ident| $body:expr) => ( - res! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body } - ); - ($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => ( - #[test] - fn $name() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut res = Response::new(&mut headers[..]); - let status = res.parse($buf.as_ref()); - assert_eq!(status, $len); - closure(res); - - fn closure($arg: Response) { - $body - } - } - ) - } - - res! { - test_response_simple, - b"HTTP/1.1 200 OK\r\n\r\n", - |res| { - assert_eq!(res.version.unwrap(), 1); - assert_eq!(res.code.unwrap(), 200); - assert_eq!(res.reason.unwrap(), "OK"); - } - } - - res! { - test_response_newlines, - b"HTTP/1.0 403 Forbidden\nServer: foo.bar\n\n", - |_r| {} - } - - res! { - test_response_reason_missing, - b"HTTP/1.1 200 \r\n\r\n", - |res| { - assert_eq!(res.version.unwrap(), 1); - assert_eq!(res.code.unwrap(), 200); - assert_eq!(res.reason.unwrap(), ""); - } - } - - res! { - test_response_reason_missing_no_space, - b"HTTP/1.1 200\r\n\r\n", - |res| { - assert_eq!(res.version.unwrap(), 1); - assert_eq!(res.code.unwrap(), 200); - assert_eq!(res.reason.unwrap(), ""); - } - } - - res! { - test_response_reason_missing_no_space_with_headers, - b"HTTP/1.1 200\r\nFoo: bar\r\n\r\n", - |res| { - assert_eq!(res.version.unwrap(), 1); - assert_eq!(res.code.unwrap(), 200); - assert_eq!(res.reason.unwrap(), ""); - assert_eq!(res.headers.len(), 1); - assert_eq!(res.headers[0].name, "Foo"); - assert_eq!(res.headers[0].value, b"bar"); - } - } - - res! { - test_response_reason_with_space_and_tab, - b"HTTP/1.1 101 Switching Protocols\t\r\n\r\n", - |res| { - assert_eq!(res.version.unwrap(), 1); - assert_eq!(res.code.unwrap(), 101); - assert_eq!(res.reason.unwrap(), "Switching Protocols\t"); - } - } - - static RESPONSE_REASON_WITH_OBS_TEXT_BYTE: &[u8] = b"HTTP/1.1 200 X\xFFZ\r\n\r\n"; - res! { - test_response_reason_with_obsolete_text_byte, - RESPONSE_REASON_WITH_OBS_TEXT_BYTE, - |res| { - assert_eq!(res.version.unwrap(), 1); - assert_eq!(res.code.unwrap(), 200); - // Empty string fallback in case of obs-text - assert_eq!(res.reason.unwrap(), ""); - } - } - - res! { - test_response_reason_with_nul_byte, - b"HTTP/1.1 200 \x00\r\n\r\n", - Err(crate::Error::Status), - |_res| {} - } - - res! { - test_response_version_missing_space, - b"HTTP/1.1", - Ok(Status::Partial), - |_res| {} - } - - res! { - test_response_code_missing_space, - b"HTTP/1.1 200", - Ok(Status::Partial), - |_res| {} - } - - res! { - test_response_partial_parses_headers_as_much_as_it_can, - b"HTTP/1.1 200 OK\r\nServer: yolo\r\n", - Ok(crate::Status::Partial), - |res| { - assert_eq!(res.version.unwrap(), 1); - assert_eq!(res.code.unwrap(), 200); - assert_eq!(res.reason.unwrap(), "OK"); - assert_eq!(res.headers.len(), NUM_OF_HEADERS); // doesn't slice since not Complete - assert_eq!(res.headers[0].name, "Server"); - assert_eq!(res.headers[0].value, b"yolo"); - } - } - - res! { - test_response_empty_lines_prefix_lf_only, - b"\n\nHTTP/1.1 200 OK\n\n", - |_res| {} - } - - res! { - test_response_no_cr, - b"HTTP/1.0 200\nContent-type: text/html\n\n", - |res| { - assert_eq!(res.version.unwrap(), 0); - assert_eq!(res.code.unwrap(), 200); - assert_eq!(res.reason.unwrap(), ""); - assert_eq!(res.headers.len(), 1); - assert_eq!(res.headers[0].name, "Content-type"); - assert_eq!(res.headers[0].value, b"text/html"); - } - } - - /// Check all subset permutations of a partial request line with no headers - #[test] - fn partial_permutations() { - let req_str = "GET / HTTP/1.1\r\n\r\n"; - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut req = Request::new(&mut headers[..]); - for i in 0..req_str.len() { - let status = req.parse(req_str[..i].as_bytes()); - assert_eq!( - status, - Ok(Status::Partial), - "partial request line should return partial. \ - Portion which failed: '{seg}' (below {i})", - seg = &req_str[..i] - ); - } - } - - static RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON: &[u8] = - b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials : true\r\nBread: baguette\r\n\r\n"; - - #[test] - fn test_forbid_response_with_whitespace_between_header_name_and_colon() { - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - let result = response.parse(RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON); - - assert_eq!(result, Err(crate::Error::HeaderName)); - } - - #[test] - fn test_allow_response_with_whitespace_between_header_name_and_colon() { - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_spaces_after_header_name_in_responses(true) - .parse_response(&mut response, RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON); - - assert_eq!(result, Ok(Status::Complete(77))); - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 2); - assert_eq!(response.headers[0].name, "Access-Control-Allow-Credentials"); - assert_eq!(response.headers[0].value, &b"true"[..]); - assert_eq!(response.headers[1].name, "Bread"); - assert_eq!(response.headers[1].value, &b"baguette"[..]); - } - - #[test] - fn test_ignore_header_line_with_whitespaces_after_header_name_in_response() { - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_responses(true) - .parse_response(&mut response, RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON); - - assert_eq!(result, Ok(Status::Complete(77))); - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "Bread"); - assert_eq!(response.headers[0].value, &b"baguette"[..]); - } - - static REQUEST_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON: &[u8] = - b"GET / HTTP/1.1\r\nHost : localhost\r\n\r\n"; - - #[test] - fn test_forbid_request_with_whitespace_between_header_name_and_colon() { - let mut headers = [EMPTY_HEADER; 1]; - let mut request = Request::new(&mut headers[..]); - let result = request.parse(REQUEST_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON); - - assert_eq!(result, Err(crate::Error::HeaderName)); - } - - #[test] - fn test_ignore_header_line_with_whitespaces_after_header_name_in_request() { - let mut headers = [EMPTY_HEADER; 2]; - let mut request = Request::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_requests(true) - .parse_request(&mut request, REQUEST_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON); - - assert_eq!(result, Ok(Status::Complete(36))); - } - - static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START: &[u8] = - b"HTTP/1.1 200 OK\r\nLine-Folded-Header: \r\n \r\n hello there\r\n\r\n"; - - #[test] - fn test_forbid_response_with_obsolete_line_folding_at_start() { - let mut headers = [EMPTY_HEADER; 1]; - let mut response = Response::new(&mut headers[..]); - let result = response.parse(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START); - - assert_eq!(result, Err(crate::Error::HeaderName)); - } - - #[test] - fn test_allow_response_with_obsolete_line_folding_at_start() { - let mut headers = [EMPTY_HEADER; 1]; - let mut response = Response::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_obsolete_multiline_headers_in_responses(true) - .parse_response(&mut response, RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START); - - assert_eq!(result, Ok(Status::Complete(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START.len()))); - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "Line-Folded-Header"); - assert_eq!(response.headers[0].value, &b"hello there"[..]); - } - - static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_END: &[u8] = - b"HTTP/1.1 200 OK\r\nLine-Folded-Header: hello there\r\n \r\n \r\n\r\n"; - - #[test] - fn test_forbid_response_with_obsolete_line_folding_at_end() { - let mut headers = [EMPTY_HEADER; 1]; - let mut response = Response::new(&mut headers[..]); - let result = response.parse(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_END); - - assert_eq!(result, Err(crate::Error::HeaderName)); - } - - #[test] - fn test_allow_response_with_obsolete_line_folding_at_end() { - let mut headers = [EMPTY_HEADER; 1]; - let mut response = Response::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_obsolete_multiline_headers_in_responses(true) - .parse_response(&mut response, RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_END); - - assert_eq!(result, Ok(Status::Complete(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_END.len()))); - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "Line-Folded-Header"); - assert_eq!(response.headers[0].value, &b"hello there"[..]); - } - - static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_MIDDLE: &[u8] = - b"HTTP/1.1 200 OK\r\nLine-Folded-Header: hello \r\n \r\n there\r\n\r\n"; - - #[test] - fn test_forbid_response_with_obsolete_line_folding_in_middle() { - let mut headers = [EMPTY_HEADER; 1]; - let mut response = Response::new(&mut headers[..]); - let result = response.parse(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_MIDDLE); - - assert_eq!(result, Err(crate::Error::HeaderName)); - } - - #[test] - fn test_allow_response_with_obsolete_line_folding_in_middle() { - let mut headers = [EMPTY_HEADER; 1]; - let mut response = Response::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_obsolete_multiline_headers_in_responses(true) - .parse_response(&mut response, RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_MIDDLE); - - assert_eq!(result, Ok(Status::Complete(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_MIDDLE.len()))); - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "Line-Folded-Header"); - assert_eq!(response.headers[0].value, &b"hello \r\n \r\n there"[..]); - } - - static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_EMPTY_HEADER: &[u8] = - b"HTTP/1.1 200 OK\r\nLine-Folded-Header: \r\n \r\n \r\n\r\n"; - - #[test] - fn test_forbid_response_with_obsolete_line_folding_in_empty_header() { - let mut headers = [EMPTY_HEADER; 1]; - let mut response = Response::new(&mut headers[..]); - let result = response.parse(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_EMPTY_HEADER); - - assert_eq!(result, Err(crate::Error::HeaderName)); - } - - #[test] - fn test_allow_response_with_obsolete_line_folding_in_empty_header() { - let mut headers = [EMPTY_HEADER; 1]; - let mut response = Response::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_obsolete_multiline_headers_in_responses(true) - .parse_response(&mut response, RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_EMPTY_HEADER); - - assert_eq!(result, Ok(Status::Complete(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_EMPTY_HEADER.len()))); - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "Line-Folded-Header"); - assert_eq!(response.headers[0].value, &b""[..]); - } - - #[test] - fn test_chunk_size() { - assert_eq!(parse_chunk_size(b"0\r\n"), Ok(Status::Complete((3, 0)))); - assert_eq!(parse_chunk_size(b"12\r\nchunk"), Ok(Status::Complete((4, 18)))); - assert_eq!(parse_chunk_size(b"3086d\r\n"), Ok(Status::Complete((7, 198765)))); - assert_eq!(parse_chunk_size(b"3735AB1;foo bar*\r\n"), Ok(Status::Complete((18, 57891505)))); - assert_eq!(parse_chunk_size(b"3735ab1 ; baz \r\n"), Ok(Status::Complete((16, 57891505)))); - assert_eq!(parse_chunk_size(b"77a65\r"), Ok(Status::Partial)); - assert_eq!(parse_chunk_size(b"ab"), Ok(Status::Partial)); - assert_eq!(parse_chunk_size(b"567f8a\rfoo"), Err(crate::InvalidChunkSize)); - assert_eq!(parse_chunk_size(b"567f8a\rfoo"), Err(crate::InvalidChunkSize)); - assert_eq!(parse_chunk_size(b"567xf8a\r\n"), Err(crate::InvalidChunkSize)); - assert_eq!(parse_chunk_size(b"ffffffffffffffff\r\n"), Ok(Status::Complete((18, u64::MAX)))); - assert_eq!(parse_chunk_size(b"1ffffffffffffffff\r\n"), Err(crate::InvalidChunkSize)); - assert_eq!(parse_chunk_size(b"Affffffffffffffff\r\n"), Err(crate::InvalidChunkSize)); - assert_eq!(parse_chunk_size(b"fffffffffffffffff\r\n"), Err(crate::InvalidChunkSize)); - } - - static RESPONSE_WITH_MULTIPLE_SPACE_DELIMITERS: &[u8] = - b"HTTP/1.1 200 OK\r\n\r\n"; - - #[test] - fn test_forbid_response_with_multiple_space_delimiters() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut response = Response::new(&mut headers[..]); - let result = response.parse(RESPONSE_WITH_MULTIPLE_SPACE_DELIMITERS); - - assert_eq!(result, Err(crate::Error::Status)); - } - - #[test] - fn test_allow_response_with_multiple_space_delimiters() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut response = Response::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_response_status_delimiters(true) - .parse_response(&mut response, RESPONSE_WITH_MULTIPLE_SPACE_DELIMITERS); - - assert_eq!(result, Ok(Status::Complete(RESPONSE_WITH_MULTIPLE_SPACE_DELIMITERS.len()))); - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 0); - } - - /// This is technically allowed by the spec, but we only support multiple spaces as an option, - /// not stray `\r`s. - static RESPONSE_WITH_WEIRD_WHITESPACE_DELIMITERS: &[u8] = - b"HTTP/1.1 200\rOK\r\n\r\n"; - - #[test] - fn test_forbid_response_with_weird_whitespace_delimiters() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut response = Response::new(&mut headers[..]); - let result = response.parse(RESPONSE_WITH_WEIRD_WHITESPACE_DELIMITERS); - - assert_eq!(result, Err(crate::Error::Status)); - } - - #[test] - fn test_still_forbid_response_with_weird_whitespace_delimiters() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut response = Response::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_response_status_delimiters(true) - .parse_response(&mut response, RESPONSE_WITH_WEIRD_WHITESPACE_DELIMITERS); - assert_eq!(result, Err(crate::Error::Status)); - } - - static REQUEST_WITH_MULTIPLE_SPACE_DELIMITERS: &[u8] = - b"GET / HTTP/1.1\r\n\r\n"; - - #[test] - fn test_forbid_request_with_multiple_space_delimiters() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut request = Request::new(&mut headers[..]); - let result = request.parse(REQUEST_WITH_MULTIPLE_SPACE_DELIMITERS); - - assert_eq!(result, Err(crate::Error::Token)); - } - - #[test] - fn test_allow_request_with_multiple_space_delimiters() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut request = Request::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_request_line_delimiters(true) - .parse_request(&mut request, REQUEST_WITH_MULTIPLE_SPACE_DELIMITERS); - - assert_eq!(result, Ok(Status::Complete(REQUEST_WITH_MULTIPLE_SPACE_DELIMITERS.len()))); - assert_eq!(request.method.unwrap(), "GET"); - assert_eq!(request.path.unwrap(), "/"); - assert_eq!(request.version.unwrap(), 1); - assert_eq!(request.headers.len(), 0); - } - - /// This is technically allowed by the spec, but we only support multiple spaces as an option, - /// not stray `\r`s. - static REQUEST_WITH_WEIRD_WHITESPACE_DELIMITERS: &[u8] = - b"GET\r/\rHTTP/1.1\r\n\r\n"; - - #[test] - fn test_forbid_request_with_weird_whitespace_delimiters() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut request = Request::new(&mut headers[..]); - let result = request.parse(REQUEST_WITH_WEIRD_WHITESPACE_DELIMITERS); - - assert_eq!(result, Err(crate::Error::Token)); - } - - #[test] - fn test_still_forbid_request_with_weird_whitespace_delimiters() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut request = Request::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_request_line_delimiters(true) - .parse_request(&mut request, REQUEST_WITH_WEIRD_WHITESPACE_DELIMITERS); - assert_eq!(result, Err(crate::Error::Token)); - } - - static REQUEST_WITH_MULTIPLE_SPACES_AND_BAD_PATH: &[u8] = b"GET /foo ohno HTTP/1.1\r\n\r\n"; - - #[test] - fn test_request_with_multiple_spaces_and_bad_path() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut request = Request::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_request_line_delimiters(true) - .parse_request(&mut request, REQUEST_WITH_MULTIPLE_SPACES_AND_BAD_PATH); - assert_eq!(result, Err(crate::Error::Version)); - } - - // This test ensure there is an error when there is a DEL character in the path - // since we allow all char from 0x21 code except DEL, this test ensure that DEL - // is not allowed in the path - static REQUEST_WITH_DEL_IN_PATH: &[u8] = b"GET /foo\x7Fohno HTTP/1.1\r\n\r\n"; - - #[test] - fn test_request_with_del_in_path() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut request = Request::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_request_line_delimiters(true) - .parse_request(&mut request, crate::tests::REQUEST_WITH_DEL_IN_PATH); - assert_eq!(result, Err(crate::Error::Token)); - } - - #[test] - #[cfg_attr(miri, ignore)] // Miri is too slow for this test - fn test_all_utf8_char_in_paths() { - // two code points - for i in 128..256 { - for j in 128..256 { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut request = Request::new(&mut headers[..]); - let bytes = [i as u8, j as u8]; - - match core::str::from_utf8(&bytes) { - Ok(s) => { - let first_line = format!("GET /{} HTTP/1.1\r\n\r\n", s); - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_request_line_delimiters(true) - .parse_request(&mut request, first_line.as_bytes()); - - assert_eq!(result, Ok(Status::Complete(20)), "failed for utf8 char i: {}, j: {}", i, j); - }, - Err(_) => { - let mut first_line = b"GET /".to_vec(); - first_line.extend(&bytes); - first_line.extend(b" HTTP/1.1\r\n\r\n"); - - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_request_line_delimiters(true) - .parse_request(&mut request, first_line.as_slice()); - - assert_eq!(result, Err(crate::Error::Token), "failed for utf8 char i: {}, j: {}", i, j); - }, - }; - - // three code points starting from 0xe0 - if i < 0xe0 { - continue; - } - - for k in 128..256 { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut request = Request::new(&mut headers[..]); - let bytes = [i as u8, j as u8, k as u8]; - - match core::str::from_utf8(&bytes) { - Ok(s) => { - let first_line = format!("GET /{} HTTP/1.1\r\n\r\n", s); - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_request_line_delimiters(true) - .parse_request(&mut request, first_line.as_bytes()); - - assert_eq!(result, Ok(Status::Complete(21)), "failed for utf8 char i: {}, j: {}, k: {}", i, j, k); - }, - Err(_) => { - let mut first_line = b"GET /".to_vec(); - first_line.extend(&bytes); - first_line.extend(b" HTTP/1.1\r\n\r\n"); - - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_request_line_delimiters(true) - .parse_request(&mut request, first_line.as_slice()); - - assert_eq!(result, Err(crate::Error::Token), "failed for utf8 char i: {}, j: {}, k: {}", i, j, k); - }, - }; - - // four code points starting from 0xf0 - if i < 0xf0 { - continue; - } - - for l in 128..256 { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut request = Request::new(&mut headers[..]); - let bytes = [i as u8, j as u8, k as u8, l as u8]; - - match core::str::from_utf8(&bytes) { - Ok(s) => { - let first_line = format!("GET /{} HTTP/1.1\r\n\r\n", s); - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_request_line_delimiters(true) - .parse_request(&mut request, first_line.as_bytes()); - - assert_eq!(result, Ok(Status::Complete(22)), "failed for utf8 char i: {}, j: {}, k: {}, l: {}", i, j, k, l); - }, - Err(_) => { - let mut first_line = b"GET /".to_vec(); - first_line.extend(&bytes); - first_line.extend(b" HTTP/1.1\r\n\r\n"); - - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_request_line_delimiters(true) - .parse_request(&mut request, first_line.as_slice()); - - assert_eq!(result, Err(crate::Error::Token), "failed for utf8 char i: {}, j: {}, k: {}, l: {}", i, j, k, l); - }, - }; - } - } - } - } - } - - static RESPONSE_WITH_SPACES_IN_CODE: &[u8] = b"HTTP/1.1 99 200 OK\r\n\r\n"; - - #[test] - fn test_response_with_spaces_in_code() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut response = Response::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_multiple_spaces_in_response_status_delimiters(true) - .parse_response(&mut response, RESPONSE_WITH_SPACES_IN_CODE); - assert_eq!(result, Err(crate::Error::Status)); - } - - #[test] - fn test_response_with_empty_header_name() { - const RESPONSE: &[u8] = - b"HTTP/1.1 200 OK\r\n: hello\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .allow_spaces_after_header_name_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Ok(Status::Complete(45))); - - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "Bread"); - assert_eq!(response.headers[0].value, &b"baguette"[..]); - } - - #[test] - fn test_request_with_empty_header_name() { - const RESPONSE: &[u8] = - b"GET / HTTP/1.1\r\n: hello\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_request(&mut request, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_requests(true) - .parse_request(&mut request, RESPONSE); - assert_eq!(result, Ok(Status::Complete(44))); - } - - #[test] - fn test_request_with_whitespace_between_header_name_and_colon() { - const REQUEST: &[u8] = - b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials : true\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .allow_spaces_after_header_name_in_responses(true) - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - - .ignore_invalid_headers_in_responses(true) - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderName)); - } - - #[test] - fn test_response_with_invalid_char_between_header_name_and_colon() { - const RESPONSE: &[u8] = - b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials\xFF : true\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .allow_spaces_after_header_name_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_responses(true) - .parse_response(&mut response, RESPONSE); - - assert_eq!(result, Ok(Status::Complete(79))); - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "Bread"); - assert_eq!(response.headers[0].value, &b"baguette"[..]); - } - - #[test] - fn test_request_with_invalid_char_between_header_name_and_colon() { - const REQUEST: &[u8] = - b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials\xFF : true\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_requests(true) - .parse_request(&mut request, REQUEST); - assert_eq!(result, Ok(Status::Complete(78))); - } - - #[test] - fn test_ignore_header_line_with_missing_colon_in_response() { - const RESPONSE: &[u8] = - b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Ok(Status::Complete(70))); - - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "Bread"); - assert_eq!(response.headers[0].value, &b"baguette"[..]); - } - - #[test] - fn test_ignore_header_line_with_missing_colon_in_request() { - const REQUEST: &[u8] = - b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_requests(true) - .parse_request(&mut request, REQUEST); - assert_eq!(result, Ok(Status::Complete(69))); - } - - #[test] - fn test_response_header_with_missing_colon_with_folding() { - const RESPONSE: &[u8] = - b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials \r\n hello\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .allow_obsolete_multiline_headers_in_responses(true) - .allow_spaces_after_header_name_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Ok(Status::Complete(81))); - - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "Bread"); - assert_eq!(response.headers[0].value, &b"baguette"[..]); - } - - #[test] - fn test_request_header_with_missing_colon_with_folding() { - const REQUEST: &[u8] = - b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials \r\n hello\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_requests(true) - .parse_request(&mut request, REQUEST); - assert_eq!(result, Ok(Status::Complete(80))); - } - - #[test] - fn test_response_header_with_nul_in_header_name() { - const RESPONSE: &[u8] = - b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Cred\0entials: hello\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderName)); - } - - #[test] - fn test_request_header_with_nul_in_header_name() { - const REQUEST: &[u8] = - b"GET / HTTP/1.1\r\nAccess-Control-Allow-Cred\0entials: hello\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_requests(true) - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderName)); - } - - #[test] - fn test_header_with_cr_in_header_name() { - const RESPONSE: &[u8] = - b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Cred\rentials: hello\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderName)); - - const REQUEST: &[u8] = - b"GET / HTTP/1.1\r\nAccess-Control-Allow-Cred\rentials: hello\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_requests(true) - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderName)); - } - - #[test] - fn test_header_with_nul_in_whitespace_before_colon() { - const RESPONSE: &[u8] = - b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials \0: hello\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .allow_spaces_after_header_name_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderName)); - - let result = crate::ParserConfig::default() - .allow_spaces_after_header_name_in_responses(true) - .ignore_invalid_headers_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderName)); - - const REQUEST: &[u8] = - b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials \0: hello\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_requests(true) - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderName)); - } - - #[test] - fn test_header_with_nul_in_value() { - const RESPONSE: &[u8] = - b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials: hell\0o\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderValue)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderValue)); - - const REQUEST: &[u8] = - b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials: hell\0o\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderValue)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_requests(true) - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderValue)); - } - - #[test] - fn test_header_with_invalid_char_in_value() { - const RESPONSE: &[u8] = - b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials: hell\x01o\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderValue)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Ok(Status::Complete(78))); - - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "Bread"); - assert_eq!(response.headers[0].value, &b"baguette"[..]); - - const REQUEST: &[u8] = - b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials: hell\x01o\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderValue)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_requests(true) - .parse_request(&mut request, REQUEST); - assert_eq!(result, Ok(Status::Complete(77))); - - assert_eq!(request.version.unwrap(), 1); - assert_eq!(request.method.unwrap(), "GET"); - assert_eq!(request.path.unwrap(), "/"); - assert_eq!(request.headers.len(), 1); - assert_eq!(request.headers[0].name, "Bread"); - assert_eq!(request.headers[0].value, &b"baguette"[..]); - } - - #[test] - fn test_header_with_invalid_char_in_value_with_folding() { - const RESPONSE: &[u8] = - b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials: hell\x01o \n world!\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut response = Response::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Err(crate::Error::HeaderValue)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_responses(true) - .parse_response(&mut response, RESPONSE); - assert_eq!(result, Ok(Status::Complete(88))); - - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "Bread"); - assert_eq!(response.headers[0].value, &b"baguette"[..]); - - const REQUEST: &[u8] = - b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials: hell\x01o \n world!\r\nBread: baguette\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 2]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default() - .parse_request(&mut request, REQUEST); - assert_eq!(result, Err(crate::Error::HeaderValue)); - - let result = crate::ParserConfig::default() - .ignore_invalid_headers_in_requests(true) - .parse_request(&mut request, REQUEST); - assert_eq!(result, Ok(Status::Complete(87))); - - assert_eq!(request.version.unwrap(), 1); - assert_eq!(request.method.unwrap(), "GET"); - assert_eq!(request.path.unwrap(), "/"); - assert_eq!(request.headers.len(), 1); - assert_eq!(request.headers[0].name, "Bread"); - assert_eq!(request.headers[0].value, &b"baguette"[..]); - } - - #[test] - fn test_method_within_buffer() { - const REQUEST: &[u8] = b"GET / HTTP/1.1\r\n\r\n"; - - let mut headers = [EMPTY_HEADER; 0]; - let mut request = Request::new(&mut headers[..]); - - crate::ParserConfig::default() - .parse_request(&mut request, REQUEST) - .unwrap(); - - // SAFETY: will not wrap - let buf_end = unsafe { REQUEST.as_ptr().add(REQUEST.len()) }; - // Check that the method str is within the buffer - let method = request.method.unwrap(); - assert!(REQUEST.as_ptr() <= method.as_ptr()); - assert!(method.as_ptr() <= buf_end); - } - - static RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER: &[u8] = - b"HTTP/1.1 200 OK\r\n Space-Before-Header: hello there\r\n\r\n"; - - #[test] - fn test_forbid_response_with_space_before_first_header() { - let mut headers = [EMPTY_HEADER; 1]; - let mut response = Response::new(&mut headers[..]); - let result = response.parse(RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER); - - assert_eq!(result, Err(crate::Error::HeaderName)); - } - - #[test] - fn test_allow_response_response_with_space_before_first_header() { - let mut headers = [EMPTY_HEADER; 1]; - let mut response = Response::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .allow_space_before_first_header_name(true) - .parse_response(&mut response, RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER); - - assert_eq!( - result, - Ok(Status::Complete( - RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER.len() - )) - ); - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "Space-Before-Header"); - assert_eq!(response.headers[0].value, &b"hello there"[..]); - } - - #[test] - fn test_no_space_after_colon() { - let mut headers = [EMPTY_HEADER; 1]; - let mut response = Response::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .parse_response(&mut response, b"HTTP/1.1 200 OK\r\nfoo:bar\r\n\r\n"); - - assert_eq!(result, Ok(Status::Complete(28))); - assert_eq!(response.version.unwrap(), 1); - assert_eq!(response.code.unwrap(), 200); - assert_eq!(response.reason.unwrap(), "OK"); - assert_eq!(response.headers.len(), 1); - assert_eq!(response.headers[0].name, "foo"); - assert_eq!(response.headers[0].value, &b"bar"[..]); - } - - #[test] - fn test_request_with_leading_space() { - let mut headers = [EMPTY_HEADER; 1]; - let mut request = Request::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .parse_request(&mut request, b" GET / HTTP/1.1\r\nfoo:bar\r\n\r\n"); - - assert_eq!(result, Err(Error::Token)); - } - - #[test] - fn test_request_with_invalid_method() { - let mut headers = [EMPTY_HEADER; 1]; - let mut request = Request::new(&mut headers[..]); - let result = crate::ParserConfig::default() - .parse_request(&mut request, b"P()ST / HTTP/1.1\r\nfoo:bar\r\n\r\n"); - - assert_eq!(result, Err(Error::Token)); - } - - #[test] - fn test_utf8_in_path_ok() { - let mut headers = [EMPTY_HEADER; 1]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default().parse_request(&mut request, b"GET /test?post=I\xE2\x80\x99msorryIforkedyou HTTP/1.1\r\nHost: example.org\r\n\r\n"); - - assert_eq!(result, Ok(Status::Complete(67))); - assert_eq!(request.version.unwrap(), 1); - assert_eq!(request.method.unwrap(), "GET"); - assert_eq!(request.path.unwrap(), "/test?post=I’msorryIforkedyou"); - assert_eq!(request.headers.len(), 1); - assert_eq!(request.headers[0].name, "Host"); - assert_eq!(request.headers[0].value, &b"example.org"[..]); - } - - #[test] - fn test_bad_utf8_in_path() { - let mut headers = [EMPTY_HEADER; 1]; - let mut request = Request::new(&mut headers[..]); - - let result = crate::ParserConfig::default().parse_request(&mut request, b"GET /test?post=I\xE2msorryIforkedyou HTTP/1.1\r\nHost: example.org\r\n\r\n"); - - assert_eq!(result, Err(crate::Error::Token)); - } -} diff --git a/vendor/httparse/src/macros.rs b/vendor/httparse/src/macros.rs deleted file mode 100644 index 751f60b3..00000000 --- a/vendor/httparse/src/macros.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Utility macros - -macro_rules! next { - ($bytes:ident) => ({ - match $bytes.next() { - Some(b) => b, - None => return Ok(Status::Partial) - } - }) -} - -macro_rules! expect { - ($bytes:ident.next() == $pat:pat => $ret:expr) => { - expect!(next!($bytes) => $pat |? $ret) - }; - ($e:expr => $pat:pat |? $ret:expr) => { - match $e { - v@$pat => v, - _ => return $ret - } - }; -} - -macro_rules! complete { - ($e:expr) => { - match $e? { - Status::Complete(v) => v, - Status::Partial => return Ok(Status::Partial) - } - } -} - -macro_rules! byte_map { - ($($p:pat)|+) => {{ - const fn make_map() -> [bool; 256] { - let mut ret = [false; 256]; - let mut i = 0; - while i < 256 { - ret[i] = matches!(i as u8, $($p)|+); - i += 1; - } - ret - } - make_map() - }} -} - -macro_rules! space { - ($bytes:ident or $err:expr) => ({ - expect!($bytes.next() == b' ' => Err($err)); - $bytes.slice(); - }) -} - -macro_rules! newline { - ($bytes:ident) => ({ - match next!($bytes) { - b'\r' => { - expect!($bytes.next() == b'\n' => Err(Error::NewLine)); - $bytes.slice(); - }, - b'\n' => { - $bytes.slice(); - }, - _ => return Err(Error::NewLine) - } - }) -} diff --git a/vendor/httparse/src/simd/avx2.rs b/vendor/httparse/src/simd/avx2.rs deleted file mode 100644 index 2adf0a28..00000000 --- a/vendor/httparse/src/simd/avx2.rs +++ /dev/null @@ -1,206 +0,0 @@ -use crate::iter::Bytes; - -#[inline] -#[target_feature(enable = "avx2")] -pub unsafe fn match_uri_vectored(bytes: &mut Bytes) { - while bytes.as_ref().len() >= 32 { - - let advance = match_url_char_32_avx(bytes.as_ref()); - - bytes.advance(advance); - - if advance != 32 { - return; - } - } - // NOTE: use SWAR for <32B, more efficient than falling back to SSE4.2 - super::swar::match_uri_vectored(bytes) -} - -#[inline(always)] -#[allow(non_snake_case, overflowing_literals)] -#[allow(unused)] -unsafe fn match_url_char_32_avx(buf: &[u8]) -> usize { - // NOTE: This check might be not necessary since this function is only used in - // `match_uri_vectored` where buffer overflow is taken care of. - debug_assert!(buf.len() >= 32); - - #[cfg(target_arch = "x86")] - use core::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::*; - - // pointer to buffer - let ptr = buf.as_ptr(); - - // %x21-%x7e %x80-%xff - // - // Character ranges allowed by this function, can also be interpreted as: - // 33 =< (x != 127) =< 255 - // - // Create a vector full of DEL (0x7f) characters. - let DEL: __m256i = _mm256_set1_epi8(0x7f); - // Create a vector full of exclamation mark (!) (0x21) characters. - // Used as lower threshold, characters in URLs cannot be smaller than this. - let LOW: __m256i = _mm256_set1_epi8(0x21); - - // Load a chunk of 32 bytes from `ptr` as a vector. - // We can check 32 bytes in parallel at most with AVX2 since - // YMM registers can only have 256 bits most. - let dat = _mm256_lddqu_si256(ptr as *const _); - - // unsigned comparison dat >= LOW - // - // `_mm256_max_epu8` creates a new vector by comparing vectors `dat` and `LOW` - // and picks the max. values from each for all indices. - // So if a byte in `dat` is <= 32, it'll be represented as 33 - // which is the smallest valid character. - // - // Then, we compare the new vector with `dat` for equality. - // - // `_mm256_cmpeq_epi8` returns a new vector where; - // * matching bytes are set to 0xFF (all bits set), - // * nonmatching bytes are set to 0 (no bits set). - let low = _mm256_cmpeq_epi8(_mm256_max_epu8(dat, LOW), dat); - // Similar to what we did before, but now invalid characters are set to 0xFF. - let del = _mm256_cmpeq_epi8(dat, DEL); - - // We glue the both comparisons via `_mm256_andnot_si256`. - // - // Since the representation of truthiness differ in these comparisons, - // we are in need of bitwise NOT to convert valid characters of `del`. - let bit = _mm256_andnot_si256(del, low); - // This creates a bitmask from the most significant bit of each byte. - // Simply, we're converting a vector value to scalar value here. - let res = _mm256_movemask_epi8(bit) as u32; - - // Count trailing zeros to find the first encountered invalid character. - // Bitwise NOT is required once again to flip truthiness. - // TODO: use .trailing_ones() once MSRV >= 1.46 - (!res).trailing_zeros() as usize -} - -#[target_feature(enable = "avx2")] -pub unsafe fn match_header_value_vectored(bytes: &mut Bytes) { - while bytes.as_ref().len() >= 32 { - let advance = match_header_value_char_32_avx(bytes.as_ref()); - bytes.advance(advance); - - if advance != 32 { - return; - } - } - // NOTE: use SWAR for <32B, more efficient than falling back to SSE4.2 - super::swar::match_header_value_vectored(bytes) -} - -#[inline(always)] -#[allow(non_snake_case)] -#[allow(unused)] -unsafe fn match_header_value_char_32_avx(buf: &[u8]) -> usize { - debug_assert!(buf.len() >= 32); - - #[cfg(target_arch = "x86")] - use core::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::*; - - let ptr = buf.as_ptr(); - - // %x09 %x20-%x7e %x80-%xff - // Create a vector full of horizontal tab (\t) (0x09) characters. - let TAB: __m256i = _mm256_set1_epi8(0x09); - // Create a vector full of DEL (0x7f) characters. - let DEL: __m256i = _mm256_set1_epi8(0x7f); - // Create a vector full of space (0x20) characters. - let LOW: __m256i = _mm256_set1_epi8(0x20); - - // Load a chunk of 32 bytes from `ptr` as a vector. - let dat = _mm256_lddqu_si256(ptr as *const _); - - // unsigned comparison dat >= LOW - // - // Same as what we do in `match_url_char_32_avx`. - // This time the lower threshold is set to space character though. - let low = _mm256_cmpeq_epi8(_mm256_max_epu8(dat, LOW), dat); - // Check if `dat` includes `TAB` characters. - let tab = _mm256_cmpeq_epi8(dat, TAB); - // Check if `dat` includes `DEL` characters. - let del = _mm256_cmpeq_epi8(dat, DEL); - - // Combine all comparisons together, notice that we're also using OR - // to connect `low` and `tab` but flip bits of `del`. - // - // In the end, this is simply: - // ~del & (low | tab) - let bit = _mm256_andnot_si256(del, _mm256_or_si256(low, tab)); - // This creates a bitmask from the most significant bit of each byte. - // Creates a scalar value from vector value. - let res = _mm256_movemask_epi8(bit) as u32; - - // Count trailing zeros to find the first encountered invalid character. - // Bitwise NOT is required once again to flip truthiness. - // TODO: use .trailing_ones() once MSRV >= 1.46 - (!res).trailing_zeros() as usize -} - -#[test] -fn avx2_code_matches_uri_chars_table() { - if !is_x86_feature_detected!("avx2") { - return; - } - - #[allow(clippy::undocumented_unsafe_blocks)] - unsafe { - assert!(byte_is_allowed(b'_', match_uri_vectored)); - - for (b, allowed) in crate::URI_MAP.iter().cloned().enumerate() { - assert_eq!( - byte_is_allowed(b as u8, match_uri_vectored), allowed, - "byte_is_allowed({:?}) should be {:?}", b, allowed, - ); - } - } -} - -#[test] -fn avx2_code_matches_header_value_chars_table() { - if !is_x86_feature_detected!("avx2") { - return; - } - - #[allow(clippy::undocumented_unsafe_blocks)] - unsafe { - assert!(byte_is_allowed(b'_', match_header_value_vectored)); - - for (b, allowed) in crate::HEADER_VALUE_MAP.iter().cloned().enumerate() { - assert_eq!( - byte_is_allowed(b as u8, match_header_value_vectored), allowed, - "byte_is_allowed({:?}) should be {:?}", b, allowed, - ); - } - } -} - -#[cfg(test)] -unsafe fn byte_is_allowed(byte: u8, f: unsafe fn(bytes: &mut Bytes<'_>)) -> bool { - let slice = [ - b'_', b'_', b'_', b'_', - b'_', b'_', b'_', b'_', - b'_', b'_', b'_', b'_', - b'_', b'_', b'_', b'_', - b'_', b'_', b'_', b'_', - b'_', b'_', b'_', b'_', - b'_', b'_', byte, b'_', - b'_', b'_', b'_', b'_', - ]; - let mut bytes = Bytes::new(&slice); - - f(&mut bytes); - - match bytes.pos() { - 32 => true, - 26 => false, - _ => unreachable!(), - } -} diff --git a/vendor/httparse/src/simd/mod.rs b/vendor/httparse/src/simd/mod.rs deleted file mode 100644 index 0e4493a5..00000000 --- a/vendor/httparse/src/simd/mod.rs +++ /dev/null @@ -1,153 +0,0 @@ -mod swar; - -#[cfg(not(all( - httparse_simd, - any( - target_arch = "x86", - target_arch = "x86_64", - all( - target_arch = "aarch64", - httparse_simd_neon_intrinsics, - ) - ), -)))] -pub use self::swar::*; - -#[cfg(all( - httparse_simd, - not(httparse_simd_target_feature_avx2), - any( - target_arch = "x86", - target_arch = "x86_64", - ), -))] -mod sse42; - -#[cfg(all( - httparse_simd, - any( - httparse_simd_target_feature_avx2, - not(httparse_simd_target_feature_sse42), - ), - any( - target_arch = "x86", - target_arch = "x86_64", - ), -))] -mod avx2; - -#[cfg(all( - httparse_simd, - not(any( - httparse_simd_target_feature_sse42, - httparse_simd_target_feature_avx2, - )), - any( - target_arch = "x86", - target_arch = "x86_64", - ), -))] -mod runtime; - -#[cfg(all( - httparse_simd, - not(any( - httparse_simd_target_feature_sse42, - httparse_simd_target_feature_avx2, - )), - any( - target_arch = "x86", - target_arch = "x86_64", - ), -))] -pub use self::runtime::*; - -#[cfg(all( - httparse_simd, - httparse_simd_target_feature_sse42, - not(httparse_simd_target_feature_avx2), - any( - target_arch = "x86", - target_arch = "x86_64", - ), -))] -mod sse42_compile_time { - #[inline(always)] - pub fn match_header_name_vectored(b: &mut crate::iter::Bytes<'_>) { - super::swar::match_header_name_vectored(b); - } - - #[inline(always)] - pub fn match_uri_vectored(b: &mut crate::iter::Bytes<'_>) { - // SAFETY: calls are guarded by a compile time feature check - unsafe { crate::simd::sse42::match_uri_vectored(b) } - } - - #[inline(always)] - pub fn match_header_value_vectored(b: &mut crate::iter::Bytes<'_>) { - // SAFETY: calls are guarded by a compile time feature check - unsafe { crate::simd::sse42::match_header_value_vectored(b) } - } -} - -#[cfg(all( - httparse_simd, - httparse_simd_target_feature_sse42, - not(httparse_simd_target_feature_avx2), - any( - target_arch = "x86", - target_arch = "x86_64", - ), -))] -pub use self::sse42_compile_time::*; - -#[cfg(all( - httparse_simd, - httparse_simd_target_feature_avx2, - any( - target_arch = "x86", - target_arch = "x86_64", - ), -))] -mod avx2_compile_time { - #[inline(always)] - pub fn match_header_name_vectored(b: &mut crate::iter::Bytes<'_>) { - super::swar::match_header_name_vectored(b); - } - - #[inline(always)] - pub fn match_uri_vectored(b: &mut crate::iter::Bytes<'_>) { - // SAFETY: calls are guarded by a compile time feature check - unsafe { crate::simd::avx2::match_uri_vectored(b) } - } - - #[inline(always)] - pub fn match_header_value_vectored(b: &mut crate::iter::Bytes<'_>) { - // SAFETY: calls are guarded by a compile time feature check - unsafe { crate::simd::avx2::match_header_value_vectored(b) } - } -} - -#[cfg(all( - httparse_simd, - httparse_simd_target_feature_avx2, - any( - target_arch = "x86", - target_arch = "x86_64", - ), -))] -pub use self::avx2_compile_time::*; - -#[cfg(all( - httparse_simd, - target_arch = "aarch64", - httparse_simd_neon_intrinsics, -))] -mod neon; - -#[cfg(all( - httparse_simd, - target_arch = "aarch64", - httparse_simd_neon_intrinsics, -))] -pub use self::neon::*; diff --git a/vendor/httparse/src/simd/neon.rs b/vendor/httparse/src/simd/neon.rs deleted file mode 100644 index b059efb2..00000000 --- a/vendor/httparse/src/simd/neon.rs +++ /dev/null @@ -1,258 +0,0 @@ -use crate::iter::Bytes; -use core::arch::aarch64::*; - -#[inline] -pub fn match_header_name_vectored(bytes: &mut Bytes) { - while bytes.as_ref().len() >= 16 { - // SAFETY: ensured that there are at least 16 bytes remaining - unsafe { - let advance = match_header_name_char_16_neon(bytes.as_ref().as_ptr()); - bytes.advance(advance); - - if advance != 16 { - return; - } - } - } - super::swar::match_header_name_vectored(bytes); -} - -#[inline] -pub fn match_header_value_vectored(bytes: &mut Bytes) { - while bytes.as_ref().len() >= 16 { - // SAFETY: ensured that there are at least 16 bytes remaining - unsafe { - let advance = match_header_value_char_16_neon(bytes.as_ref().as_ptr()); - bytes.advance(advance); - - if advance != 16 { - return; - } - } - } - super::swar::match_header_value_vectored(bytes); -} - -#[inline] -pub fn match_uri_vectored(bytes: &mut Bytes) { - while bytes.as_ref().len() >= 16 { - // SAFETY: ensured that there are at least 16 bytes remaining - unsafe { - let advance = match_url_char_16_neon(bytes.as_ref().as_ptr()); - bytes.advance(advance); - - if advance != 16 { - return; - } - } - } - super::swar::match_uri_vectored(bytes); -} - -const fn bit_set(x: u8) -> bool { - // Validates if a byte is a valid header name character - // https://tools.ietf.org/html/rfc7230#section-3.2.6 - matches!(x, b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' | b'!' | b'#' | b'$' | b'%' | b'&' | b'\'' | b'*' | b'+' | b'-' | b'.' | b'^' | b'_' | b'`' | b'|' | b'~') -} - -// A 256-bit bitmap, split into two halves -// lower half contains bits whose higher nibble is <= 7 -// higher half contains bits whose higher nibble is >= 8 -const fn build_bitmap() -> ([u8; 16], [u8; 16]) { - let mut bitmap_0_7 = [0u8; 16]; // 0x00..0x7F - let mut bitmap_8_15 = [0u8; 16]; // 0x80..0xFF - let mut i = 0; - while i < 256 { - if bit_set(i as u8) { - // Nibbles - let (lo, hi) = (i & 0x0F, i >> 4); - if i < 128 { - bitmap_0_7[lo] |= 1 << hi; - } else { - bitmap_8_15[lo] |= 1 << hi; - } - } - i += 1; - } - (bitmap_0_7, bitmap_8_15) -} - -const BITMAPS: ([u8; 16], [u8; 16]) = build_bitmap(); - -// NOTE: adapted from 256-bit version, with upper 128-bit ops commented out -#[inline] -unsafe fn match_header_name_char_16_neon(ptr: *const u8) -> usize { - let bitmaps = BITMAPS; - // NOTE: ideally compile-time constants - let (bitmap_0_7, _bitmap_8_15) = bitmaps; - let bitmap_0_7 = vld1q_u8(bitmap_0_7.as_ptr()); - // let bitmap_8_15 = vld1q_u8(bitmap_8_15.as_ptr()); - - // Initialize the bitmask_lookup. - const BITMASK_LOOKUP_DATA: [u8; 16] = - [1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128]; - let bitmask_lookup = vld1q_u8(BITMASK_LOOKUP_DATA.as_ptr()); - - // Load 16 input bytes. - let input = vld1q_u8(ptr); - - // Extract indices for row_0_7. - let indices_0_7 = vandq_u8(input, vdupq_n_u8(0x8F)); // 0b1000_1111; - - // Extract indices for row_8_15. - // let msb = vandq_u8(input, vdupq_n_u8(0x80)); - // let indices_8_15 = veorq_u8(indices_0_7, msb); - - // Fetch row_0_7 and row_8_15. - let row_0_7 = vqtbl1q_u8(bitmap_0_7, indices_0_7); - // let row_8_15 = vqtbl1q_u8(bitmap_8_15, indices_8_15); - - // Calculate a bitmask, i.e. (1 << hi_nibble % 8). - let bitmask = vqtbl1q_u8(bitmask_lookup, vshrq_n_u8(input, 4)); - - // Choose rows halves depending on higher nibbles. - // let bitsets = vorrq_u8(row_0_7, row_8_15); - let bitsets = row_0_7; - - // Finally check which bytes belong to the set. - let tmp = vandq_u8(bitsets, bitmask); - let result = vceqq_u8(tmp, bitmask); - - offsetz(result) as usize -} - -#[inline] -unsafe fn match_url_char_16_neon(ptr: *const u8) -> usize { - let input = vld1q_u8(ptr); - - // Check that b'!' <= and b != 127 - let result = vcleq_u8(vdupq_n_u8(b'!'), input); - - // Disallow del - let del = vceqq_u8(input, vdupq_n_u8(0x7F)); - let result = vbicq_u8(result, del); - - offsetz(result) as usize -} - -#[inline] -unsafe fn match_header_value_char_16_neon(ptr: *const u8) -> usize { - let input = vld1q_u8(ptr); - - // Check that b' ' <= and b != 127 or b == 9 - let result = vcleq_u8(vdupq_n_u8(b' '), input); - - // Allow tab - let tab = vceqq_u8(input, vdupq_n_u8(0x09)); - let result = vorrq_u8(result, tab); - - // Disallow del - let del = vceqq_u8(input, vdupq_n_u8(0x7F)); - let result = vbicq_u8(result, del); - - offsetz(result) as usize -} - -#[inline] -unsafe fn offsetz(x: uint8x16_t) -> u32 { - // NOT the vector since it's faster to operate with zeros instead - offsetnz(vmvnq_u8(x)) -} - -#[inline] -unsafe fn offsetnz(x: uint8x16_t) -> u32 { - // Extract two u64 - let x = vreinterpretq_u64_u8(x); - // Extract to general purpose registers to perform clz - let low: u64 = vgetq_lane_u64::<0>(x); - let high: u64 = vgetq_lane_u64::<1>(x); - - #[inline] - fn clz(x: u64) -> u32 { - // perf: rust will unroll this loop - // and it's much faster than rbit + clz so voila - for (i, b) in x.to_ne_bytes().iter().copied().enumerate() { - if b != 0 { - return i as u32; - } - } - 8 // Technically not reachable since zero-guarded - } - - if low != 0 { - clz(low) - } else if high != 0 { - return 8 + clz(high); - } else { - return 16; - } -} - -#[test] -fn neon_code_matches_uri_chars_table() { - #[allow(clippy::undocumented_unsafe_blocks)] - unsafe { - assert!(byte_is_allowed(b'_', match_uri_vectored)); - - for (b, allowed) in crate::URI_MAP.iter().cloned().enumerate() { - assert_eq!( - byte_is_allowed(b as u8, match_uri_vectored), - allowed, - "byte_is_allowed({:?}) should be {:?}", - b, - allowed, - ); - } - } -} - -#[test] -fn neon_code_matches_header_value_chars_table() { - #[allow(clippy::undocumented_unsafe_blocks)] - unsafe { - assert!(byte_is_allowed(b'_', match_header_value_vectored)); - - for (b, allowed) in crate::HEADER_VALUE_MAP.iter().cloned().enumerate() { - assert_eq!( - byte_is_allowed(b as u8, match_header_value_vectored), - allowed, - "byte_is_allowed({:?}) should be {:?}", - b, - allowed, - ); - } - } -} - -#[test] -fn neon_code_matches_header_name_chars_table() { - #[allow(clippy::undocumented_unsafe_blocks)] - unsafe { - assert!(byte_is_allowed(b'_', match_header_name_vectored)); - - for (b, allowed) in crate::TOKEN_MAP.iter().cloned().enumerate() { - assert_eq!( - byte_is_allowed(b as u8, match_header_name_vectored), - allowed, - "byte_is_allowed({:?}) should be {:?}", - b, - allowed, - ); - } - } -} - -#[cfg(test)] -unsafe fn byte_is_allowed(byte: u8, f: unsafe fn(bytes: &mut Bytes<'_>)) -> bool { - let mut slice = [b'_'; 16]; - slice[10] = byte; - let mut bytes = Bytes::new(&slice); - - f(&mut bytes); - - match bytes.pos() { - 16 => true, - 10 => false, - x => panic!("unexpected pos: {}", x), - } -} diff --git a/vendor/httparse/src/simd/runtime.rs b/vendor/httparse/src/simd/runtime.rs deleted file mode 100644 index c523a921..00000000 --- a/vendor/httparse/src/simd/runtime.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::sync::atomic::{AtomicU8, Ordering}; -use crate::iter::Bytes; -use super::avx2; -use super::sse42; - -const AVX2: u8 = 1; -const SSE42: u8 = 2; -const NOP: u8 = 3; - -fn detect_runtime_feature() -> u8 { - if is_x86_feature_detected!("avx2") { - AVX2 - } else if is_x86_feature_detected!("sse4.2") { - SSE42 - } else { - NOP - } -} - -static RUNTIME_FEATURE: AtomicU8 = AtomicU8::new(0); - -#[inline] -fn get_runtime_feature() -> u8 { - let mut feature = RUNTIME_FEATURE.load(Ordering::Relaxed); - if feature == 0 { - feature = detect_runtime_feature(); - RUNTIME_FEATURE.store(feature, Ordering::Relaxed); - } - - feature -} - -pub fn match_header_name_vectored(bytes: &mut Bytes) { - super::swar::match_header_name_vectored(bytes); -} - -pub fn match_uri_vectored(bytes: &mut Bytes) { - // SAFETY: calls are guarded by a feature check - unsafe { - match get_runtime_feature() { - AVX2 => avx2::match_uri_vectored(bytes), - SSE42 => sse42::match_uri_vectored(bytes), - _ /* NOP */ => super::swar::match_uri_vectored(bytes), - } - } -} - -pub fn match_header_value_vectored(bytes: &mut Bytes) { - // SAFETY: calls are guarded by a feature check - unsafe { - match get_runtime_feature() { - AVX2 => avx2::match_header_value_vectored(bytes), - SSE42 => sse42::match_header_value_vectored(bytes), - _ /* NOP */ => super::swar::match_header_value_vectored(bytes), - } - } -} diff --git a/vendor/httparse/src/simd/sse42.rs b/vendor/httparse/src/simd/sse42.rs deleted file mode 100644 index 0fabdfeb..00000000 --- a/vendor/httparse/src/simd/sse42.rs +++ /dev/null @@ -1,142 +0,0 @@ -use crate::iter::Bytes; - -#[target_feature(enable = "sse4.2")] -pub unsafe fn match_uri_vectored(bytes: &mut Bytes) { - while bytes.as_ref().len() >= 16 { - let advance = match_url_char_16_sse(bytes.as_ref()); - - bytes.advance(advance); - - if advance != 16 { - return; - } - } - super::swar::match_uri_vectored(bytes); -} - -#[inline(always)] -#[allow(non_snake_case)] -unsafe fn match_url_char_16_sse(buf: &[u8]) -> usize { - debug_assert!(buf.len() >= 16); - - #[cfg(target_arch = "x86")] - use core::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::*; - - let ptr = buf.as_ptr(); - - // %x21-%x7e %x80-%xff - let DEL: __m128i = _mm_set1_epi8(0x7f); - let LOW: __m128i = _mm_set1_epi8(0x21); - - let dat = _mm_lddqu_si128(ptr as *const _); - // unsigned comparison dat >= LOW - let low = _mm_cmpeq_epi8(_mm_max_epu8(dat, LOW), dat); - let del = _mm_cmpeq_epi8(dat, DEL); - let bit = _mm_andnot_si128(del, low); - let res = _mm_movemask_epi8(bit) as u16; - - // TODO: use .trailing_ones() once MSRV >= 1.46 - (!res).trailing_zeros() as usize -} - -#[target_feature(enable = "sse4.2")] -pub unsafe fn match_header_value_vectored(bytes: &mut Bytes) { - while bytes.as_ref().len() >= 16 { - let advance = match_header_value_char_16_sse(bytes.as_ref()); - bytes.advance(advance); - - if advance != 16 { - return; - } - } - super::swar::match_header_value_vectored(bytes); -} - -#[inline(always)] -#[allow(non_snake_case)] -unsafe fn match_header_value_char_16_sse(buf: &[u8]) -> usize { - debug_assert!(buf.len() >= 16); - - #[cfg(target_arch = "x86")] - use core::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::*; - - let ptr = buf.as_ptr(); - - // %x09 %x20-%x7e %x80-%xff - let TAB: __m128i = _mm_set1_epi8(0x09); - let DEL: __m128i = _mm_set1_epi8(0x7f); - let LOW: __m128i = _mm_set1_epi8(0x20); - - let dat = _mm_lddqu_si128(ptr as *const _); - // unsigned comparison dat >= LOW - let low = _mm_cmpeq_epi8(_mm_max_epu8(dat, LOW), dat); - let tab = _mm_cmpeq_epi8(dat, TAB); - let del = _mm_cmpeq_epi8(dat, DEL); - let bit = _mm_andnot_si128(del, _mm_or_si128(low, tab)); - let res = _mm_movemask_epi8(bit) as u16; - - // TODO: use .trailing_ones() once MSRV >= 1.46 - (!res).trailing_zeros() as usize -} - -#[test] -fn sse_code_matches_uri_chars_table() { - if !is_x86_feature_detected!("sse4.2") { - return; - } - - #[allow(clippy::undocumented_unsafe_blocks)] - unsafe { - assert!(byte_is_allowed(b'_', match_uri_vectored)); - - for (b, allowed) in crate::URI_MAP.iter().cloned().enumerate() { - assert_eq!( - byte_is_allowed(b as u8, match_uri_vectored), allowed, - "byte_is_allowed({:?}) should be {:?}", b, allowed, - ); - } - } -} - -#[test] -fn sse_code_matches_header_value_chars_table() { - if !is_x86_feature_detected!("sse4.2") { - return; - } - - #[allow(clippy::undocumented_unsafe_blocks)] - unsafe { - assert!(byte_is_allowed(b'_', match_header_value_vectored)); - - for (b, allowed) in crate::HEADER_VALUE_MAP.iter().cloned().enumerate() { - assert_eq!( - byte_is_allowed(b as u8, match_header_value_vectored), allowed, - "byte_is_allowed({:?}) should be {:?}", b, allowed, - ); - } - } -} - -#[allow(clippy::missing_safety_doc)] -#[cfg(test)] -unsafe fn byte_is_allowed(byte: u8, f: unsafe fn(bytes: &mut Bytes<'_>)) -> bool { - let slice = [ - b'_', b'_', b'_', b'_', - b'_', b'_', b'_', b'_', - b'_', b'_', byte, b'_', - b'_', b'_', b'_', b'_', - ]; - let mut bytes = Bytes::new(&slice); - - f(&mut bytes); - - match bytes.pos() { - 16 => true, - 10 => false, - _ => unreachable!(), - } -} diff --git a/vendor/httparse/src/simd/swar.rs b/vendor/httparse/src/simd/swar.rs deleted file mode 100644 index e1028d05..00000000 --- a/vendor/httparse/src/simd/swar.rs +++ /dev/null @@ -1,235 +0,0 @@ -/// SWAR: SIMD Within A Register -/// SIMD validator backend that validates register-sized chunks of data at a time. -use crate::{is_header_name_token, is_header_value_token, is_uri_token, Bytes}; - -// Adapt block-size to match native register size, i.e: 32bit => 4, 64bit => 8 -const BLOCK_SIZE: usize = core::mem::size_of::<usize>(); -type ByteBlock = [u8; BLOCK_SIZE]; - -#[inline] -pub fn match_uri_vectored(bytes: &mut Bytes) { - loop { - if let Some(bytes8) = bytes.peek_n::<ByteBlock>(BLOCK_SIZE) { - let n = match_uri_char_8_swar(bytes8); - // SAFETY: using peek_n to retrieve the bytes ensures that there are at least n more bytes - // in `bytes`, so calling `advance(n)` is safe. - unsafe { - bytes.advance(n); - } - if n == BLOCK_SIZE { - continue; - } - } - if let Some(b) = bytes.peek() { - if is_uri_token(b) { - // SAFETY: using peek to retrieve the byte ensures that there is at least 1 more byte - // in bytes, so calling advance is safe. - unsafe { - bytes.advance(1); - } - continue; - } - } - break; - } -} - -#[inline] -pub fn match_header_value_vectored(bytes: &mut Bytes) { - loop { - if let Some(bytes8) = bytes.peek_n::<ByteBlock>(BLOCK_SIZE) { - let n = match_header_value_char_8_swar(bytes8); - // SAFETY: using peek_n to retrieve the bytes ensures that there are at least n more bytes - // in `bytes`, so calling `advance(n)` is safe. - unsafe { - bytes.advance(n); - } - if n == BLOCK_SIZE { - continue; - } - } - if let Some(b) = bytes.peek() { - if is_header_value_token(b) { - // SAFETY: using peek to retrieve the byte ensures that there is at least 1 more byte - // in bytes, so calling advance is safe. - unsafe { - bytes.advance(1); - } - continue; - } - } - break; - } -} - -#[inline] -pub fn match_header_name_vectored(bytes: &mut Bytes) { - while let Some(block) = bytes.peek_n::<ByteBlock>(BLOCK_SIZE) { - let n = match_block(is_header_name_token, block); - // SAFETY: using peek_n to retrieve the bytes ensures that there are at least n more bytes - // in `bytes`, so calling `advance(n)` is safe. - unsafe { - bytes.advance(n); - } - if n != BLOCK_SIZE { - return; - } - } - // SAFETY: match_tail processes at most the remaining data in `bytes`. advances `bytes` to the - // end, but no further. - unsafe { bytes.advance(match_tail(is_header_name_token, bytes.as_ref())) }; -} - -// Matches "tail", i.e: when we have <BLOCK_SIZE bytes in the buffer, should be uncommon -#[cold] -#[inline] -fn match_tail(f: impl Fn(u8) -> bool, bytes: &[u8]) -> usize { - for (i, &b) in bytes.iter().enumerate() { - if !f(b) { - return i; - } - } - bytes.len() -} - -// Naive fallback block matcher -#[inline(always)] -fn match_block(f: impl Fn(u8) -> bool, block: ByteBlock) -> usize { - for (i, &b) in block.iter().enumerate() { - if !f(b) { - return i; - } - } - BLOCK_SIZE -} - -// A const alternative to u64::from_ne_bytes to avoid bumping MSRV (1.36 => 1.44) -// creates a u64 whose bytes are each equal to b -const fn uniform_block(b: u8) -> usize { - (b as u64 * 0x01_01_01_01_01_01_01_01 /* [1_u8; 8] */) as usize -} - -// A byte-wise range-check on an entire word/block, -// ensuring all bytes in the word satisfy `33 <= (x != 127) <= 255` -#[inline] -fn match_uri_char_8_swar(block: ByteBlock) -> usize { - // 33 <= (x != 127) <= 255 - const M: u8 = 0x21; - // uniform block full of exclamation mark (!) (33). - const BM: usize = uniform_block(M); - // uniform block full of 1. - const ONE: usize = uniform_block(0x01); - // uniform block full of DEL (127). - const DEL: usize = uniform_block(0x7f); - // uniform block full of 128. - const M128: usize = uniform_block(128); - - let x = usize::from_ne_bytes(block); // Really just a transmute - let lt = x.wrapping_sub(BM) & !x; // <= m - - let xor_del = x ^ DEL; - let eq_del = xor_del.wrapping_sub(ONE) & !xor_del; // == DEL - - offsetnz((lt | eq_del) & M128) -} - -// A byte-wise range-check on an entire word/block, -// ensuring all bytes in the word satisfy `32 <= (x != 127) <= 255` -#[inline] -fn match_header_value_char_8_swar(block: ByteBlock) -> usize { - // 32 <= (x != 127) <= 255 - const M: u8 = 0x20; - // uniform block full of exclamation mark (!) (33). - const BM: usize = uniform_block(M); - // uniform block full of 1. - const ONE: usize = uniform_block(0x01); - // uniform block full of DEL (127). - const DEL: usize = uniform_block(0x7f); - // uniform block full of 128. - const M128: usize = uniform_block(128); - - let x = usize::from_ne_bytes(block); // Really just a transmute - let lt = x.wrapping_sub(BM) & !x; // <= m - - let xor_del = x ^ DEL; - let eq_del = xor_del.wrapping_sub(ONE) & !xor_del; // == DEL - - offsetnz((lt | eq_del) & M128) -} - -/// Check block to find offset of first non-zero byte -// NOTE: Curiously `block.trailing_zeros() >> 3` appears to be slower, maybe revisit -#[inline] -fn offsetnz(block: usize) -> usize { - // fast path optimistic case (common for long valid sequences) - if block == 0 { - return BLOCK_SIZE; - } - - // perf: rust will unroll this loop - for (i, b) in block.to_ne_bytes().iter().copied().enumerate() { - if b != 0 { - return i; - } - } - unreachable!() -} - -#[test] -fn test_is_header_value_block() { - let is_header_value_block = |b| match_header_value_char_8_swar(b) == BLOCK_SIZE; - - // 0..32 => false - for b in 0..32_u8 { - assert!(!is_header_value_block([b; BLOCK_SIZE]), "b={}", b); - } - // 32..=126 => true - for b in 32..=126_u8 { - assert!(is_header_value_block([b; BLOCK_SIZE]), "b={}", b); - } - // 127 => false - assert!(!is_header_value_block([b'\x7F'; BLOCK_SIZE]), "b={}", b'\x7F'); - // 128..=255 => true - for b in 128..=255_u8 { - assert!(is_header_value_block([b; BLOCK_SIZE]), "b={}", b); - } - - - #[cfg(target_pointer_width = "64")] - { - // A few sanity checks on non-uniform bytes for safe-measure - assert!(!is_header_value_block(*b"foo.com\n")); - assert!(!is_header_value_block(*b"o.com\r\nU")); - } -} - -#[test] -fn test_is_uri_block() { - let is_uri_block = |b| match_uri_char_8_swar(b) == BLOCK_SIZE; - - // 0..33 => false - for b in 0..33_u8 { - assert!(!is_uri_block([b; BLOCK_SIZE]), "b={}", b); - } - // 33..=126 => true - for b in 33..=126_u8 { - assert!(is_uri_block([b; BLOCK_SIZE]), "b={}", b); - } - // 127 => false - assert!(!is_uri_block([b'\x7F'; BLOCK_SIZE]), "b={}", b'\x7F'); - // 128..=255 => true - for b in 128..=255_u8 { - assert!(is_uri_block([b; BLOCK_SIZE]), "b={}", b); - } -} - -#[test] -fn test_offsetnz() { - let seq = [0_u8; BLOCK_SIZE]; - for i in 0..BLOCK_SIZE { - let mut seq = seq; - seq[i] = 1; - let x = usize::from_ne_bytes(seq); - assert_eq!(offsetnz(x), i); - } -} diff --git a/vendor/httparse/tests/uri.rs b/vendor/httparse/tests/uri.rs deleted file mode 100644 index e0ceab47..00000000 --- a/vendor/httparse/tests/uri.rs +++ /dev/null @@ -1,3692 +0,0 @@ - -use httparse::{Error, Request, Status, EMPTY_HEADER}; - -const NUM_OF_HEADERS: usize = 4; - -macro_rules! req { - ($name:ident, $buf:expr, |$arg:ident| $body:expr) => ( - req! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body } - ); - ($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => ( - #[test] - fn $name() { - let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; - let mut req = Request::new(&mut headers[..]); - let status = req.parse($buf.as_ref()); - assert_eq!(status, $len); - closure(req); - - fn closure($arg: Request<'_, '_>) { - $body - } - } - ) -} - -req! { - urltest_001, - b"GET /bar;par?b HTTP/1.1\r\nHost: foo\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/bar;par?b"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo"); - } -} - - -req! { - urltest_002, - b"GET /x HTTP/1.1\r\nHost: test\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/x"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"test"); - } -} - - -req! { - urltest_003, - b"GET /x HTTP/1.1\r\nHost: test\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/x"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"test"); - } -} - - -req! { - urltest_004, - b"GET /foo/foo.com HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/foo.com"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_005, - b"GET /foo/:foo.com HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/:foo.com"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_006, - b"GET /foo/foo.com HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/foo.com"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_007, - b"GET foo.com HTTP/1.1\r\nHost: \r\n\r\n", - Err(Error::Token), - |_r| {} -} - - -req! { - urltest_008, - b"GET /%20b%20?%20d%20 HTTP/1.1\r\nHost: f\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/%20b%20?%20d%20"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"f"); - } -} - - -req! { - urltest_009, - b"GET x x HTTP/1.1\r\nHost: \r\n\r\n", - Err(Error::Version), - |_r| {} -} - - -req! { - urltest_010, - b"GET /c HTTP/1.1\r\nHost: f\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/c"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"f"); - } -} - - -req! { - urltest_011, - b"GET /c HTTP/1.1\r\nHost: f\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/c"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"f"); - } -} - - -req! { - urltest_012, - b"GET /c HTTP/1.1\r\nHost: f\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/c"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"f"); - } -} - - -req! { - urltest_013, - b"GET /c HTTP/1.1\r\nHost: f\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/c"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"f"); - } -} - - -req! { - urltest_014, - b"GET /c HTTP/1.1\r\nHost: f\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/c"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"f"); - } -} - - -req! { - urltest_015, - b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_016, - b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_017, - b"GET /foo/:foo.com/ HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/:foo.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_018, - b"GET /foo/:foo.com/ HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/:foo.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_019, - b"GET /foo/: HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/:"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_020, - b"GET /foo/:a HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/:a"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_021, - b"GET /foo/:/ HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_022, - b"GET /foo/:/ HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_023, - b"GET /foo/: HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/:"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_024, - b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_025, - b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_026, - b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_027, - b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_028, - b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_029, - b"GET /foo/:23 HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/:23"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_030, - b"GET /:23 HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/:23"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_031, - b"GET /foo/:: HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/::"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_032, - b"GET /foo/::23 HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/::23"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_033, - b"GET /d HTTP/1.1\r\nHost: c\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/d"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"c"); - } -} - - -req! { - urltest_034, - b"GET /foo/:@c:29 HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/:@c:29"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_035, - b"GET //@ HTTP/1.1\r\nHost: foo.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "//@"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo.com"); - } -} - - -req! { - urltest_036, - b"GET /b:c/d@foo.com/ HTTP/1.1\r\nHost: a\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/b:c/d@foo.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"a"); - } -} - - -req! { - urltest_037, - b"GET /bar.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/bar.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_038, - b"GET /////// HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "///////"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_039, - b"GET ///////bar.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "///////bar.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_040, - b"GET //:///// HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "//://///"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_041, - b"GET /foo HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_042, - b"GET /bar HTTP/1.1\r\nHost: foo\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo"); - } -} - - -req! { - urltest_043, - b"GET /path;a??e HTTP/1.1\r\nHost: foo\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/path;a??e"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo"); - } -} - - -req! { - urltest_044, - b"GET /abcd?efgh?ijkl HTTP/1.1\r\nHost: foo\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/abcd?efgh?ijkl"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo"); - } -} - - -req! { - urltest_045, - b"GET /abcd HTTP/1.1\r\nHost: foo\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/abcd"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo"); - } -} - - -req! { - urltest_046, - b"GET /foo/[61:24:74]:98 HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/[61:24:74]:98"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_047, - b"GET /foo/[61:27]/:foo HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/[61:27]/:foo"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_048, - b"GET /example.com/ HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_049, - b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_050, - b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_051, - b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_052, - b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_053, - b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_054, - b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_055, - b"GET /foo/example.com/ HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_056, - b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_057, - b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_058, - b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_059, - b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_060, - b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_061, - b"GET /a/b/c HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/a/b/c"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_062, - b"GET /a/%20/c HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/a/%20/c"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_063, - b"GET /a%2fc HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/a%2fc"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_064, - b"GET /a/%2f/c HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/a/%2f/c"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_065, - b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_066, - b"GET text/html,test HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "text/html,test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_067, - b"GET 1234567890 HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "1234567890"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_068, - b"GET /c:/foo/bar.html HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/c:/foo/bar.html"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_069, - b"GET /c:////foo/bar.html HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/c:////foo/bar.html"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_070, - b"GET /C:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_071, - b"GET /C:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_072, - b"GET /C:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_073, - b"GET /file HTTP/1.1\r\nHost: server\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/file"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"server"); - } -} - - -req! { - urltest_074, - b"GET /file HTTP/1.1\r\nHost: server\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/file"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"server"); - } -} - - -req! { - urltest_075, - b"GET /file HTTP/1.1\r\nHost: server\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/file"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"server"); - } -} - - -req! { - urltest_076, - b"GET /foo/bar.txt HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar.txt"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_077, - b"GET /home/me HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/home/me"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_078, - b"GET /test HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_079, - b"GET /test HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_080, - b"GET /tmp/mock/test HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/tmp/mock/test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_081, - b"GET /tmp/mock/test HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/tmp/mock/test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_082, - b"GET /foo HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_083, - b"GET /.foo HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/.foo"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_084, - b"GET /foo/ HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_085, - b"GET /foo/ HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_086, - b"GET /foo/ HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_087, - b"GET /foo/ HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_088, - b"GET /foo/..bar HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/..bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_089, - b"GET /foo/ton HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/ton"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_090, - b"GET /a HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/a"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_091, - b"GET /ton HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/ton"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_092, - b"GET /foo/ HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_093, - b"GET /foo/%2e%2 HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/%2e%2"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_094, - b"GET /%2e.bar HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/%2e.bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_095, - b"GET // HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "//"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_096, - b"GET /foo/ HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_097, - b"GET /foo/bar/ HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_098, - b"GET /foo HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_099, - b"GET /%20foo HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/%20foo"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_100, - b"GET /foo% HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo%"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_101, - b"GET /foo%2 HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo%2"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_102, - b"GET /foo%2zbar HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo%2zbar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_103, - b"GET /foo%2%C3%82%C2%A9zbar HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo%2%C3%82%C2%A9zbar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_104, - b"GET /foo%41%7a HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo%41%7a"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_105, - b"GET /foo%C2%91%91 HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo%C2%91%91"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_106, - b"GET /foo%00%51 HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo%00%51"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_107, - b"GET /(%28:%3A%29) HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/(%28:%3A%29)"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_108, - b"GET /%3A%3a%3C%3c HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/%3A%3a%3C%3c"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_109, - b"GET /foobar HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foobar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_110, - b"GET //foo//bar HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "//foo//bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_111, - b"GET /%7Ffp3%3Eju%3Dduvgw%3Dd HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/%7Ffp3%3Eju%3Dduvgw%3Dd"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_112, - b"GET /@asdf%40 HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/@asdf%40"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_113, - b"GET /%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_114, - b"GET /%E2%80%A5/foo HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/%E2%80%A5/foo"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_115, - b"GET /%EF%BB%BF/foo HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/%EF%BB%BF/foo"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_116, - b"GET /%E2%80%AE/foo/%E2%80%AD/bar HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/%E2%80%AE/foo/%E2%80%AD/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_117, - b"GET /foo?bar=baz HTTP/1.1\r\nHost: www.google.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo?bar=baz"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"www.google.com"); - } -} - - -req! { - urltest_118, - b"GET /foo?bar=baz HTTP/1.1\r\nHost: www.google.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo?bar=baz"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"www.google.com"); - } -} - - -req! { - urltest_119, - b"GET test HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_120, - b"GET /foo%2Ehtml HTTP/1.1\r\nHost: www\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo%2Ehtml"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"www"); - } -} - - -req! { - urltest_121, - b"GET /foo/html HTTP/1.1\r\nHost: www\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/html"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"www"); - } -} - - -req! { - urltest_122, - b"GET /foo HTTP/1.1\r\nHost: www.google.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"www.google.com"); - } -} - - -req! { - urltest_123, - b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_124, - b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_125, - b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_126, - b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_127, - b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_128, - b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_129, - b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_130, - b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_131, - b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_132, - b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_133, - b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "example.com/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_134, - b"GET /test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test.txt"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"www.example.com"); - } -} - - -req! { - urltest_135, - b"GET /test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test.txt"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"www.example.com"); - } -} - - -req! { - urltest_136, - b"GET /test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test.txt"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"www.example.com"); - } -} - - -req! { - urltest_137, - b"GET /test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test.txt"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"www.example.com"); - } -} - - -req! { - urltest_138, - b"GET /aaa/test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/aaa/test.txt"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"www.example.com"); - } -} - - -req! { - urltest_139, - b"GET /test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test.txt"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"www.example.com"); - } -} - - -req! { - urltest_140, - b"GET /%E4%B8%AD/test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/%E4%B8%AD/test.txt"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"www.example.com"); - } -} - - -req! { - urltest_141, - b"GET /... HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/..."); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_142, - b"GET /a HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/a"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_143, - b"GET /%EF%BF%BD?%EF%BF%BD HTTP/1.1\r\nHost: x\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/%EF%BF%BD?%EF%BF%BD"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"x"); - } -} - - -req! { - urltest_144, - b"GET /bar HTTP/1.1\r\nHost: example.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.com"); - } -} - - -req! { - urltest_145, - b"GET test HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_146, - b"GET x@x.com HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "x@x.com"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_147, - b"GET , HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), ","); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_148, - b"GET blank HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "blank"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_149, - b"GET test?test HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "test?test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_150, - b"GET /%60%7B%7D?`{} HTTP/1.1\r\nHost: h\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/%60%7B%7D?`{}"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"h"); - } - -} - - -req! { - urltest_151, - b"GET /?%27 HTTP/1.1\r\nHost: host\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/?%27"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"host"); - } -} - - -req! { - urltest_152, - b"GET /?' HTTP/1.1\r\nHost: host\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/?'"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"host"); - } -} - - -req! { - urltest_153, - b"GET /some/path HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/some/path"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_154, - b"GET /smth HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/smth"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_155, - b"GET /some/path HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/some/path"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_156, - b"GET /pa/i HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/pa/i"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_157, - b"GET /i HTTP/1.1\r\nHost: ho\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/i"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"ho"); - } -} - - -req! { - urltest_158, - b"GET /pa/i HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/pa/i"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_159, - b"GET /i HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/i"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_160, - b"GET /i HTTP/1.1\r\nHost: ho\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/i"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"ho"); - } -} - - -req! { - urltest_161, - b"GET /i HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/i"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_162, - b"GET /i HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/i"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_163, - b"GET /i HTTP/1.1\r\nHost: ho\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/i"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"ho"); - } -} - - -req! { - urltest_164, - b"GET /i HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/i"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_165, - b"GET /pa/pa?i HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/pa/pa?i"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_166, - b"GET /pa?i HTTP/1.1\r\nHost: ho\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/pa?i"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"ho"); - } -} - - -req! { - urltest_167, - b"GET /pa/pa?i HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/pa/pa?i"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_168, - b"GET sd HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "sd"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_169, - b"GET sd/sd HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "sd/sd"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_170, - b"GET /pa/pa HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/pa/pa"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_171, - b"GET /pa HTTP/1.1\r\nHost: ho\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/pa"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"ho"); - } -} - - -req! { - urltest_172, - b"GET /pa/pa HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/pa/pa"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_173, - b"GET /x HTTP/1.1\r\nHost: %C3%B1\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/x"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"%C3%B1"); - } -} - - -req! { - urltest_174, - b"GET \\.\\./ HTTP/1.1\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "\\.\\./"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 0); - } -} - - -req! { - urltest_175, - b"GET :a@example.net HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), ":a@example.net"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_176, - b"GET %NBD HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "%NBD"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_177, - b"GET %1G HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "%1G"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_178, - b"GET /relative_import.html HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/relative_import.html"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"127.0.0.1"); - } -} - - -req! { - urltest_179, - b"GET /?foo=%7B%22abc%22 HTTP/1.1\r\nHost: facebook.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/?foo=%7B%22abc%22"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"facebook.com"); - } -} - - -req! { - urltest_180, - b"GET /jqueryui@1.2.3 HTTP/1.1\r\nHost: localhost\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/jqueryui@1.2.3"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"localhost"); - } -} - - -req! { - urltest_181, - b"GET /path?query HTTP/1.1\r\nHost: host\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/path?query"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"host"); - } -} - - -req! { - urltest_182, - b"GET /foo/bar?a=b&c=d HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar?a=b&c=d"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_183, - b"GET /foo/bar??a=b&c=d HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar??a=b&c=d"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_184, - b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_185, - b"GET /baz?qux HTTP/1.1\r\nHost: foo.bar\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/baz?qux"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo.bar"); - } -} - - -req! { - urltest_186, - b"GET /baz?qux HTTP/1.1\r\nHost: foo.bar\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/baz?qux"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo.bar"); - } -} - - -req! { - urltest_187, - b"GET /baz?qux HTTP/1.1\r\nHost: foo.bar\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/baz?qux"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo.bar"); - } -} - - -req! { - urltest_188, - b"GET /baz?qux HTTP/1.1\r\nHost: foo.bar\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/baz?qux"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo.bar"); - } -} - - -req! { - urltest_189, - b"GET /baz?qux HTTP/1.1\r\nHost: foo.bar\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/baz?qux"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foo.bar"); - } -} - - -req! { - urltest_190, - b"GET /C%3A/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C%3A/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_191, - b"GET /C%7C/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C%7C/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_192, - b"GET /C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_193, - b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_194, - b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_195, - b"GET /d: HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/d:"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_196, - b"GET /d:/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/d:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_197, - b"GET /test?test HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_198, - b"GET /test?test HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_199, - b"GET /test?x HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?x"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_200, - b"GET /test?x HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?x"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_201, - b"GET /test?test HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_202, - b"GET /test?test HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_203, - b"GET /?fox HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/?fox"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_204, - b"GET /localhost//cat HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/localhost//cat"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_205, - b"GET /localhost//cat HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/localhost//cat"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_206, - b"GET /mouse HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/mouse"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_207, - b"GET /pig HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/pig"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_208, - b"GET /pig HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/pig"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_209, - b"GET /pig HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/pig"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_210, - b"GET /localhost//pig HTTP/1.1\r\nHost: lion\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/localhost//pig"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"lion"); - } -} - - -req! { - urltest_211, - b"GET /rooibos HTTP/1.1\r\nHost: tea\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/rooibos"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"tea"); - } -} - - -req! { - urltest_212, - b"GET /?chai HTTP/1.1\r\nHost: tea\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/?chai"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"tea"); - } -} - - -req! { - urltest_213, - b"GET /C: HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_214, - b"GET /C: HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_215, - b"GET /C: HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_216, - b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_217, - b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_218, - b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_219, - b"GET /dir/C HTTP/1.1\r\nHost: host\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/dir/C"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"host"); - } -} - - -req! { - urltest_220, - b"GET /dir/C|a HTTP/1.1\r\nHost: host\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/dir/C|a"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"host"); - } -} - - -req! { - urltest_221, - b"GET /c:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/c:/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_222, - b"GET /c:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/c:/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_223, - b"GET /c:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/c:/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_224, - b"GET /c:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/c:/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_225, - b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_226, - b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_227, - b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_228, - b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_229, - b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/C:/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_230, - b"GET /?q=v HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/?q=v"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_231, - b"GET ?x HTTP/1.1\r\nHost: %C3%B1\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "?x"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"%C3%B1"); - } -} - - -req! { - urltest_232, - b"GET ?x HTTP/1.1\r\nHost: %C3%B1\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "?x"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"%C3%B1"); - } -} - - -req! { - urltest_233, - b"GET // HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "//"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_234, - b"GET //x/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "//x/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_235, - b"GET /someconfig;mode=netascii HTTP/1.1\r\nHost: foobar.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/someconfig;mode=netascii"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"foobar.com"); - } -} - - -req! { - urltest_236, - b"GET /Index.ut2 HTTP/1.1\r\nHost: 10.10.10.10\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/Index.ut2"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"10.10.10.10"); - } -} - - -req! { - urltest_237, - b"GET /0?baz=bam&qux=baz HTTP/1.1\r\nHost: somehost\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/0?baz=bam&qux=baz"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"somehost"); - } -} - - -req! { - urltest_238, - b"GET /sup HTTP/1.1\r\nHost: host\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/sup"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"host"); - } -} - - -req! { - urltest_239, - b"GET /foo/bar.git HTTP/1.1\r\nHost: github.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar.git"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"github.com"); - } -} - - -req! { - urltest_240, - b"GET /channel?passwd HTTP/1.1\r\nHost: myserver.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/channel?passwd"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"myserver.com"); - } -} - - -req! { - urltest_241, - b"GET /foo.bar.org?type=TXT HTTP/1.1\r\nHost: fw.example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo.bar.org?type=TXT"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"fw.example.org"); - } -} - - -req! { - urltest_242, - b"GET /ou=People,o=JNDITutorial HTTP/1.1\r\nHost: localhost\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/ou=People,o=JNDITutorial"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"localhost"); - } -} - - -req! { - urltest_243, - b"GET /foo/bar HTTP/1.1\r\nHost: github.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"github.com"); - } -} - - -req! { - urltest_244, - b"GET ietf:rfc:2648 HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "ietf:rfc:2648"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_245, - b"GET joe@example.org,2001:foo/bar HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "joe@example.org,2001:foo/bar"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_246, - b"GET /path HTTP/1.1\r\nHost: H%4fSt\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/path"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"H%4fSt"); - } -} - - -req! { - urltest_247, - b"GET https://example.com:443/ HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "https://example.com:443/"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_248, - b"GET d3958f5c-0777-0845-9dcf-2cb28783acaf HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "d3958f5c-0777-0845-9dcf-2cb28783acaf"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_249, - b"GET /test?%22 HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?%22"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_250, - b"GET /test HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_251, - b"GET /test?%3C HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?%3C"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_252, - b"GET /test?%3E HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?%3E"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_253, - b"GET /test?%E2%8C%A3 HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?%E2%8C%A3"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_254, - b"GET /test?%23%23 HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?%23%23"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_255, - b"GET /test?%GH HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?%GH"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_256, - b"GET /test?a HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?a"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_257, - b"GET /test?a HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?a"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_258, - b"GET /test-a-colon-slash.html HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test-a-colon-slash.html"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_259, - b"GET /test-a-colon-slash-slash.html HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test-a-colon-slash-slash.html"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_260, - b"GET /test-a-colon-slash-b.html HTTP/1.1\r\nHost: \r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test-a-colon-slash-b.html"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b""); - } -} - - -req! { - urltest_261, - b"GET /test-a-colon-slash-slash-b.html HTTP/1.1\r\nHost: b\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test-a-colon-slash-slash-b.html"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"b"); - } -} - - -req! { - urltest_262, - b"GET /test?a HTTP/1.1\r\nHost: example.org\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/test?a"); - assert_eq!(req.version.unwrap(), 1); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"example.org"); - } -} - - -req! { - urltest_nvidia, - b"GET /nvidia_web_services/controller.gfeclientcontent.php/com.nvidia.services.GFEClientContent.getShieldReady/{\"gcV\":\"2.2.2.0\",\"dID\":\"1341\",\"osC\":\"6.20\",\"is6\":\"1\",\"lg\":\"1033\",\"GFPV\":\"389.08\",\"isO\":\"1\",\"sM\":\"16777216\"} HTTP/1.0\r\nHost: gfwsl.geforce.com\r\n\r\n", - |req| { - assert_eq!(req.method.unwrap(), "GET"); - assert_eq!(req.path.unwrap(), "/nvidia_web_services/controller.gfeclientcontent.php/com.nvidia.services.GFEClientContent.getShieldReady/{\"gcV\":\"2.2.2.0\",\"dID\":\"1341\",\"osC\":\"6.20\",\"is6\":\"1\",\"lg\":\"1033\",\"GFPV\":\"389.08\",\"isO\":\"1\",\"sM\":\"16777216\"}"); - assert_eq!(req.version.unwrap(), 0); - assert_eq!(req.headers.len(), 1); - assert_eq!(req.headers[0].name, "Host"); - assert_eq!(req.headers[0].value, b"gfwsl.geforce.com"); - } -} |
