httparse-1.3.3/.gitignore010060000017500001750000000000221247116652500135540ustar0000000000000000target Cargo.lock httparse-1.3.3/.travis.yml010066400017500001750000000037451335322402300137120ustar0000000000000000language: rust sudo: false dist: trusty rust: - nightly - beta - stable env: - - CARGO_CFG_HTTPARSE_DISABLE_SIMD=1 - CARGO_CFG_HTTPARSE_DISABLE_SIMD_COMPILETIME=1 RUSTFLAGS="-C target_feature=+sse4.2" - RUSTFLAGS="-C target_feature=+sse4.2" matrix: fast_finish: true include: - rust: 1.10.0 # minimum Rust version script: # don't run tests, since dev-dependencies don't build on 1.10 - cargo build --no-default-features - cargo build # with sudo the worker has avx2 support - rust: nightly sudo: true env: RUSTFLAGS="-C target_feature=+avx2" - rust: nightly sudo: true env: RUSTFLAGS="-C target_feature=sse4.2" - rust: nightly sudo: true env: RUSTFLAGS="-C target_feature=+sse4.2,+avx2" - rust: nightly sudo: true env: CARGO_CFG_HTTPARSE_DISABLE_SIMD_COMPILETIME=1 RUSTFLAGS="-C target_feature=+sse4.2,+avx2" - rust: beta sudo: true env: RUSTFLAGS="-C target_feature=+avx2" - rust: beta sudo: true env: RUSTFLAGS="-C target_feature=+sse4.2" - rust: beta sudo: true env: RUSTFLAGS="-C target_feature=+sse4.2,+avx2" - rust: beta sudo: true env: CARGO_CFG_HTTPARSE_DISABLE_SIMD_COMPILETIME=1 RUSTFLAGS="-C target_feature=+sse4.2,+avx2" - rust: stable sudo: true env: RUSTFLAGS="-C target_feature=+avx2" - rust: stable sudo: true env: RUSTFLAGS="-C target_feature=+sse4.2" - rust: stable sudo: true env: RUSTFLAGS="-C target_feature=+sse4.2,+avx2" - rust: stable sudo: true env: CARGO_CFG_HTTPARSE_DISABLE_SIMD_COMPILETIME=1 RUSTFLAGS="-C target_feature=+sse4.2,+avx2" script: - cargo build --no-default-features - cargo test --no-default-features - cargo build - cargo test httparse-1.3.3/Cargo.toml.orig010066400017500001750000000011251335323133000144550ustar0000000000000000[package] name = "httparse" version = "1.3.3" authors = ["Sean McArthur "] license = "MIT/Apache-2.0" description = "A tiny, safe, speedy, zero-copy HTTP/1.x parser." repository = "https://github.com/seanmonstar/httparse" documentation = "https://docs.rs/httparse" readme = "README.md" keywords = ["http", "parser", "no_std"] categories = ["network-programming", "no-std", "parser-implementations", "web-programming"] build = "build.rs" [features] default = ["std"] std = [] [dev-dependencies] pico-sys = "0.0" [profile.bench] lto = true codegen-units = 1 opt-level = 3 httparse-1.3.3/Cargo.toml0000644000000021450000000000000107310ustar00# 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 "] 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 = [] httparse-1.3.3/LICENSE-APACHE010066400017500001750000000251371335322402300135240ustar0000000000000000 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. httparse-1.3.3/LICENSE-MIT010066400017500001750000000020421335322402300132220ustar0000000000000000Copyright (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. httparse-1.3.3/README.md010066400017500001750000000026701335323115700130620ustar0000000000000000# 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. httparse-1.3.3/benches/parse.rs010066400017500001750000000073021335322402300146610ustar0000000000000000#![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; } httparse-1.3.3/build.rs010066400017500001750000000106431335322402300132410ustar0000000000000000use 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 { 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::().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::().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::().map_err(|e| e.to_string())); Ok(Version { major: major, minor: minor, patch: patch, }) } } httparse-1.3.3/src/iter.rs010066400017500001750000000065251335322402300137000ustar0000000000000000use 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 { 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> { 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 { 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; } } httparse-1.3.3/src/lib.rs010066400017500001750000001122721335323057200135060ustar0000000000000000#![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(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 = result::Result, 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 { /// The completed result. Complete(T), /// A partial result. Partial } impl Status { /// 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, /// 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 { 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, /// The response code, such as `200`. pub code: Option, /// 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 { 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 { 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 { 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 { 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, 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()); } } httparse-1.3.3/src/macros.rs010066400017500001750000000023121335322402300142070ustar0000000000000000///! 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) } }) } httparse-1.3.3/src/simd/avx2.rs010066400017500001750000000066141335322402300145500ustar0000000000000000use ::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"); } httparse-1.3.3/src/simd/fallback.rs010066400017500001750000000002721335322402300154210ustar0000000000000000use ::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) {} httparse-1.3.3/src/simd/mod.rs010066400017500001750000000140011335322402300144340ustar0000000000000000#[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::*; httparse-1.3.3/src/simd/sse42.rs010066400017500001750000000046331335322402300146270ustar0000000000000000use ::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 } httparse-1.3.3/tests/uri.rs010066400017500001750000003070261335322562400141170ustar0000000000000000extern 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"); } } httparse-1.3.3/.cargo_vcs_info.json0000644000000001120000000000000127230ustar00{ "git": { "sha1": "dfe8a56dd343189e7cdce01d7ef835e3920cbdc2" } }