diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/httparse | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/httparse')
-rw-r--r-- | third_party/rust/httparse/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/httparse/Cargo.toml | 34 | ||||
-rw-r--r-- | third_party/rust/httparse/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | third_party/rust/httparse/LICENSE-MIT | 20 | ||||
-rw-r--r-- | third_party/rust/httparse/README.md | 38 | ||||
-rw-r--r-- | third_party/rust/httparse/benches/parse.rs | 122 | ||||
-rw-r--r-- | third_party/rust/httparse/build.rs | 155 | ||||
-rw-r--r-- | third_party/rust/httparse/src/iter.rs | 156 | ||||
-rw-r--r-- | third_party/rust/httparse/src/lib.rs | 1138 | ||||
-rw-r--r-- | third_party/rust/httparse/src/macros.rs | 59 | ||||
-rw-r--r-- | third_party/rust/httparse/src/simd/avx2.rs | 116 | ||||
-rw-r--r-- | third_party/rust/httparse/src/simd/fallback.rs | 8 | ||||
-rw-r--r-- | third_party/rust/httparse/src/simd/mod.rs | 238 | ||||
-rw-r--r-- | third_party/rust/httparse/src/simd/sse42.rs | 84 | ||||
-rw-r--r-- | third_party/rust/httparse/tests/uri.rs | 3677 |
15 files changed, 6047 insertions, 0 deletions
diff --git a/third_party/rust/httparse/.cargo-checksum.json b/third_party/rust/httparse/.cargo-checksum.json new file mode 100644 index 0000000000..6e45afdaaa --- /dev/null +++ b/third_party/rust/httparse/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"2d893bf5d1e9a5445e74c2a7a75b804492245647004155a798f5456e5c0f4712","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ad5ce29918424008bdd8c6e7851bb064533456cbb32ec0d0955b2bc9444613d3","README.md":"b54e1e379daa12d26aadad7c1bef578a3cbcf243f2f229d8b17868c90a384d7d","benches/parse.rs":"caabd31cbcb00172bb7f31a1398dbed27a3bf36b01d69729c3d6fbd9a4008e05","build.rs":"00bab146ec6a10fac91958a06bdd4b7b4d71932e0480b6e84a4248cb339dbe79","src/iter.rs":"3f165be2f0d3bb7e0cbe37cb67560e36e06cdb5921e145446a5985c3580a6b6e","src/lib.rs":"21436cacd3b33b20ad75877e6260f34391a9215ffa6ad2c10ebf1a0c67ac07dc","src/macros.rs":"25de190f894eefb48a6992f9dc3d039d9065f908f381d683f0395d568d992275","src/simd/avx2.rs":"1b27cad7b5c210f8a1283d423ca18372127ea50f5565b9be0b83d2a51a1eb826","src/simd/fallback.rs":"0234cc11459f3225d6e3d329068a01206e39625a538bdc292e0d1beaa06a37e5","src/simd/mod.rs":"c67e118a45da679d41de0d51c2f632f64902083db4be8f636021dbfe08f0f9b4","src/simd/sse42.rs":"373f5bf0596942b9ba4497a8a89975117ec0da6d8b8c2345fe03e0d28e68627f","tests/uri.rs":"92a0dc4cfa8eee2e6b8e9109e2e0062ccb50b9ec8cb4b7c06794dab1a3e68c9c"},"package":"e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"}
\ No newline at end of file diff --git a/third_party/rust/httparse/Cargo.toml b/third_party/rust/httparse/Cargo.toml new file mode 100644 index 0000000000..34e1b3bcf3 --- /dev/null +++ b/third_party/rust/httparse/Cargo.toml @@ -0,0 +1,34 @@ +# 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 believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "httparse" +version = "1.3.3" +authors = ["Sean McArthur <sean@seanmonstar.com>"] +build = "build.rs" +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/Apache-2.0" +repository = "https://github.com/seanmonstar/httparse" +[profile.bench] +opt-level = 3 +lto = true +codegen-units = 1 +[dev-dependencies.pico-sys] +version = "0.0" + +[features] +default = ["std"] +std = [] diff --git a/third_party/rust/httparse/LICENSE-APACHE b/third_party/rust/httparse/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/httparse/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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/third_party/rust/httparse/LICENSE-MIT b/third_party/rust/httparse/LICENSE-MIT new file mode 100644 index 0000000000..f62775d2bc --- /dev/null +++ b/third_party/rust/httparse/LICENSE-MIT @@ -0,0 +1,20 @@ +Copyright (c) 2015 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/third_party/rust/httparse/README.md b/third_party/rust/httparse/README.md new file mode 100644 index 0000000000..f786302a4d --- /dev/null +++ b/third_party/rust/httparse/README.md @@ -0,0 +1,38 @@ +# httparse + +[![Build Status](https://travis-ci.org/seanmonstar/httparse.svg?branch=master)](https://travis-ci.org/seanmonstar/httparse) +[![Coverage Status](https://coveralls.io/repos/seanmonstar/httparse/badge.svg)](https://coveralls.io/r/seanmonstar/httparse) +[![crates.io](https://img.shields.io/crates/v/httparse.svg)](https://crates.io/crates/httparse) + +A push parser for the HTTP 1.x protocol. Avoids allocations. No copy. **Fast.** + +Works with `no_std`, simply disable the `std` Cargo feature. + +[Documentation](https://docs.rs/httparse) +[Changelog](https://github.com/seanmonstar/httparse/releases) + +## Usage + +```rust +let mut headers = [httparse::EMPTY_HEADER; 16]; +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 http://apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://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/third_party/rust/httparse/benches/parse.rs b/third_party/rust/httparse/benches/parse.rs new file mode 100644 index 0000000000..38e8b58507 --- /dev/null +++ b/third_party/rust/httparse/benches/parse.rs @@ -0,0 +1,122 @@ +#![feature(test)] + +extern crate pico_sys as pico; +extern crate httparse; + +extern crate test; + +const REQ_SHORT: &'static [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: &'static [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"; + + +#[bench] +fn bench_pico(b: &mut test::Bencher) { + use std::mem; + + #[repr(C)] + #[derive(Clone, Copy)] + struct Header<'a>(&'a [u8], &'a [u8]); + + + #[repr(C)] + struct Headers<'a>(&'a mut [Header<'a>]); + let method = [0i8; 16]; + let path = [0i8; 16]; + let mut minor_version = 0; + let mut h = [Header(&[], &[]); 16]; + let mut h_len = h.len(); + let headers = Headers(&mut h); + let prev_buf_len = 0; + + b.iter(|| { + let ret = unsafe { + pico::ffi::phr_parse_request( + REQ.as_ptr() as *const _, + REQ.len(), + &mut method.as_ptr(), + &mut 16, + &mut path.as_ptr(), + &mut 16, + &mut minor_version, + mem::transmute::<*mut Header, *mut pico::ffi::phr_header>(headers.0.as_mut_ptr()), + &mut h_len as *mut usize as *mut _, + prev_buf_len + ) + }; + assert_eq!(ret, REQ.len() as i32); + }); + b.bytes = REQ.len() as u64; +} + +#[bench] +fn bench_httparse(b: &mut test::Bencher) { + let mut headers = [httparse::Header{ name: "", value: &[] }; 16]; + let mut req = httparse::Request::new(&mut headers); + b.iter(|| { + assert_eq!(req.parse(REQ).unwrap(), httparse::Status::Complete(REQ.len())); + }); + b.bytes = REQ.len() as u64; +} + +#[bench] +fn bench_pico_short(b: &mut test::Bencher) { + use std::mem; + + #[repr(C)] + #[derive(Clone, Copy)] + struct Header<'a>(&'a [u8], &'a [u8]); + + + #[repr(C)] + struct Headers<'a>(&'a mut [Header<'a>]); + let method = [0i8; 16]; + let path = [0i8; 16]; + let mut minor_version = 0; + let mut h = [Header(&[], &[]); 16]; + let mut h_len = h.len(); + let headers = Headers(&mut h); + let prev_buf_len = 0; + + b.iter(|| { + let ret = unsafe { + pico::ffi::phr_parse_request( + REQ_SHORT.as_ptr() as *const _, + REQ_SHORT.len(), + &mut method.as_ptr(), + &mut 16, + &mut path.as_ptr(), + &mut 16, + &mut minor_version, + mem::transmute::<*mut Header, *mut pico::ffi::phr_header>(headers.0.as_mut_ptr()), + &mut h_len as *mut usize as *mut _, + prev_buf_len + ) + }; + assert_eq!(ret, REQ_SHORT.len() as i32); + }); + b.bytes = REQ_SHORT.len() as u64; +} + +#[bench] +fn bench_httparse_short(b: &mut test::Bencher) { + let mut headers = [httparse::Header{ name: "", value: &[] }; 16]; + let mut req = httparse::Request::new(&mut headers); + b.iter(|| { + assert_eq!(req.parse(REQ_SHORT).unwrap(), httparse::Status::Complete(REQ_SHORT.len())); + }); + b.bytes = REQ_SHORT.len() as u64; +} diff --git a/third_party/rust/httparse/build.rs b/third_party/rust/httparse/build.rs new file mode 100644 index 0000000000..e46dea0d15 --- /dev/null +++ b/third_party/rust/httparse/build.rs @@ -0,0 +1,155 @@ +use std::env; +use std::ffi::OsString; +use std::process::Command; + +fn main() { + 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 version = String::from_utf8(output) + .expect("rustc version output should be utf-8"); + + enable_new_features(&version); +} + +fn enable_new_features(raw_version: &str) { + let version = match Version::parse(raw_version) { + Ok(version) => version, + Err(err) => { + println!("cargo:warning=failed to parse `rustc --version`: {}", err); + return; + } + }; + + 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; + } + + let env_disable = "CARGO_CFG_HTTPARSE_DISABLE_SIMD"; + if env::var_os(env_disable).is_some() { + println!("cargo:warning=detected {} environment variable, disabling SIMD", env_disable); + return; + } + + let min_simd_version = Version { + major: 1, + minor: 27, + patch: 0, + }; + + if version >= min_simd_version { + 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 env::var_os(env_runtime_only).is_some() { + 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 mut saw_sse42 = false; + let mut saw_avx2 = false; + + for feature in feature_list.split(',') { + let feature = feature.trim(); + if !saw_sse42 && feature == "sse4.2" { + saw_sse42 = true; + println!("cargo:rustc-cfg=httparse_simd_target_feature_sse42"); + } + + if !saw_avx2 && feature == "avx2" { + saw_avx2 = true; + println!("cargo:rustc-cfg=httparse_simd_target_feature_avx2"); + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +struct Version { + major: u32, + minor: u32, + patch: u32, +} + +impl Version { + fn parse(mut s: &str) -> Result<Version, String> { + if !s.starts_with("rustc ") { + return Err(format!("unrecognized version string: {}", s)); + } + s = &s["rustc ".len()..]; + + let parts: Vec<&str> = s.split(".").collect(); + if parts.len() < 3 { + return Err(format!("not enough version parts: {:?}", parts)); + } + + let mut num = String::new(); + for c in parts[0].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let major = try!(num.parse::<u32>().map_err(|e| e.to_string())); + + num.clear(); + for c in parts[1].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let minor = try!(num.parse::<u32>().map_err(|e| e.to_string())); + + num.clear(); + for c in parts[2].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let patch = try!(num.parse::<u32>().map_err(|e| e.to_string())); + + Ok(Version { + major: major, + minor: minor, + patch: patch, + }) + } +} + diff --git a/third_party/rust/httparse/src/iter.rs b/third_party/rust/httparse/src/iter.rs new file mode 100644 index 0000000000..ca2767a1df --- /dev/null +++ b/third_party/rust/httparse/src/iter.rs @@ -0,0 +1,156 @@ +use core::slice; + +pub struct Bytes<'a> { + slice: &'a [u8], + pos: usize +} + +impl<'a> Bytes<'a> { + #[inline] + pub fn new(slice: &'a [u8]) -> Bytes<'a> { + Bytes { + slice: slice, + pos: 0 + } + } + + #[inline] + pub fn pos(&self) -> usize { + self.pos + } + + #[inline] + pub fn peek(&self) -> Option<u8> { + self.slice.get(self.pos).cloned() + } + + #[inline] + pub unsafe fn bump(&mut self) { + debug_assert!(self.pos + 1 <= self.slice.len(), "overflow"); + self.pos += 1; + } + + #[allow(unused)] + #[inline] + pub unsafe fn advance(&mut self, n: usize) { + debug_assert!(self.pos + n <= self.slice.len(), "overflow"); + self.pos += n; + } + + #[inline] + pub fn len(&self) -> usize { + self.slice.len() + } + + #[inline] + pub fn slice(&mut self) -> &'a [u8] { + // not moving position at all, so it's safe + unsafe { + self.slice_skip(0) + } + } + + #[inline] + pub unsafe fn slice_skip(&mut self, skip: usize) -> &'a [u8] { + debug_assert!(self.pos >= skip); + let head_pos = self.pos - skip; + let ptr = self.slice.as_ptr(); + let head = slice::from_raw_parts(ptr, head_pos); + let tail = slice::from_raw_parts(ptr.offset(self.pos as isize), self.slice.len() - self.pos); + self.pos = 0; + self.slice = tail; + head + } + + #[inline] + pub fn next_8<'b>(&'b mut self) -> Option<Bytes8<'b, 'a>> { + if self.slice.len() > self.pos + 8 { + Some(Bytes8::new(self)) + } else { + None + } + } +} + +impl<'a> AsRef<[u8]> for Bytes<'a> { + #[inline] + fn as_ref(&self) -> &[u8] { + &self.slice[self.pos..] + } +} + +impl<'a> Iterator for Bytes<'a> { + type Item = u8; + + #[inline] + fn next(&mut self) -> Option<u8> { + if self.slice.len() > self.pos { + let b = unsafe { *self.slice.get_unchecked(self.pos) }; + self.pos += 1; + Some(b) + } else { + None + } + } +} + +pub struct Bytes8<'a, 'b: 'a> { + bytes: &'a mut Bytes<'b>, + #[cfg(debug_assertions)] + pos: usize +} + +macro_rules! bytes8_methods { + ($f:ident, $pos:expr) => { + #[inline] + pub fn $f(&mut self) -> u8 { + self.assert_pos($pos); + let b = unsafe { *self.bytes.slice.get_unchecked(self.bytes.pos) }; + self.bytes.pos += 1; + b + } + }; + () => { + bytes8_methods!(_0, 0); + bytes8_methods!(_1, 1); + bytes8_methods!(_2, 2); + bytes8_methods!(_3, 3); + bytes8_methods!(_4, 4); + bytes8_methods!(_5, 5); + bytes8_methods!(_6, 6); + bytes8_methods!(_7, 7); + } +} + +impl<'a, 'b: 'a> Bytes8<'a, 'b> { + bytes8_methods! {} + + #[cfg(not(debug_assertions))] + #[inline] + fn new(bytes: &'a mut Bytes<'b>) -> Bytes8<'a, 'b> { + Bytes8 { + bytes: bytes, + } + } + + #[cfg(debug_assertions)] + #[inline] + fn new(bytes: &'a mut Bytes<'b>) -> Bytes8<'a, 'b> { + Bytes8 { + bytes: bytes, + pos: 0, + } + } + + #[cfg(not(debug_assertions))] + #[inline] + fn assert_pos(&mut self, _pos: usize) { + } + + #[cfg(debug_assertions)] + #[inline] + fn assert_pos(&mut self, pos: usize) { + assert!(self.pos == pos); + self.pos += 1; + } +} diff --git a/third_party/rust/httparse/src/lib.rs b/third_party/rust/httparse/src/lib.rs new file mode 100644 index 0000000000..99e9e09953 --- /dev/null +++ b/third_party/rust/httparse/src/lib.rs @@ -0,0 +1,1138 @@ +#![doc(html_root_url = "https://docs.rs/httparse/1.3.3")] +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(test, deny(warnings))] +#![deny(missing_docs)] + +//! # 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. +#[cfg(feature = "std")] +extern crate std as core; + +use core::{fmt, result, str, slice}; + +use iter::Bytes; + +mod iter; +#[macro_use] mod macros; +mod simd; + +#[inline] +fn shrink<T>(slice: &mut &mut [T], len: usize) { + debug_assert!(slice.len() >= len); + let ptr = slice.as_mut_ptr(); + *slice = unsafe { slice::from_raw_parts_mut(ptr, len) }; +} + +/// Determines if byte is a token char. +/// +/// > ```notrust +/// > token = 1*tchar +/// > +/// > tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" +/// > / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" +/// > / DIGIT / ALPHA +/// > ; any VCHAR, except delimiters +/// > ``` +#[inline] +fn is_token(b: u8) -> bool { + b > 0x1F && b < 0x7F +} + +// ASCII codes to accept URI string. +// i.e. A-Z a-z 0-9 !#$%&'*+-._();:@=,/?[]~^ +// TODO: Make a stricter checking for URI string? +static URI_MAP: [bool; 256] = byte_map![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// \0 \n + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// commands + 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// \w ! " # $ % & ' ( ) * + , - . / + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, +// 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// @ A B C D E F G H I J K L M N O + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, +// P Q R S T U V W X Y Z [ \ ] ^ _ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// ` a b c d e f g h i j k l m n o + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, +// p q r s t u v w x y z { | } ~ del +// ====== Extended ASCII (aka. obs-text) ====== + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +#[inline] +fn is_uri_token(b: u8) -> bool { + URI_MAP[b as usize] +} + +static HEADER_NAME_MAP: [bool; 256] = byte_map![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +#[inline] +fn is_header_name_token(b: u8) -> bool { + HEADER_NAME_MAP[b as usize] +} + +static HEADER_VALUE_MAP: [bool; 256] = byte_map![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +]; + + +#[inline] +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, 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") + } + } +} + +/// 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, PartialEq)] +pub struct Request<'headers, 'buf: 'headers> { + /// 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 version, such as `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: headers, + } + } + + /// Try to parse a buffer of bytes into the Request. + pub fn parse(&mut self, buf: &'b [u8]) -> Result<usize> { + let orig_len = buf.len(); + let mut bytes = Bytes::new(buf); + complete!(skip_empty_lines(&mut bytes)); + self.method = Some(complete!(parse_token(&mut bytes))); + self.path = Some(complete!(parse_uri(&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(&mut self.headers, &mut bytes)); + + Ok(Status::Complete(len + headers_len)) + } +} + +#[inline] +fn skip_empty_lines(bytes: &mut Bytes) -> Result<()> { + loop { + let b = bytes.peek(); + match b { + Some(b'\r') => { + // there's `\r`, so it's safe to bump 1 pos + unsafe { bytes.bump() }; + expect!(bytes.next() == b'\n' => Err(Error::NewLine)); + }, + Some(b'\n') => { + // there's `\n`, 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, PartialEq)] +pub struct Response<'headers, 'buf: 'headers> { + /// The response version, such as `HTTP/1.1`. + pub version: Option<u8>, + /// The response code, such as `200`. + pub code: Option<u16>, + /// The response reason-phrase, such as `OK`. + 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: headers, + } + } + + /// Try to parse a buffer of bytes into this `Response`. + pub fn parse(&mut self, buf: &'b [u8]) -> 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); + 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' ' => { + 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' => self.reason = Some(""), + _ => return Err(Error::Status), + } + + + let len = orig_len - bytes.len(); + let headers_len = complete!(parse_headers_iter(&mut self.headers, &mut bytes)); + Ok(Status::Complete(len + headers_len)) + } +} + +/// Represents a parsed header. +#[derive(Copy, Clone, PartialEq, Debug)] +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], +} + +/// 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] +fn parse_version(bytes: &mut Bytes) -> Result<u8> { + if let Some(mut eight) = bytes.next_8() { + expect!(eight._0() => b'H' |? Err(Error::Version)); + expect!(eight._1() => b'T' |? Err(Error::Version)); + expect!(eight._2() => b'T' |? Err(Error::Version)); + expect!(eight._3() => b'P' |? Err(Error::Version)); + expect!(eight._4() => b'/' |? Err(Error::Version)); + expect!(eight._5() => b'1' |? Err(Error::Version)); + expect!(eight._6() => b'.' |? Err(Error::Version)); + let v = match eight._7() { + b'0' => 0, + b'1' => 1, + _ => return Err(Error::Version) + }; + return Ok(Status::Complete(v)) + } + + // 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) +} + +/// 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). +/// +/// Note that the following implementation deliberately rejects the obsoleted (non-US-ASCII) text range. +/// +/// The fully compliant parser should probably just return the reason-phrase as an opaque &[u8] data +/// and leave interpretation to user or specialized helpers (akin to .display() in std::path::Path) +#[inline] +fn parse_reason<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> { + loop { + let b = next!(bytes); + if b == b'\r' { + expect!(bytes.next() == b'\n' => Err(Error::Status)); + return Ok(Status::Complete(unsafe { + // all bytes up till `i` must have been HTAB / SP / VCHAR + str::from_utf8_unchecked(bytes.slice_skip(2)) + })); + } else if b == b'\n' { + return Ok(Status::Complete(unsafe { + // all bytes up till `i` must have been HTAB / SP / VCHAR + str::from_utf8_unchecked(bytes.slice_skip(1)) + })); + } else if !((b >= 0x20 && b <= 0x7E) || b == b'\t') { + return Err(Error::Status); + } + } +} + +#[inline] +fn parse_token<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> { + loop { + let b = next!(bytes); + if b == b' ' { + return Ok(Status::Complete(unsafe { + // all bytes up till `i` must have been `is_token`. + str::from_utf8_unchecked(bytes.slice_skip(1)) + })); + } else if !is_token(b) { + return Err(Error::Token); + } + } +} + +#[inline] +fn parse_uri<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> { + simd::match_uri_vectored(bytes); + + loop { + let b = next!(bytes); + if b == b' ' { + return Ok(Status::Complete(unsafe { + // all bytes up till `i` must have been `is_token`. + str::from_utf8_unchecked(bytes.slice_skip(1)) + })); + } else if !is_uri_token(b) { + return 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)); + Ok(Status::Complete((pos, dst))) +} + + +#[inline] +fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut Bytes<'a>) + -> Result<usize> { + let mut num_headers: usize = 0; + let mut count: usize = 0; + let mut result = Err(Error::TooManyHeaders); + + { + let mut iter = headers.iter_mut(); + + 'headers: loop { + // a newline here means the head is over! + let b = next!(bytes); + if b == b'\r' { + expect!(bytes.next() == b'\n' => Err(Error::NewLine)); + result = Ok(Status::Complete(count + bytes.pos())); + break; + } else if b == b'\n' { + result = Ok(Status::Complete(count + bytes.pos())); + break; + } else if !is_header_name_token(b) { + return Err(Error::HeaderName); + } + + let header = match iter.next() { + Some(header) => header, + None => break 'headers + }; + + num_headers += 1; + // parse header name until colon + 'name: loop { + let b = next!(bytes); + if b == b':' { + count += bytes.pos(); + header.name = unsafe { + str::from_utf8_unchecked(bytes.slice_skip(1)) + }; + break 'name; + } else if !is_header_name_token(b) { + return Err(Error::HeaderName); + } + } + + let mut b; + + 'value: loop { + + // eat white space between colon and value + 'whitespace: loop { + b = next!(bytes); + if b == b' ' || b == b'\t' { + count += bytes.pos(); + bytes.slice(); + continue 'whitespace; + } else { + if !is_header_value_token(b) { + break 'value; + } + break 'whitespace; + } + } + + // parse value till EOL + + simd::match_header_value_vectored(bytes); + + macro_rules! check { + ($bytes:ident, $i:ident) => ({ + b = $bytes.$i(); + if !is_header_value_token(b) { + break 'value; + } + }); + ($bytes:ident) => ({ + check!($bytes, _0); + check!($bytes, _1); + check!($bytes, _2); + check!($bytes, _3); + check!($bytes, _4); + check!($bytes, _5); + check!($bytes, _6); + check!($bytes, _7); + }) + } + while let Some(mut bytes8) = bytes.next_8() { + check!(bytes8); + } + loop { + b = next!(bytes); + if !is_header_value_token(b) { + break 'value; + } + } + } + + //found_ctl + let value_slice : &[u8] = if b == b'\r' { + expect!(bytes.next() == b'\n' => Err(Error::HeaderValue)); + count += bytes.pos(); + // having just check that `\r\n` exists, it's safe to skip those 2 bytes + unsafe { + bytes.slice_skip(2) + } + } else if b == b'\n' { + count += bytes.pos(); + // having just check that `\r\n` exists, it's safe to skip 1 byte + unsafe { + bytes.slice_skip(1) + } + } else { + return Err(Error::HeaderValue); + }; + // trim trailing whitespace in the header + if let Some(last_visible) = value_slice.iter().rposition(|b| *b != b' ' && *b != b'\t' ) { + // There is at least one non-whitespace character. + header.value = &value_slice[0..last_visible+1]; + } else { + // There is no non-whitespace character. This can only happen when value_slice is + // empty. + header.value = value_slice; + } + } + } // drop iter + + shrink(headers, num_headers); + 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; + size *= RADIX; + size += (b - b'0') as u64; + }, + b'a' ... b'f' if in_chunk_size => { + if count > 15 { + return Err(InvalidChunkSize); + } + count += 1; + 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; + 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::{Request, Response, Status, EMPTY_HEADER, shrink, parse_chunk_size}; + + const NUM_OF_HEADERS: usize = 4; + + #[test] + fn test_shrink() { + let mut arr = [EMPTY_HEADER; 16]; + { + let slice = &mut &mut arr[..]; + assert_eq!(slice.len(), 16); + shrink(slice, 4); + assert_eq!(slice.len(), 4); + } + assert_eq!(arr.len(), 16); + } + + 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_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[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"); + } + } + + + 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_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_with_invalid_token_delimiter, + b"GET\n/ HTTP/1.1\r\nHost: foo.bar\r\n\r\n", + Err(::Error::Token), + |_r| {} + } + + + req! { + test_request_with_invalid_but_short_version, + b"GET / HTTP/1!", + Err(::Error::Version), + |_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: &'static [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, + Err(::Error::Status), + |_res| {} + } + + res! { + test_response_reason_with_nul_byte, + b"HTTP/1.1 200 \x00\r\n\r\n", + Err(::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_empty_lines_prefix_lf_only, + b"\n\nHTTP/1.1 200 OK\n\n", + |_res| {} + } + + #[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(::InvalidChunkSize)); + assert_eq!(parse_chunk_size(b"567f8a\rfoo"), Err(::InvalidChunkSize)); + assert_eq!(parse_chunk_size(b"567xf8a\r\n"), Err(::InvalidChunkSize)); + assert_eq!(parse_chunk_size(b"ffffffffffffffff\r\n"), Ok(Status::Complete((18, ::core::u64::MAX)))); + assert_eq!(parse_chunk_size(b"1ffffffffffffffff\r\n"), Err(::InvalidChunkSize)); + assert_eq!(parse_chunk_size(b"Affffffffffffffff\r\n"), Err(::InvalidChunkSize)); + assert_eq!(parse_chunk_size(b"fffffffffffffffff\r\n"), Err(::InvalidChunkSize)); + } + + #[cfg(feature = "std")] + #[test] + fn test_std_error() { + use super::Error; + use std::error::Error as StdError; + let err = Error::HeaderName; + assert_eq!(err.to_string(), err.description()); + } +} diff --git a/third_party/rust/httparse/src/macros.rs b/third_party/rust/httparse/src/macros.rs new file mode 100644 index 0000000000..c6f4ab63f3 --- /dev/null +++ b/third_party/rust/httparse/src/macros.rs @@ -0,0 +1,59 @@ +///! 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 try!($e) { + Status::Complete(v) => v, + Status::Partial => return Ok(Status::Partial) + } + } +} + +macro_rules! byte_map { + ($($flag:expr,)*) => ([ + $($flag != 0,)* + ]) +} + +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/third_party/rust/httparse/src/simd/avx2.rs b/third_party/rust/httparse/src/simd/avx2.rs new file mode 100644 index 0000000000..368c52c2d8 --- /dev/null +++ b/third_party/rust/httparse/src/simd/avx2.rs @@ -0,0 +1,116 @@ +use ::iter::Bytes; + +pub enum Scan { + /// Returned when an implementation finds a noteworthy token. + Found, + /// Returned when an implementation couldn't keep running because the input was too short. + TooShort, +} + + +pub unsafe fn parse_uri_batch_32<'a>(bytes: &mut Bytes<'a>) -> Scan { + while bytes.as_ref().len() >= 32 { + let advance = match_url_char_32_avx(bytes.as_ref()); + bytes.advance(advance); + + if advance != 32 { + return Scan::Found; + } + } + Scan::TooShort +} + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx2")] +#[inline] +#[allow(non_snake_case, overflowing_literals)] +unsafe fn match_url_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(); + + let LSH: __m256i = _mm256_set1_epi8(0x0f); + let URI: __m256i = _mm256_setr_epi8( + 0xb8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0x7c, 0x54, 0x7c, 0xd4, 0x7c, + 0xb8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0x7c, 0x54, 0x7c, 0xd4, 0x7c, + ); + let ARF: __m256i = _mm256_setr_epi8( + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ); + + let data = _mm256_lddqu_si256(ptr as *const _); + let rbms = _mm256_shuffle_epi8(URI, data); + let cols = _mm256_and_si256(LSH, _mm256_srli_epi16(data, 4)); + let bits = _mm256_and_si256(_mm256_shuffle_epi8(ARF, cols), rbms); + + let v = _mm256_cmpeq_epi8(bits, _mm256_setzero_si256()); + let r = 0xffffffff_00000000 | _mm256_movemask_epi8(v) as u64; + + _tzcnt_u64(r) as usize +} + +#[cfg(target_arch = "x86")] +unsafe fn match_url_char_32_avx(_: &[u8]) -> usize { + unreachable!("AVX2 detection should be disabled for x86"); +} + +pub unsafe fn match_header_value_batch_32(bytes: &mut Bytes) -> Scan { + while bytes.as_ref().len() >= 32 { + let advance = match_header_value_char_32_avx(bytes.as_ref()); + bytes.advance(advance); + + if advance != 32 { + return Scan::Found; + } + } + Scan::TooShort +} + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx2")] +#[inline] +#[allow(non_snake_case)] +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 + let TAB: __m256i = _mm256_set1_epi8(0x09); + let DEL: __m256i = _mm256_set1_epi8(0x7f); + let LOW: __m256i = _mm256_set1_epi8(0x1f); + + let dat = _mm256_lddqu_si256(ptr as *const _); + let low = _mm256_cmpgt_epi8(dat, LOW); + let tab = _mm256_cmpeq_epi8(dat, TAB); + let del = _mm256_cmpeq_epi8(dat, DEL); + let bit = _mm256_andnot_si256(del, _mm256_or_si256(low, tab)); + let rev = _mm256_cmpeq_epi8(bit, _mm256_setzero_si256()); + let res = 0xffffffff_00000000 | _mm256_movemask_epi8(rev) as u64; + + _tzcnt_u64(res) as usize +} + +#[cfg(target_arch = "x86")] +unsafe fn match_header_value_char_32_avx(_: &[u8]) -> usize { + unreachable!("AVX2 detection should be disabled for x86"); +} diff --git a/third_party/rust/httparse/src/simd/fallback.rs b/third_party/rust/httparse/src/simd/fallback.rs new file mode 100644 index 0000000000..4a79cb9978 --- /dev/null +++ b/third_party/rust/httparse/src/simd/fallback.rs @@ -0,0 +1,8 @@ +use ::iter::Bytes; + +// Fallbacks that do nothing... + +#[inline(always)] +pub fn match_uri_vectored(_: &mut Bytes) {} +#[inline(always)] +pub fn match_header_value_vectored(_: &mut Bytes) {} diff --git a/third_party/rust/httparse/src/simd/mod.rs b/third_party/rust/httparse/src/simd/mod.rs new file mode 100644 index 0000000000..e78034996a --- /dev/null +++ b/third_party/rust/httparse/src/simd/mod.rs @@ -0,0 +1,238 @@ +#[cfg(not(all( + httparse_simd, + any( + target_arch = "x86", + target_arch = "x86_64", + ), +)))] +mod fallback; + +#[cfg(not(all( + httparse_simd, + any( + target_arch = "x86", + target_arch = "x86_64", + ), +)))] +pub use self::fallback::*; + +#[cfg(all( + httparse_simd, + 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 { + //! Runtime detection of simd features. Used when the build script + //! doesn't notice any target features at build time. + //! + //! While `is_x86_feature_detected!` has it's own caching built-in, + //! at least in 1.27.0, the functions don't inline, leaving using it + //! actually *slower* than just using the scalar fallback. + + use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + + static FEATURE: AtomicUsize = ATOMIC_USIZE_INIT; + + const INIT: usize = 0; + const SSE_42: usize = 1; + const AVX_2: usize = 2; + const AVX_2_AND_SSE_42: usize = 3; + const NONE: usize = ::core::usize::MAX; + + fn detect() -> usize { + let feat = FEATURE.load(Ordering::Relaxed); + if feat == INIT { + if cfg!(target_arch = "x86_64") && is_x86_feature_detected!("avx2") { + if is_x86_feature_detected!("sse4.2") { + FEATURE.store(AVX_2_AND_SSE_42, Ordering::Relaxed); + return AVX_2_AND_SSE_42; + } else { + FEATURE.store(AVX_2, Ordering::Relaxed); + return AVX_2; + } + } else if is_x86_feature_detected!("sse4.2") { + FEATURE.store(SSE_42, Ordering::Relaxed); + return SSE_42; + } else { + FEATURE.store(NONE, Ordering::Relaxed); + } + } + feat + } + + pub fn match_uri_vectored(bytes: &mut ::Bytes) { + unsafe { + match detect() { + SSE_42 => super::sse42::parse_uri_batch_16(bytes), + AVX_2 => { super::avx2::parse_uri_batch_32(bytes); }, + AVX_2_AND_SSE_42 => { + if let super::avx2::Scan::Found = super::avx2::parse_uri_batch_32(bytes) { + return; + } + super::sse42::parse_uri_batch_16(bytes) + }, + _ => () + } + } + + // else do nothing + } + + pub fn match_header_value_vectored(bytes: &mut ::Bytes) { + unsafe { + match detect() { + SSE_42 => super::sse42::match_header_value_batch_16(bytes), + AVX_2 => { super::avx2::match_header_value_batch_32(bytes); }, + AVX_2_AND_SSE_42 => { + if let super::avx2::Scan::Found = super::avx2::match_header_value_batch_32(bytes) { + return; + } + super::sse42::match_header_value_batch_16(bytes) + }, + _ => () + } + } + + // else do nothing + } +} + +#[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 { + pub fn match_uri_vectored(bytes: &mut ::Bytes) { + if is_x86_feature_detected!("sse4.2") { + unsafe { + super::sse42::parse_uri_batch_16(bytes); + } + } + + // else do nothing + } + + pub fn match_header_value_vectored(bytes: &mut ::Bytes) { + if is_x86_feature_detected!("sse4.2") { + unsafe { + super::sse42::match_header_value_batch_16(bytes); + } + } + + // else do nothing + } +} + +#[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 { + pub fn match_uri_vectored(bytes: &mut ::Bytes) { + // do both, since avx2 only works when bytes.len() >= 32 + if cfg!(target_arch = "x86_64") && is_x86_feature_detected!("avx2") { + unsafe { + super::avx2::parse_uri_batch_32(bytes); + } + + } + if is_x86_feature_detected!("sse4.2") { + unsafe { + super::sse42::parse_uri_batch_16(bytes); + } + } + + // else do nothing + } + + pub fn match_header_value_vectored(bytes: &mut ::Bytes) { + // do both, since avx2 only works when bytes.len() >= 32 + if cfg!(target_arch = "x86_64") && is_x86_feature_detected!("avx2") { + let scanned = unsafe { + super::avx2::match_header_value_batch_32(bytes) + }; + + if let super::avx2::Scan::Found = scanned { + return; + } + } + if is_x86_feature_detected!("sse4.2") { + unsafe { + super::sse42::match_header_value_batch_16(bytes); + } + } + + // else do nothing + } +} + +#[cfg(all( + httparse_simd, + httparse_simd_target_feature_avx2, + any( + target_arch = "x86", + target_arch = "x86_64", + ), +))] +pub use self::avx2_compile_time::*; diff --git a/third_party/rust/httparse/src/simd/sse42.rs b/third_party/rust/httparse/src/simd/sse42.rs new file mode 100644 index 0000000000..1770ba9aeb --- /dev/null +++ b/third_party/rust/httparse/src/simd/sse42.rs @@ -0,0 +1,84 @@ +use ::iter::Bytes; + +pub unsafe fn parse_uri_batch_16<'a>(bytes: &mut Bytes<'a>) { + while bytes.as_ref().len() >= 16 { + let advance = match_url_char_16_sse(bytes.as_ref()); + bytes.advance(advance); + + if advance != 16 { + break; + } + } +} + +#[target_feature(enable = "sse4.2")] +#[allow(non_snake_case, overflowing_literals)] +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(); + + let LSH: __m128i = _mm_set1_epi8(0x0f); + let URI: __m128i = _mm_setr_epi8( + 0xb8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0x7c, 0x54, 0x7c, 0xd4, 0x7c, + ); + let ARF: __m128i = _mm_setr_epi8( + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ); + + let data = _mm_lddqu_si128(ptr as *const _); + let rbms = _mm_shuffle_epi8(URI, data); + let cols = _mm_and_si128(LSH, _mm_srli_epi16(data, 4)); + let bits = _mm_and_si128(_mm_shuffle_epi8(ARF, cols), rbms); + + let v = _mm_cmpeq_epi8(bits, _mm_setzero_si128()); + let r = 0xffff_0000 | _mm_movemask_epi8(v) as u32; + + _tzcnt_u32(r) as usize +} + +pub unsafe fn match_header_value_batch_16(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 { + break; + } + } +} + +#[target_feature(enable = "sse4.2")] +#[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(0x1f); + + let dat = _mm_lddqu_si128(ptr as *const _); + let low = _mm_cmpgt_epi8(dat, LOW); + 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 rev = _mm_cmpeq_epi8(bit, _mm_setzero_si128()); + let res = 0xffff_0000 | _mm_movemask_epi8(rev) as u32; + + _tzcnt_u32(res) as usize +} diff --git a/third_party/rust/httparse/tests/uri.rs b/third_party/rust/httparse/tests/uri.rs new file mode 100644 index 0000000000..78ca72ac8d --- /dev/null +++ b/third_party/rust/httparse/tests/uri.rs @@ -0,0 +1,3677 @@ +extern crate httparse; + +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::Version), + |_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\nHost: \r\n\r\n", + Err(Error::Token), + |_r| {} +} + + +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"); + } +} + + |