summaryrefslogtreecommitdiffstats
path: root/third_party/rust/httparse
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/httparse
parentInitial commit. (diff)
downloadfirefox-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.json1
-rw-r--r--third_party/rust/httparse/Cargo.toml34
-rw-r--r--third_party/rust/httparse/LICENSE-APACHE201
-rw-r--r--third_party/rust/httparse/LICENSE-MIT20
-rw-r--r--third_party/rust/httparse/README.md38
-rw-r--r--third_party/rust/httparse/benches/parse.rs122
-rw-r--r--third_party/rust/httparse/build.rs155
-rw-r--r--third_party/rust/httparse/src/iter.rs156
-rw-r--r--third_party/rust/httparse/src/lib.rs1138
-rw-r--r--third_party/rust/httparse/src/macros.rs59
-rw-r--r--third_party/rust/httparse/src/simd/avx2.rs116
-rw-r--r--third_party/rust/httparse/src/simd/fallback.rs8
-rw-r--r--third_party/rust/httparse/src/simd/mod.rs238
-rw-r--r--third_party/rust/httparse/src/simd/sse42.rs84
-rw-r--r--third_party/rust/httparse/tests/uri.rs3677
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");
+ }
+}
+
+