RPM build fix (reverted CI changes which will need to be un-reverted or made conditional) and vendor Rust dependencies to make builds much faster in any CI system.

This commit is contained in:
Adam Ierymenko
2022-06-08 07:32:16 -04:00
parent 373ca30269
commit d5ca4e5f52
12611 changed files with 2898014 additions and 284 deletions

View File

@@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"9da8137ba524bbfc6ad9caed8b2f1919b7ff3477b9fdffa65f6d6da499e13528","Cargo.toml":"9b964a1a24b7f8e43b0f183b12577299db8be2621026dfc1926a8ff2b8ea020d","LICENSE-APACHE":"8bb1b50b0e5c9399ae33bd35fab2769010fa6c14e8860c729a52295d84896b7a","LICENSE-MIT":"dc91f8200e4b2a1f9261035d4c18c33c246911a6c0f7b543d75347e61b249cff","README.md":"2b08369b8ce261843a84103642fd4d8b1ab556af6d6397dbc78c19f7025d255a","benches/header_map/basic.rs":"7aa1f667be9b7fd2aab249a6ca6cfa2f06229c79d3406a8354d07bf9ccf09fd8","benches/header_map/mod.rs":"c1a4c7291b94d2477c1aa6721a5cfbd3dc63242baf14b836138273830cc67990","benches/header_map/vec_map.rs":"48f4eb7a90b6f0844a445924cf24c80acfaf76f909acca4492bfeb9b1ea9e4a4","benches/header_name.rs":"0c6ea9862807f7973b9e6577ef8959b3f41da04837cde326faa73d028caeb420","benches/header_name2.rs":"b19a4e9ca8ffe19e415bd2b498055c89da3ab773ea04b973747fc8517cfe7d2b","benches/header_value.rs":"7aa588f2155c513b7aebfe0b1cc7f7c6b0a699fafd817fe2fee8e46fb131bd76","benches/method.rs":"1913b8c95ecf542e9e50e20ff645f4024036e9b89f04a83e06303bf423053508","benches/uri.rs":"fbc88c25bc27d39162c674c162d1e40c8139452fbfb891a7caebb3c225baa1ae","src/byte_str.rs":"4767ad7bb6e5cda64a63e00ec549c1318e9305acb64d22d5cfbe54b8540b425b","src/convert.rs":"a31a4351cd3ee36a58ff4f5b30ce2c8967cde8486faea2d2673a8f8cb74b3204","src/error.rs":"8163a0b4f659a0f0070559568a7b553a5370553a4570bb496811ca3b978046bf","src/extensions.rs":"5f85c3e1eef53d0fcbd4a24a6c13828790dac74ad60f71cad365e14d39b196a6","src/header/map.rs":"353e7c213933945119d774a655dd822a3afc05b08c832707691910a647c1231c","src/header/mod.rs":"b91ee39f0f76aba6a2ca4e818126d0185272c150c29a43dfbec60891d213c45a","src/header/name.rs":"ce12e22ee9812ee3ffb07b45d8b02aa64ee6aa4c32dc434c76e1b4e02d81b8b8","src/header/value.rs":"ffea8236f38178fa3dd600b893d1eb8b698e3a052aaad2dbdda4a14e1b3c7108","src/lib.rs":"ebd9065bb9f2a3cef9c70a9c43619e2c767c00a33c145997fdbd1a731ba8bbfe","src/method.rs":"1de55021d29174c462ed60042d0d263276af131a25c4d942c91afb09622644f8","src/request.rs":"8c76af67f41c62774c298016ab562a1ab0e8f6d9ab5617e0294a10c0200e5f74","src/response.rs":"5a17fafd73e6d51f2fe43af26143aa2390384c09045d8b634b68515118665bdb","src/status.rs":"fd9d1c1670bde5f94934ff2a9fa9c7f2db5bbe32a750e4e202bf2775b5c5cac3","src/uri/authority.rs":"4df1371b3bd751dd8b5c4b88a4dc67eac3c691748992223e78d7eb859832ebe0","src/uri/builder.rs":"875506b3a603a6e35557548ed0cf3beb7de0a4d1c898316e7293f3bc2ffb05c5","src/uri/mod.rs":"a70ef96edd8b7920b404a88a5d7bf09b382bf24b93e5d28dfc82b83bd77e2ce7","src/uri/path.rs":"72a300e800a85dd9901a18dae3d3f0beacb783472d66a70615486194f43cd118","src/uri/port.rs":"a30793678abc96e833d026d96f060244183ab631e19eafbbad8e4643c7bb9d86","src/uri/scheme.rs":"59e6f12d3e1e1ee982e68a4a6556f25e94073ca3d77c372b6d8d71daf8f62f2a","src/uri/tests.rs":"61f88b73490c2442ec12cb0829aa1ddd28f1bce874b4fc6dd7a544c80280aeb1","src/version.rs":"623ef60a450203b051f3457e2f095508b66aaaa799b1447fb1b34d92cb2e7d62","tests/header_map.rs":"b81993a9042c21fd64114fb099b1666ea4685246f4f1c76bac72b825b6a3741b","tests/header_map_fuzz.rs":"a71387a8e1a3906f713a00cde443790cd7a86b7e37cafa2f9ed4d432cbf97026","tests/status_code.rs":"4c1bd08baffa6265aad5e837b189c269a3bef9031984b37980c24a8c671ac22c"},"package":"75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"}

199
zeroidc/vendor/http/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,199 @@
# 0.2.8 (June 6, 2022)
* Fix internal usage of uninitialized memory to use `MaybeUninit` inside `HeaderName`.
# 0.2.7 (April 28, 2022)
* MSRV bumped to `1.49`.
* Add `extend()` method to `Extensions`.
* Add `From<Authority>` and `From<PathAndQuery>` impls for `Uri`.
* Make `HeaderName::from_static` a `const fn`.
# 0.2.6 (December 30, 2021)
* Upgrade internal `itoa` dependency to 1.0.
# 0.2.5 (September 21, 2021)
* Add `is_empty()` and `len()` methods to `Extensions`.
* Add `version_ref()` method to `request::Builder`.
* Implement `TryFrom<Vec<u8>>` and `TryFrom<String>` for `Authority`, `Uri`, `PathAndQuery`, and `HeaderName`.
* Make `HeaderValue::from_static` a `const fn`.
# 0.2.4 (April 4, 2021)
* Fix `Uri` parsing to allow `{`, `"`, and `}` in paths.
# 0.2.3 (January 7, 2021)
* Upgrade internal (private) `bytes` dependency to 1.0.
# 0.2.2 (December 14, 2020)
* Fix (potential double) panic of (`HeaderMap`) `OccupiedEntry::remove_entry` and
`remove_entry_mult` when multiple values are present. ([#446], [#449] dekellum)
* Safety audits of (priv) `ByteStr` and refactor of `Authority` ([#408], [#414] sbosnick)
* Fix `HeaderName` to error instead of panic when input is too long ([#432] [#433] acfoltzer)
* Allow `StatusCode` to encode values 100-999 without error. Use of the
unclassified range 600-999 remains discouraged. ([#144], [#438], [#443] quininer dekellum)
* Add `String` and `&String` fallible conversions to `PathAndQuery` ([#450] mkindahl)
* Fix `Authority` (and `Uri`) to error instead of panic on unbalanced brackets
([#435], [#445] aeryz)
# 0.2.1 (March 25, 2020)
* Add `extensions_ref` and `extensions_mut` to `request::Builder` and `response::Builder`.
# 0.2.0 (December 2, 2019)
* Add `Version::HTTP_3` constant.
* Add `HeaderValue::from_maybe_shared`, `HeaderValue::from_maybe_shared_unchecked`, `Uri::from_maybe_shared`, `Authority::from_maybe_shared`, and `PathAndQuery::from_maybe_shared`.
* Change `request::Builder`, `response::Builder`, and `uri::Builder` to use by-value methods instead of by-ref.
* Change from `HttpTryFrom` trait to `std::convert::TryFrom`.
* Change `HeaderMap::entry` to no longer return a `Result`.
* Change `HeaderMap::drain` iterator to match the behavior of `IntoIter`.
* Change `Authority::port` to return an `Option<Port>` instead of `Option<u16>`.
* Change `Uri::scheme` to return `Option<&Scheme>` instead of `Option<&str>`.
* Change `Uri::authority` to return `Option<&Authority>` instead of `Option<&str>`.
* Remove `InvalidUriBytes`, `InvalidHeaderNameBytes`, and `InvalidHeaderValueBytes` error types.
* Remove `HeaderValue::from_shared`, `HeaderValue::from_shared_unchecked`, `Uri::from_shared`, `Authority::from_shared`, `Scheme::from_shared`, and `PathAndQuery::from_shared`.
* Remove `Authority::port_part`.
* Remove `Uri::scheme_part` and `Uri::authority_part`.
# 0.1.20 (November 26, 2019)
* Fix possible double-free if `header::Drain` iterator is `std::mem::forgot`en (#357).
* Fix possible data race if multiple `header::ValueDrain`s are iterated on different threads (#362).
* Fix `HeaderMap::reserve` capacity overflows (#360).
* Fix parsing long authority-form `Uri`s (#351).
# 0.1.19 (October 15, 2019)
* Allow `%` in IPv6 addresses in `Uri` (#343).
# 0.1.18 (July 26, 2019)
* Fix compilation of `HeaderName` parsing on WASM targets (#324).
* Implement `HttpTryFrom<HashMap>` for `HeaderMap` (#326).
* Export `http::header::HeaderValue` as `http::HeaderValue`.
# 0.1.17 (April 5, 2019)
* Add `Error::inner_ref()` to view the kind of error (#303)
* Add `headers_ref()` and `headers_mut()` methods to `request::Builder` and `response::Builder` (#293)
# 0.1.16 (February 19, 2019)
* Fix `Uri` to permit more characters in the `path` (#296)
# 0.1.15 (January 22, 2019)
* Fix `Uri::host()` to include brackets of IPv6 literals (#292)
* Add `scheme_str` and `port_u16` methods to `Uri` (#287)
* Add `method_ref`, `uri_ref`, and `headers_ref` to `request::Builder` (#284)
# 0.1.14 (November 21, 2018)
* Add `Port` struct (#252, #255, #265)
* Introduce `Uri` builder (#219)
* Empty `Method` no longer considered valid (#262)
* Fix `Uri` equality when terminating question mark is present (#270)
* Allow % character in userinfo (#269)
* Support additional tokens for header names (#271)
* Export `http::headers::{IterMut, ValuesMut}` (#278)
# 0.1.13 (September 14, 2018)
* impl `fmt::Display` for `HeaderName` (#249)
* Fix `uri::Authority` parsing when there is no host after an `@` (#248)
* Fix `Uri` parsing to allow more characters in query strings (#247)
# 0.1.12 (September 7, 2018)
* Fix `HeaderValue` parsing to allow HTABs (#244)
# 0.1.11 (September 5, 2018)
* Add `From<&Self>` for `HeaderValue`, `Method`, and `StatusCode` (#238)
* Add `Uri::from_static` (#240)
# 0.1.10 (August 8, 2018)
* `impl HttpTryFrom<String>` for HeaderValue (#236)
# 0.1.9 (August 7, 2018)
* Fix double percent encoding (#233)
* Add additional HttpTryFrom impls (#234)
# 0.1.8 (July 23, 2018)
* Add fuller set of `PartialEq` for `Method` (#221)
* Reduce size of `HeaderMap` by using `Box<[Entry]>` instea of `Vec` (#224)
* Reduce size of `Extensions` by storing as `Option<Box<AnyMap>>` (#227)
* Implement `Iterator::size_hint` for most iterators in `header` (#226)
# 0.1.7 (June 22, 2018)
* Add `From<uN> for HeaderValue` for most integer types (#218).
* Add `Uri::into_parts()` inherent method (same as `Parts::from(uri)`) (#214).
* Fix converting `Uri`s in authority-form to `Parts` and then back into `Uri` (#216).
* Fix `Authority` parsing to reject multiple port sections (#215).
* Fix parsing 1 character authority-form `Uri`s into illegal forms (#220).
# 0.1.6 (June 13, 2018)
* Add `HeaderName::from_static()` constructor (#195).
* Add `Authority::from_static()` constructor (#186).
* Implement `From<HeaderName>` for `HeaderValue` (#184).
* Fix duplicate keys when iterating over `header::Keys` (#201).
# 0.1.5 (February 28, 2018)
* Add websocket handshake related header constants (#162).
* Parsing `Authority` with an empty string now returns an error (#164).
* Implement `PartialEq<u16>` for `StatusCode` (#153).
* Implement `HttpTryFrom<&Uri>` for `Uri` (#165).
* Implement `FromStr` for `Method` (#167).
* Implement `HttpTryFrom<String>` for `Uri` (#171).
* Add `into_body` fns to `Request` and `Response` (#172).
* Fix `Request::options` (#177).
# 0.1.4 (January 4, 2018)
* Add PathAndQuery::from_static (#148).
* Impl PartialOrd / PartialEq for Authority and PathAndQuery (#150).
* Add `map` fn to `Request` and `Response` (#151).
# 0.1.3 (December 11, 2017)
* Add `Scheme` associated consts for common protos.
# 0.1.2 (November 29, 2017)
* Add Uri accessor for scheme part.
* Fix Uri parsing bug (#134)
# 0.1.1 (October 9, 2017)
* Provide Uri accessors for parts (#129)
* Add Request builder helpers. (#123)
* Misc performance improvements (#126)
# 0.1.0 (September 8, 2017)
* Initial release.
[#144]: https://github.com/hyperium/http/issues/144
[#408]: https://github.com/hyperium/http/pull/408
[#414]: https://github.com/hyperium/http/pull/414
[#432]: https://github.com/hyperium/http/issues/432
[#433]: https://github.com/hyperium/http/pull/433
[#438]: https://github.com/hyperium/http/pull/438
[#443]: https://github.com/hyperium/http/pull/443
[#446]: https://github.com/hyperium/http/issues/446
[#449]: https://github.com/hyperium/http/pull/449
[#450]: https://github.com/hyperium/http/pull/450
[#435]: https://github.com/hyperium/http/issues/435
[#445]: https://github.com/hyperium/http/pull/445

88
zeroidc/vendor/http/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,88 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
rust-version = "1.49.0"
name = "http"
version = "0.2.8"
authors = [
"Alex Crichton <alex@alexcrichton.com>",
"Carl Lerche <me@carllerche.com>",
"Sean McArthur <sean@seanmonstar.com>",
]
description = """
A set of types for representing HTTP requests and responses.
"""
documentation = "https://docs.rs/http"
readme = "README.md"
keywords = ["http"]
categories = ["web-programming"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/hyperium/http"
[[bench]]
name = "header_map"
path = "benches/header_map/mod.rs"
[[bench]]
name = "header_name"
path = "benches/header_name.rs"
[[bench]]
name = "header_name2"
path = "benches/header_name2.rs"
harness = false
[[bench]]
name = "header_value"
path = "benches/header_value.rs"
[[bench]]
name = "method"
path = "benches/method.rs"
[[bench]]
name = "uri"
path = "benches/uri.rs"
[dependencies.bytes]
version = "1"
[dependencies.fnv]
version = "1.0.5"
[dependencies.itoa]
version = "1"
[dev-dependencies.criterion]
version = "0.3.2"
[dev-dependencies.doc-comment]
version = "0.3"
[dev-dependencies.indexmap]
version = "1.0"
[dev-dependencies.quickcheck]
version = "0.9.0"
[dev-dependencies.rand]
version = "0.7.0"
[dev-dependencies.seahash]
version = "3.0.5"
[dev-dependencies.serde]
version = "1.0"
[dev-dependencies.serde_json]
version = "1.0"

201
zeroidc/vendor/http/LICENSE-APACHE vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2017 http-rs authors
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.

25
zeroidc/vendor/http/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,25 @@
Copyright (c) 2017 http-rs authors
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.

80
zeroidc/vendor/http/README.md vendored Normal file
View File

@@ -0,0 +1,80 @@
# HTTP
A general purpose library of common HTTP types
[![CI](https://github.com/hyperium/http/workflows/CI/badge.svg)](https://github.com/hyperium/http/actions?query=workflow%3ACI)
[![Crates.io](https://img.shields.io/crates/v/http.svg)](https://crates.io/crates/http)
[![Documentation](https://docs.rs/http/badge.svg)][dox]
More information about this crate can be found in the [crate
documentation][dox].
[dox]: https://docs.rs/http
## Usage
To use `http`, first add this to your `Cargo.toml`:
```toml
[dependencies]
http = "0.2"
```
Next, add this to your crate:
```rust
use http::{Request, Response};
fn main() {
// ...
}
```
## Examples
Create an HTTP request:
```rust
use http::Request;
fn main() {
let request = Request::builder()
.uri("https://www.rust-lang.org/")
.header("User-Agent", "awesome/1.0")
.body(())
.unwrap();
}
```
Create an HTTP response:
```rust
use http::{Response, StatusCode};
fn main() {
let response = Response::builder()
.status(StatusCode::MOVED_PERMANENTLY)
.header("Location", "https://www.rust-lang.org/install.html")
.body(())
.unwrap();
}
```
# Supported Rust Versions
This project follows the [Tokio MSRV][msrv] and is currently set to `1.49`.
[msrv]: https://github.com/tokio-rs/tokio/#supported-rust-versions
# License
Licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or https://apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
# Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

View File

@@ -0,0 +1,595 @@
macro_rules! bench {
($name:ident($map:ident, $b:ident) $body:expr) => {
mod $name {
#[allow(unused_imports)]
use super::custom_hdr;
use fnv::FnvHasher;
use http::header::*;
use seahash::SeaHasher;
use std::hash::BuildHasherDefault;
#[allow(unused_imports)]
use test::{self, Bencher};
#[bench]
fn header_map($b: &mut Bencher) {
let $map = || HeaderMap::default();
$body
}
#[bench]
fn order_map_fnv($b: &mut Bencher) {
use indexmap::IndexMap;
let $map = || IndexMap::<_, _, BuildHasherDefault<FnvHasher>>::default();
$body
}
#[bench]
fn vec_map($b: &mut Bencher) {
use crate::vec_map::VecMap;
let $map = || VecMap::with_capacity(0);
$body
}
#[bench]
fn order_map_seahash($b: &mut Bencher) {
use indexmap::IndexMap;
let $map = || IndexMap::<_, _, BuildHasherDefault<SeaHasher>>::default();
$body
}
/*
#[bench]
fn order_map_siphash($b: &mut Bencher) {
use indexmap::IndexMap;
let $map = || IndexMap::new();
$body
}
#[bench]
fn std_map_siphash($b: &mut Bencher) {
use std::collections::HashMap;
let $map = || HashMap::new();
$body
}
*/
}
};
}
bench!(new_insert_get_host(new_map, b) {
b.iter(|| {
let mut h = new_map();
h.insert(HOST, "hyper.rs");
test::black_box(h.get(&HOST));
})
});
bench!(insert_4_std_get_30(new_map, b) {
b.iter(|| {
let mut h = new_map();
for i in 0..4 {
h.insert(super::STD[i].clone(), "foo");
}
for i in 0..30 {
test::black_box(h.get(&super::STD[i % 4]));
}
})
});
bench!(insert_6_std_get_6(new_map, b) {
b.iter(|| {
let mut h = new_map();
for i in 0..6 {
h.insert(super::STD[i].clone(), "foo");
}
for i in 0..6 {
test::black_box(h.get(&super::STD[i % 4]));
}
})
});
/*
bench!(insert_remove_host(new_map, b) {
let mut h = new_map();
b.iter(|| {
test::black_box(h.insert(HOST, "hyper.rs"));
test::black_box(h.remove(&HOST));
})
});
bench!(insert_insert_host(new_map, b) {
let mut h = new_map();
b.iter(|| {
test::black_box(h.insert(HOST, "hyper.rs"));
test::black_box(h.insert(HOST, "hyper.rs"));
})
});
*/
bench!(get_10_of_20_std(new_map, b) {
let mut h = new_map();
for hdr in super::STD[10..30].iter() {
h.insert(hdr.clone(), hdr.as_str().to_string());
}
b.iter(|| {
for hdr in &super::STD[10..20] {
test::black_box(h.get(hdr));
}
})
});
bench!(get_100_std(new_map, b) {
let mut h = new_map();
for hdr in super::STD.iter() {
h.insert(hdr.clone(), hdr.as_str().to_string());
}
b.iter(|| {
for i in 0..100 {
test::black_box(h.get(&super::STD[i % super::STD.len()]));
}
})
});
bench!(set_8_get_1_std(new_map, b) {
b.iter(|| {
let mut h = new_map();
for hdr in &super::STD[0..8] {
h.insert(hdr.clone(), "foo");
}
test::black_box(h.get(&super::STD[0]));
})
});
bench!(set_10_get_1_std(new_map, b) {
b.iter(|| {
let mut h = new_map();
for hdr in &super::STD[0..10] {
h.insert(hdr.clone(), "foo");
}
test::black_box(h.get(&super::STD[0]));
})
});
bench!(set_20_get_1_std(new_map, b) {
b.iter(|| {
let mut h = new_map();
for hdr in &super::STD[0..20] {
h.insert(hdr.clone(), "foo");
}
test::black_box(h.get(&super::STD[0]));
})
});
bench!(get_10_custom_short(new_map, b) {
let hdrs = custom_hdr(20);
let mut h = new_map();
for hdr in &hdrs {
h.insert(hdr.clone(), hdr.as_str().to_string());
}
b.iter(|| {
for hdr in &hdrs[..10] {
test::black_box(h.get(hdr));
}
})
});
bench!(set_10_get_1_custom_short(new_map, b) {
let hdrs = custom_hdr(10);
b.iter(|| {
let mut h = new_map();
for hdr in &hdrs {
h.insert(hdr.clone(), "foo");
}
test::black_box(h.get(&hdrs[0]));
})
});
bench!(set_10_get_1_custom_med(new_map, b) {
let hdrs = super::med_custom_hdr(10);
b.iter(|| {
let mut h = new_map();
for hdr in &hdrs {
h.insert(hdr.clone(), "foo");
}
test::black_box(h.get(&hdrs[0]));
})
});
bench!(set_10_get_1_custom_long(new_map, b) {
let hdrs = super::long_custom_hdr(10);
b.iter(|| {
let mut h = new_map();
for hdr in &hdrs {
h.insert(hdr.clone(), "foo");
}
test::black_box(h.get(&hdrs[0]));
})
});
bench!(set_10_get_1_custom_very_long(new_map, b) {
let hdrs = super::very_long_custom_hdr(10);
b.iter(|| {
let mut h = new_map();
for hdr in &hdrs {
h.insert(hdr.clone(), "foo");
}
test::black_box(h.get(&hdrs[0]));
})
});
bench!(set_20_get_1_custom_short(new_map, b) {
let hdrs = custom_hdr(20);
b.iter(|| {
let mut h = new_map();
for hdr in &hdrs {
h.insert(hdr.clone(), "foo");
}
test::black_box(h.get(&hdrs[0]));
})
});
bench!(set_20_get_1_custom_med(new_map, b) {
let hdrs = super::med_custom_hdr(20);
b.iter(|| {
let mut h = new_map();
for hdr in &hdrs {
h.insert(hdr.clone(), "foo");
}
test::black_box(h.get(&hdrs[0]));
})
});
bench!(set_20_get_1_custom_long(new_map, b) {
let hdrs = super::long_custom_hdr(20);
b.iter(|| {
let mut h = new_map();
for hdr in &hdrs {
h.insert(hdr.clone(), "foo");
}
test::black_box(h.get(&hdrs[0]));
})
});
bench!(set_20_get_1_custom_very_long(new_map, b) {
let hdrs = super::very_long_custom_hdr(20);
b.iter(|| {
let mut h = new_map();
for hdr in &hdrs {
h.insert(hdr.clone(), "foo");
}
test::black_box(h.get(&hdrs[0]));
})
});
bench!(insert_all_std_headers(new_map, b) {
b.iter(|| {
let mut h = new_map();
for hdr in super::STD {
test::black_box(h.insert(hdr.clone(), "foo"));
}
})
});
bench!(insert_79_custom_std_headers(new_map, b) {
let hdrs = super::custom_std(79);
b.iter(|| {
let mut h = new_map();
for hdr in &hdrs {
h.insert(hdr.clone(), "foo");
}
})
});
bench!(insert_100_custom_headers(new_map, b) {
let hdrs = custom_hdr(100);
b.iter(|| {
let mut h = new_map();
for hdr in &hdrs {
test::black_box(h.insert(hdr.clone(), "foo"));
}
})
});
bench!(insert_500_custom_headers(new_map, b) {
let hdrs = custom_hdr(500);
b.iter(|| {
let mut h = new_map();
for hdr in &hdrs {
test::black_box(h.insert(hdr.clone(), "foo"));
}
})
});
bench!(insert_one_15_char_header(new_map, b) {
let hdr: HeaderName = "abcd-abcd-abcde"
.parse().unwrap();
b.iter(|| {
let mut h = new_map();
h.insert(hdr.clone(), "hello");
test::black_box(h);
})
});
bench!(insert_one_25_char_header(new_map, b) {
let hdr: HeaderName = "abcd-abcd-abcd-abcd-abcde"
.parse().unwrap();
b.iter(|| {
let mut h = new_map();
h.insert(hdr.clone(), "hello");
test::black_box(h);
})
});
bench!(insert_one_50_char_header(new_map, b) {
let hdr: HeaderName = "abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcde"
.parse().unwrap();
b.iter(|| {
let mut h = new_map();
h.insert(hdr.clone(), "hello");
test::black_box(h);
})
});
bench!(insert_one_100_char_header(new_map, b) {
let hdr: HeaderName = "abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcdeabcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcde"
.parse().unwrap();
b.iter(|| {
let mut h = new_map();
h.insert(hdr.clone(), "hello");
test::black_box(h);
})
});
const HN_HDRS: [(&'static str, &'static str); 11] = [
("Date", "Fri, 27 Jan 2017 23:00:00 GMT"),
("Content-Type", "text/html; charset=utf-8"),
("Transfer-Encoding", "chunked"),
("Connection", "keep-alive"),
("Set-Cookie", "__cfduid=dbdfbbe3822b61cb8750ba37d894022151485558000; expires=Sat, 27-Jan-18 23:00:00 GMT; path=/; domain=.ycombinator.com; HttpOnly"),
("Vary", "Accept-Encoding"),
("Cache-Control", "private"),
("X-Frame-Options", "DENY"),
("Strict-Transport-Security", "max-age=31556900; includeSubDomains"),
("Server", "cloudflare-nginx"),
("CF-RAY", "327fd1809f3c1baf-SEA"),
];
bench!(hn_hdrs_set_8_get_many(new_map, b) {
let hdrs: Vec<(HeaderName, &'static str)> = super::HN_HDRS[..8].iter()
.map(|&(name, val)| (name.parse().unwrap(), val))
.collect();
b.iter(|| {
let mut h = new_map();
for &(ref name, val) in hdrs.iter() {
h.insert(name.clone(), val);
}
for _ in 0..15 {
test::black_box(h.get(&CONTENT_LENGTH));
test::black_box(h.get(&VARY));
}
});
});
bench!(hn_hdrs_set_8_get_miss(new_map, b) {
let hdrs: Vec<(HeaderName, &'static str)> = super::HN_HDRS[..8].iter()
.map(|&(name, val)| (name.parse().unwrap(), val))
.collect();
let miss: HeaderName = "x-wat".parse().unwrap();
b.iter(|| {
let mut h = new_map();
for &(ref name, val) in hdrs.iter() {
h.insert(name.clone(), val);
}
test::black_box(h.get(&CONTENT_LENGTH));
test::black_box(h.get(&miss));
});
});
bench!(hn_hdrs_set_11_get_with_miss(new_map, b) {
let hdrs: Vec<(HeaderName, &'static str)> = super::HN_HDRS.iter()
.map(|&(name, val)| (name.parse().unwrap(), val))
.collect();
let miss: HeaderName = "x-wat".parse().unwrap();
b.iter(|| {
let mut h = new_map();
for &(ref name, val) in hdrs.iter() {
h.insert(name.clone(), val);
}
for _ in 0..10 {
test::black_box(h.get(&CONTENT_LENGTH));
test::black_box(h.get(&VARY));
test::black_box(h.get(&miss));
}
});
});
use http::header::*;
fn custom_hdr(n: usize) -> Vec<HeaderName> {
(0..n)
.map(|i| {
let s = format!("x-custom-{}", i);
s.parse().unwrap()
})
.collect()
}
fn med_custom_hdr(n: usize) -> Vec<HeaderName> {
(0..n)
.map(|i| {
let s = format!("content-length-{}", i);
s.parse().unwrap()
})
.collect()
}
fn long_custom_hdr(n: usize) -> Vec<HeaderName> {
(0..n)
.map(|i| {
let s = format!("access-control-allow-headers-{}", i);
s.parse().unwrap()
})
.collect()
}
fn very_long_custom_hdr(n: usize) -> Vec<HeaderName> {
(0..n)
.map(|i| {
let s = format!("access-control-allow-access-control-allow-headers-{}", i);
s.parse().unwrap()
})
.collect()
}
fn custom_std(n: usize) -> Vec<HeaderName> {
(0..n)
.map(|i| {
let s = format!("{}-{}", STD[i % STD.len()].as_str(), i);
s.parse().unwrap()
})
.collect()
}
const STD: &'static [HeaderName] = &[
ACCEPT,
ACCEPT_CHARSET,
ACCEPT_ENCODING,
ACCEPT_LANGUAGE,
ACCEPT_RANGES,
ACCESS_CONTROL_ALLOW_CREDENTIALS,
ACCESS_CONTROL_ALLOW_HEADERS,
ACCESS_CONTROL_ALLOW_METHODS,
ACCESS_CONTROL_ALLOW_ORIGIN,
ACCESS_CONTROL_EXPOSE_HEADERS,
ACCESS_CONTROL_MAX_AGE,
ACCESS_CONTROL_REQUEST_HEADERS,
ACCESS_CONTROL_REQUEST_METHOD,
AGE,
ALLOW,
ALT_SVC,
AUTHORIZATION,
CACHE_CONTROL,
CONNECTION,
CONTENT_DISPOSITION,
CONTENT_ENCODING,
CONTENT_LANGUAGE,
CONTENT_LENGTH,
CONTENT_LOCATION,
CONTENT_RANGE,
CONTENT_SECURITY_POLICY,
CONTENT_SECURITY_POLICY_REPORT_ONLY,
CONTENT_TYPE,
COOKIE,
DNT,
DATE,
ETAG,
EXPECT,
EXPIRES,
FORWARDED,
FROM,
HOST,
IF_MATCH,
IF_MODIFIED_SINCE,
IF_NONE_MATCH,
IF_RANGE,
IF_UNMODIFIED_SINCE,
LAST_MODIFIED,
LINK,
LOCATION,
MAX_FORWARDS,
ORIGIN,
PRAGMA,
PROXY_AUTHENTICATE,
PROXY_AUTHORIZATION,
PUBLIC_KEY_PINS,
PUBLIC_KEY_PINS_REPORT_ONLY,
RANGE,
REFERER,
REFERRER_POLICY,
REFRESH,
RETRY_AFTER,
SERVER,
SET_COOKIE,
STRICT_TRANSPORT_SECURITY,
TE,
TRAILER,
TRANSFER_ENCODING,
USER_AGENT,
UPGRADE,
UPGRADE_INSECURE_REQUESTS,
VARY,
VIA,
WARNING,
WWW_AUTHENTICATE,
X_CONTENT_TYPE_OPTIONS,
X_DNS_PREFETCH_CONTROL,
X_FRAME_OPTIONS,
X_XSS_PROTECTION,
];

View File

@@ -0,0 +1,6 @@
#![feature(test)]
extern crate test;
mod basic;
mod vec_map;

View File

@@ -0,0 +1,107 @@
#![allow(dead_code)]
#[derive(Clone)]
pub struct VecMap<K, V> {
vec: Vec<(K, V)>,
}
impl<K: PartialEq, V> VecMap<K, V> {
#[inline]
pub fn with_capacity(cap: usize) -> VecMap<K, V> {
VecMap {
vec: Vec::with_capacity(cap),
}
}
#[inline]
pub fn insert(&mut self, key: K, value: V) {
match self.find(&key) {
Some(pos) => self.vec[pos] = (key, value),
None => self.vec.push((key, value)),
}
}
#[inline]
pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
match self.find(&key) {
Some(pos) => Entry::Occupied(OccupiedEntry {
vec: self,
pos: pos,
}),
None => Entry::Vacant(VacantEntry {
vec: self,
key: key,
}),
}
}
#[inline]
pub fn get<K2: PartialEq<K> + ?Sized>(&self, key: &K2) -> Option<&V> {
self.find(key).map(move |pos| &self.vec[pos].1)
}
#[inline]
pub fn get_mut<K2: PartialEq<K> + ?Sized>(&mut self, key: &K2) -> Option<&mut V> {
self.find(key).map(move |pos| &mut self.vec[pos].1)
}
#[inline]
pub fn contains_key<K2: PartialEq<K> + ?Sized>(&self, key: &K2) -> bool {
self.find(key).is_some()
}
#[inline]
pub fn len(&self) -> usize {
self.vec.len()
}
#[inline]
pub fn iter(&self) -> ::std::slice::Iter<'_, (K, V)> {
self.vec.iter()
}
#[inline]
pub fn remove<K2: PartialEq<K> + ?Sized>(&mut self, key: &K2) -> Option<V> {
self.find(key)
.map(|pos| self.vec.remove(pos))
.map(|(_, v)| v)
}
#[inline]
pub fn clear(&mut self) {
self.vec.clear();
}
#[inline]
fn find<K2: PartialEq<K> + ?Sized>(&self, key: &K2) -> Option<usize> {
self.vec.iter().position(|entry| key == &entry.0)
}
}
pub enum Entry<'a, K: 'a, V: 'a> {
Vacant(VacantEntry<'a, K, V>),
Occupied(OccupiedEntry<'a, K, V>),
}
pub struct VacantEntry<'a, K, V> {
vec: &'a mut VecMap<K, V>,
key: K,
}
impl<'a, K, V> VacantEntry<'a, K, V> {
pub fn insert(self, val: V) -> &'a mut V {
let vec = self.vec;
vec.vec.push((self.key, val));
let pos = vec.vec.len() - 1;
&mut vec.vec[pos].1
}
}
pub struct OccupiedEntry<'a, K, V> {
vec: &'a mut VecMap<K, V>,
pos: usize,
}
impl<'a, K, V> OccupiedEntry<'a, K, V> {
pub fn into_mut(self) -> &'a mut V {
&mut self.vec.vec[self.pos].1
}
}

View File

@@ -0,0 +1,296 @@
#![feature(test)]
extern crate bytes;
extern crate http;
extern crate test;
use http::header::HeaderName;
use test::Bencher;
fn make_all_known_headers() -> Vec<Vec<u8>> {
// Standard request headers
vec![b"A-IM".to_vec(),
b"Accept".to_vec(),
b"Accept-Charset".to_vec(),
b"Accept-Datetime".to_vec(),
b"Accept-Encoding".to_vec(),
b"Accept-Language".to_vec(),
b"Access-Control-Request-Method".to_vec(),
b"Authorization".to_vec(),
b"Cache-Control".to_vec(),
b"Connection".to_vec(),
b"Permanent".to_vec(),
b"Content-Length".to_vec(),
b"Content-MD5".to_vec(),
b"Content-Type".to_vec(),
b"Cookie".to_vec(),
b"Date".to_vec(),
b"Expect".to_vec(),
b"Forwarded".to_vec(),
b"From".to_vec(),
b"Host".to_vec(),
b"Permanent".to_vec(),
b"HTTP2-Settings".to_vec(),
b"If-Match".to_vec(),
b"If-Modified-Since".to_vec(),
b"If-None-Match".to_vec(),
b"If-Range".to_vec(),
b"If-Unmodified-Since".to_vec(),
b"Max-Forwards".to_vec(),
b"Origin".to_vec(),
b"Pragma".to_vec(),
b"Proxy-Authorization".to_vec(),
b"Range".to_vec(),
b"Referer".to_vec(),
b"TE".to_vec(),
b"User-Agent".to_vec(),
b"Upgrade".to_vec(),
b"Via".to_vec(),
b"Warning".to_vec(),
// common_non_standard
b"Upgrade-Insecure-Requests".to_vec(),
b"Upgrade-Insecure-Requests".to_vec(),
b"X-Requested-With".to_vec(),
b"DNT".to_vec(),
b"X-Forwarded-For".to_vec(),
b"X-Forwarded-Host".to_vec(),
b"X-Forwarded-Proto".to_vec(),
b"Front-End-Https".to_vec(),
b"X-Http-Method-Override".to_vec(),
b"X-ATT-DeviceId".to_vec(),
b"X-Wap-Profile".to_vec(),
b"Proxy-Connection".to_vec(),
b"X-UIDH".to_vec(),
b"X-Csrf-Token".to_vec(),
b"X-Request-ID".to_vec(),
b"X-Correlation-ID".to_vec(),
b"Save-Data".to_vec(),
// standard_response_headers
b"Accept-Patch".to_vec(),
b"Accept-Ranges".to_vec(),
b"Access-Control-Allow-Credentials".to_vec(),
b"Access-Control-Allow-Headers".to_vec(),
b"Access-Control-Allow-Methods".to_vec(),
b"Access-Control-Allow-Origin".to_vec(),
b"Access-Control-Expose-Headers".to_vec(),
b"Access-Control-Max-Age".to_vec(),
b"Age".to_vec(),
b"Allow".to_vec(),
b"Alt-Svc".to_vec(),
b"Cache-Control".to_vec(),
b"Connection".to_vec(),
b"Content-Disposition".to_vec(),
b"Content-Encoding".to_vec(),
b"Content-Language".to_vec(),
b"Content-Length".to_vec(),
b"Content-Location".to_vec(),
b"Content-MD5".to_vec(),
b"Content-Range".to_vec(),
b"Content-Type".to_vec(),
b"Date".to_vec(),
b"Delta-Base".to_vec(),
b"ETag".to_vec(),
b"Expires".to_vec(),
b"IM".to_vec(),
b"Last-Modified".to_vec(),
b"Link".to_vec(),
b"Location".to_vec(),
b"P3P".to_vec(),
b"Permanent".to_vec(),
b"Pragma".to_vec(),
b"Proxy-Authenticate".to_vec(),
b"Public-Key-Pins".to_vec(),
b"Retry-After".to_vec(),
b"Server".to_vec(),
b"Set-Cookie".to_vec(),
b"Strict-Transport-Security".to_vec(),
b"Tk".to_vec(),
b"Trailer".to_vec(),
b"Transfer-Encoding".to_vec(),
b"Upgrade".to_vec(),
b"Vary".to_vec(),
b"Via".to_vec(),
b"Warning".to_vec(),
b"WWW-Authenticate".to_vec(),
b"X-Frame-Options".to_vec(),
// common_non_standard_response
b"Content-Security-Policy".to_vec(),
b"Refresh".to_vec(),
b"Status".to_vec(),
b"Timing-Allow-Origin".to_vec(),
b"X-Content-Duration".to_vec(),
b"X-Content-Security-Policy".to_vec(),
b"X-Content-Type-Options".to_vec(),
b"X-Correlation-ID".to_vec(),
b"X-Powered-By".to_vec(),
b"X-Request-ID".to_vec(),
b"X-UA-Compatible".to_vec(),
b"X-WebKit-CSP".to_vec(),
b"X-XSS-Protection".to_vec(),
]
}
static ALL_KNOWN_HEADERS: &[&str] = &[
// Standard request headers
"a-im",
"accept",
"accept-charset",
"accept-datetime",
"accept-encoding",
"accept-language",
"access-control-request-method",
"authorization",
"cache-control",
"connection",
"permanent",
"content-length",
"content-md5",
"content-type",
"cookie",
"date",
"expect",
"forwarded",
"from",
"host",
"permanent",
"http2-settings",
"if-match",
"if-modified-since",
"if-none-match",
"if-range",
"if-unmodified-since",
"max-forwards",
"origin",
"pragma",
"proxy-authorization",
"range",
"referer",
"te",
"user-agent",
"upgrade",
"via",
"warning",
// common_non_standard
"upgrade-insecure-requests",
"upgrade-insecure-requests",
"x-requested-with",
"dnt",
"x-forwarded-for",
"x-forwarded-host",
"x-forwarded-proto",
"front-end-https",
"x-http-method-override",
"x-att-deviceid",
"x-wap-profile",
"proxy-connection",
"x-uidh",
"x-csrf-token",
"x-request-id",
"x-correlation-id",
"save-data",
// standard_response_headers
"accept-patch",
"accept-ranges",
"access-control-allow-credentials",
"access-control-allow-headers",
"access-control-allow-methods",
"access-control-allow-origin",
"access-control-expose-headers",
"access-control-max-age",
"age",
"allow",
"alt-svc",
"cache-control",
"connection",
"content-disposition",
"content-encoding",
"content-language",
"content-length",
"content-location",
"content-md5",
"content-range",
"content-type",
"date",
"delta-base",
"etag",
"expires",
"im",
"last-modified",
"link",
"location",
"p3p",
"permanent",
"pragma",
"proxy-authenticate",
"public-key-pins",
"retry-after",
"server",
"set-cookie",
"strict-transport-security",
"tk",
"trailer",
"transfer-encoding",
"upgrade",
"vary",
"via",
"warning",
"www-authenticate",
"x-frame-options",
// common_non_standard_response
"content-security-policy",
"refresh",
"status",
"timing-allow-origin",
"x-content-duration",
"x-content-security-policy",
"x-content-type-options",
"x-correlation-id",
"x-powered-by",
"x-request-id",
"x-ua-compatible",
"x-webkit-csp",
"x-xss-protection",
];
#[bench]
fn header_name_easy(b: &mut Bencher) {
let name = b"Content-type";
b.iter(|| {
HeaderName::from_bytes(&name[..]).unwrap();
});
}
#[bench]
fn header_name_custom(b: &mut Bencher) {
let name = b"Foo-Bar-Baz-Blah";
b.iter(|| {
HeaderName::from_bytes(&name[..]).unwrap();
});
}
#[bench]
fn header_name_bad(b: &mut Bencher) {
let name = b"bad header name";
b.iter(|| {
HeaderName::from_bytes(&name[..]).expect_err("Bad header name");
});
}
#[bench]
fn header_name_various(b: &mut Bencher) {
let all_known_headers = make_all_known_headers();
b.iter(|| {
for name in &all_known_headers{
HeaderName::from_bytes(name.as_slice()).unwrap();
}
});
}
#[bench]
fn header_name_from_static(b: &mut Bencher) {
b.iter(|| {
for name in ALL_KNOWN_HEADERS {
HeaderName::from_static(name);
}
});
}

View File

@@ -0,0 +1,52 @@
use criterion::{criterion_group, criterion_main, BenchmarkId,Criterion, Throughput};
use http::header::HeaderName;
// This is a list of some of the standard headers ordered by increasing size.
// It has exactly one standard header per size (some sizes don't have a standard
// header).
const STANDARD_HEADERS_BY_SIZE: &[&str] = &[
"te",
"age",
"date",
"allow",
"accept",
"alt-svc",
"if-match",
"forwarded",
"connection",
"retry-after",
"content-type",
"accept-ranges",
"accept-charset",
"accept-encoding",
"content-encoding",
"if-modified-since",
"proxy-authenticate",
"content-disposition",
"sec-websocket-accept",
"sec-websocket-version",
"access-control-max-age",
"content-security-policy",
"sec-websocket-extensions",
"strict-transport-security",
"access-control-allow-origin",
"access-control-allow-headers",
"access-control-expose-headers",
"access-control-request-headers",
"access-control-allow-credentials",
"content-security-policy-report-only",
];
fn header_name_by_size(c: &mut Criterion) {
let mut group = c.benchmark_group("std_hdr");
for name in STANDARD_HEADERS_BY_SIZE {
group.throughput(Throughput::Bytes(name.len() as u64));
group.bench_with_input(BenchmarkId::from_parameter(name), name, |b, name| {
b.iter(|| HeaderName::from_static(name) );
});
}
group.finish();
}
criterion_group!(benches, header_name_by_size);
criterion_main!(benches);

View File

@@ -0,0 +1,46 @@
#![feature(test)]
extern crate test;
use bytes::Bytes;
use http::HeaderValue;
use test::Bencher;
static SHORT: &'static [u8] = b"localhost";
static LONG: &'static [u8] = b"Mozilla/5.0 (X11; CrOS x86_64 9592.71.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.80 Safari/537.36";
#[bench]
fn from_shared_short(b: &mut Bencher) {
b.bytes = SHORT.len() as u64;
let bytes = Bytes::from_static(SHORT);
b.iter(|| {
HeaderValue::from_maybe_shared(bytes.clone()).unwrap();
});
}
#[bench]
fn from_shared_long(b: &mut Bencher) {
b.bytes = LONG.len() as u64;
let bytes = Bytes::from_static(LONG);
b.iter(|| {
HeaderValue::from_maybe_shared(bytes.clone()).unwrap();
});
}
#[bench]
fn from_shared_unchecked_short(b: &mut Bencher) {
b.bytes = SHORT.len() as u64;
let bytes = Bytes::from_static(SHORT);
b.iter(|| unsafe {
HeaderValue::from_maybe_shared_unchecked(bytes.clone());
});
}
#[bench]
fn from_shared_unchecked_long(b: &mut Bencher) {
b.bytes = LONG.len() as u64;
let bytes = Bytes::from_static(LONG);
b.iter(|| unsafe {
HeaderValue::from_maybe_shared_unchecked(bytes.clone());
});
}

40
zeroidc/vendor/http/benches/method.rs vendored Normal file
View File

@@ -0,0 +1,40 @@
#![feature(test)]
extern crate test;
use http::method::Method;
use test::Bencher;
fn make_all_methods() -> Vec<Vec<u8>> {
vec![
b"OPTIONS".to_vec(),
b"GET".to_vec(),
b"POST".to_vec(),
b"PUT".to_vec(),
b"DELETE".to_vec(),
b"HEAD".to_vec(),
b"TRACE".to_vec(),
b"CONNECT".to_vec(),
b"PATCH".to_vec(),
b"CUSTOM_SHORT".to_vec(),
b"CUSTOM_LONG_METHOD".to_vec(),
]
}
#[bench]
fn method_easy(b: &mut Bencher) {
let name = b"GET";
b.iter(|| {
Method::from_bytes(&name[..]).unwrap();
});
}
#[bench]
fn method_various(b: &mut Bencher) {
let all_methods = make_all_methods();
b.iter(|| {
for name in &all_methods {
Method::from_bytes(name.as_slice()).unwrap();
}
});
}

32
zeroidc/vendor/http/benches/uri.rs vendored Normal file
View File

@@ -0,0 +1,32 @@
#![feature(test)]
extern crate test;
use http::Uri;
use test::Bencher;
#[bench]
fn uri_parse_slash(b: &mut Bencher) {
b.bytes = 1;
b.iter(|| {
"/".parse::<Uri>().unwrap();
});
}
#[bench]
fn uri_parse_relative_medium(b: &mut Bencher) {
let s = "/wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg";
b.bytes = s.len() as u64;
b.iter(|| {
s.parse::<Uri>().unwrap();
});
}
#[bench]
fn uri_parse_relative_query(b: &mut Bencher) {
let s = "/wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg?foo={bar}|baz%13%11quux";
b.bytes = s.len() as u64;
b.iter(|| {
s.parse::<Uri>().unwrap();
});
}

85
zeroidc/vendor/http/src/byte_str.rs vendored Normal file
View File

@@ -0,0 +1,85 @@
use bytes::Bytes;
use std::{ops, str};
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub(crate) struct ByteStr {
// Invariant: bytes contains valid UTF-8
bytes: Bytes,
}
impl ByteStr {
#[inline]
pub fn new() -> ByteStr {
ByteStr {
// Invariant: the empty slice is trivially valid UTF-8.
bytes: Bytes::new(),
}
}
#[inline]
pub const fn from_static(val: &'static str) -> ByteStr {
ByteStr {
// Invariant: val is a str so contains vaid UTF-8.
bytes: Bytes::from_static(val.as_bytes()),
}
}
#[inline]
/// ## Panics
/// In a debug build this will panic if `bytes` is not valid UTF-8.
///
/// ## Safety
/// `bytes` must contain valid UTF-8. In a release build it is undefined
/// behaviour to call this with `bytes` that is not valid UTF-8.
pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> ByteStr {
if cfg!(debug_assertions) {
match str::from_utf8(&bytes) {
Ok(_) => (),
Err(err) => panic!(
"ByteStr::from_utf8_unchecked() with invalid bytes; error = {}, bytes = {:?}",
err, bytes
),
}
}
// Invariant: assumed by the safety requirements of this function.
ByteStr { bytes: bytes }
}
}
impl ops::Deref for ByteStr {
type Target = str;
#[inline]
fn deref(&self) -> &str {
let b: &[u8] = self.bytes.as_ref();
// Safety: the invariant of `bytes` is that it contains valid UTF-8.
unsafe { str::from_utf8_unchecked(b) }
}
}
impl From<String> for ByteStr {
#[inline]
fn from(src: String) -> ByteStr {
ByteStr {
// Invariant: src is a String so contains valid UTF-8.
bytes: Bytes::from(src),
}
}
}
impl<'a> From<&'a str> for ByteStr {
#[inline]
fn from(src: &'a str) -> ByteStr {
ByteStr {
// Invariant: src is a str so contains valid UTF-8.
bytes: Bytes::copy_from_slice(src.as_bytes()),
}
}
}
impl From<ByteStr> for Bytes {
fn from(src: ByteStr) -> Self {
src.bytes
}
}

17
zeroidc/vendor/http/src/convert.rs vendored Normal file
View File

@@ -0,0 +1,17 @@
macro_rules! if_downcast_into {
($in_ty:ty, $out_ty:ty, $val:ident, $body:expr) => ({
if std::any::TypeId::of::<$in_ty>() == std::any::TypeId::of::<$out_ty>() {
// Store the value in an `Option` so we can `take`
// it after casting to `&mut dyn Any`.
let mut slot = Some($val);
// Re-write the `$val` ident with the downcasted value.
let $val = (&mut slot as &mut dyn std::any::Any)
.downcast_mut::<Option<$out_ty>>()
.unwrap()
.take()
.unwrap();
// Run the $body in scope of the replaced val.
$body
}
})
}

149
zeroidc/vendor/http/src/error.rs vendored Normal file
View File

@@ -0,0 +1,149 @@
use std::error;
use std::fmt;
use std::result;
use crate::header;
use crate::method;
use crate::status;
use crate::uri;
/// A generic "error" for HTTP connections
///
/// This error type is less specific than the error returned from other
/// functions in this crate, but all other errors can be converted to this
/// error. Consumers of this crate can typically consume and work with this form
/// of error for conversions with the `?` operator.
pub struct Error {
inner: ErrorKind,
}
/// A `Result` typedef to use with the `http::Error` type
pub type Result<T> = result::Result<T, Error>;
enum ErrorKind {
StatusCode(status::InvalidStatusCode),
Method(method::InvalidMethod),
Uri(uri::InvalidUri),
UriParts(uri::InvalidUriParts),
HeaderName(header::InvalidHeaderName),
HeaderValue(header::InvalidHeaderValue),
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("http::Error")
// Skip the noise of the ErrorKind enum
.field(&self.get_ref())
.finish()
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.get_ref(), f)
}
}
impl Error {
/// Return true if the underlying error has the same type as T.
pub fn is<T: error::Error + 'static>(&self) -> bool {
self.get_ref().is::<T>()
}
/// Return a reference to the lower level, inner error.
pub fn get_ref(&self) -> &(dyn error::Error + 'static) {
use self::ErrorKind::*;
match self.inner {
StatusCode(ref e) => e,
Method(ref e) => e,
Uri(ref e) => e,
UriParts(ref e) => e,
HeaderName(ref e) => e,
HeaderValue(ref e) => e,
}
}
}
impl error::Error for Error {
// Return any available cause from the inner error. Note the inner error is
// not itself the cause.
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
self.get_ref().source()
}
}
impl From<status::InvalidStatusCode> for Error {
fn from(err: status::InvalidStatusCode) -> Error {
Error {
inner: ErrorKind::StatusCode(err),
}
}
}
impl From<method::InvalidMethod> for Error {
fn from(err: method::InvalidMethod) -> Error {
Error {
inner: ErrorKind::Method(err),
}
}
}
impl From<uri::InvalidUri> for Error {
fn from(err: uri::InvalidUri) -> Error {
Error {
inner: ErrorKind::Uri(err),
}
}
}
impl From<uri::InvalidUriParts> for Error {
fn from(err: uri::InvalidUriParts) -> Error {
Error {
inner: ErrorKind::UriParts(err),
}
}
}
impl From<header::InvalidHeaderName> for Error {
fn from(err: header::InvalidHeaderName) -> Error {
Error {
inner: ErrorKind::HeaderName(err),
}
}
}
impl From<header::InvalidHeaderValue> for Error {
fn from(err: header::InvalidHeaderValue) -> Error {
Error {
inner: ErrorKind::HeaderValue(err),
}
}
}
impl From<std::convert::Infallible> for Error {
fn from(err: std::convert::Infallible) -> Error {
match err {}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn inner_error_is_invalid_status_code() {
if let Err(e) = status::StatusCode::from_u16(6666) {
let err: Error = e.into();
let ie = err.get_ref();
assert!(!ie.is::<header::InvalidHeaderValue>());
assert!(ie.is::<status::InvalidStatusCode>());
ie.downcast_ref::<status::InvalidStatusCode>().unwrap();
assert!(!err.is::<header::InvalidHeaderValue>());
assert!(err.is::<status::InvalidStatusCode>());
} else {
panic!("Bad status allowed!");
}
}
}

250
zeroidc/vendor/http/src/extensions.rs vendored Normal file
View File

@@ -0,0 +1,250 @@
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::fmt;
use std::hash::{BuildHasherDefault, Hasher};
type AnyMap = HashMap<TypeId, Box<dyn Any + Send + Sync>, BuildHasherDefault<IdHasher>>;
// With TypeIds as keys, there's no need to hash them. They are already hashes
// themselves, coming from the compiler. The IdHasher just holds the u64 of
// the TypeId, and then returns it, instead of doing any bit fiddling.
#[derive(Default)]
struct IdHasher(u64);
impl Hasher for IdHasher {
fn write(&mut self, _: &[u8]) {
unreachable!("TypeId calls write_u64");
}
#[inline]
fn write_u64(&mut self, id: u64) {
self.0 = id;
}
#[inline]
fn finish(&self) -> u64 {
self.0
}
}
/// A type map of protocol extensions.
///
/// `Extensions` can be used by `Request` and `Response` to store
/// extra data derived from the underlying protocol.
#[derive(Default)]
pub struct Extensions {
// If extensions are never used, no need to carry around an empty HashMap.
// That's 3 words. Instead, this is only 1 word.
map: Option<Box<AnyMap>>,
}
impl Extensions {
/// Create an empty `Extensions`.
#[inline]
pub fn new() -> Extensions {
Extensions { map: None }
}
/// Insert a type into this `Extensions`.
///
/// If a extension of this type already existed, it will
/// be returned.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// assert!(ext.insert(5i32).is_none());
/// assert!(ext.insert(4u8).is_none());
/// assert_eq!(ext.insert(9i32), Some(5i32));
/// ```
pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
self.map
.get_or_insert_with(|| Box::new(HashMap::default()))
.insert(TypeId::of::<T>(), Box::new(val))
.and_then(|boxed| {
(boxed as Box<dyn Any + 'static>)
.downcast()
.ok()
.map(|boxed| *boxed)
})
}
/// Get a reference to a type previously inserted on this `Extensions`.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// assert!(ext.get::<i32>().is_none());
/// ext.insert(5i32);
///
/// assert_eq!(ext.get::<i32>(), Some(&5i32));
/// ```
pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
self.map
.as_ref()
.and_then(|map| map.get(&TypeId::of::<T>()))
.and_then(|boxed| (&**boxed as &(dyn Any + 'static)).downcast_ref())
}
/// Get a mutable reference to a type previously inserted on this `Extensions`.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// ext.insert(String::from("Hello"));
/// ext.get_mut::<String>().unwrap().push_str(" World");
///
/// assert_eq!(ext.get::<String>().unwrap(), "Hello World");
/// ```
pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
self.map
.as_mut()
.and_then(|map| map.get_mut(&TypeId::of::<T>()))
.and_then(|boxed| (&mut **boxed as &mut (dyn Any + 'static)).downcast_mut())
}
/// Remove a type from this `Extensions`.
///
/// If a extension of this type existed, it will be returned.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// ext.insert(5i32);
/// assert_eq!(ext.remove::<i32>(), Some(5i32));
/// assert!(ext.get::<i32>().is_none());
/// ```
pub fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
self.map
.as_mut()
.and_then(|map| map.remove(&TypeId::of::<T>()))
.and_then(|boxed| {
(boxed as Box<dyn Any + 'static>)
.downcast()
.ok()
.map(|boxed| *boxed)
})
}
/// Clear the `Extensions` of all inserted extensions.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// ext.insert(5i32);
/// ext.clear();
///
/// assert!(ext.get::<i32>().is_none());
/// ```
#[inline]
pub fn clear(&mut self) {
if let Some(ref mut map) = self.map {
map.clear();
}
}
/// Check whether the extension set is empty or not.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// assert!(ext.is_empty());
/// ext.insert(5i32);
/// assert!(!ext.is_empty());
/// ```
#[inline]
pub fn is_empty(&self) -> bool {
self.map
.as_ref()
.map_or(true, |map| map.is_empty())
}
/// Get the numer of extensions available.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// assert_eq!(ext.len(), 0);
/// ext.insert(5i32);
/// assert_eq!(ext.len(), 1);
/// ```
#[inline]
pub fn len(&self) -> usize {
self.map
.as_ref()
.map_or(0, |map| map.len())
}
/// Extends `self` with another `Extensions`.
///
/// If an instance of a specific type exists in both, the one in `self` is overwritten with the
/// one from `other`.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext_a = Extensions::new();
/// ext_a.insert(8u8);
/// ext_a.insert(16u16);
///
/// let mut ext_b = Extensions::new();
/// ext_b.insert(4u8);
/// ext_b.insert("hello");
///
/// ext_a.extend(ext_b);
/// assert_eq!(ext_a.len(), 3);
/// assert_eq!(ext_a.get::<u8>(), Some(&4u8));
/// assert_eq!(ext_a.get::<u16>(), Some(&16u16));
/// assert_eq!(ext_a.get::<&'static str>().copied(), Some("hello"));
/// ```
pub fn extend(&mut self, other: Self) {
if let Some(other) = other.map {
if let Some(map) = &mut self.map {
map.extend(*other);
} else {
self.map = Some(other);
}
}
}
}
impl fmt::Debug for Extensions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Extensions").finish()
}
}
#[test]
fn test_extensions() {
#[derive(Debug, PartialEq)]
struct MyType(i32);
let mut extensions = Extensions::new();
extensions.insert(5i32);
extensions.insert(MyType(10));
assert_eq!(extensions.get(), Some(&5i32));
assert_eq!(extensions.get_mut(), Some(&mut 5i32));
assert_eq!(extensions.remove::<i32>(), Some(5i32));
assert!(extensions.get::<i32>().is_none());
assert_eq!(extensions.get::<bool>(), None);
assert_eq!(extensions.get(), Some(&MyType(10)));
}

3496
zeroidc/vendor/http/src/header/map.rs vendored Normal file

File diff suppressed because it is too large Load Diff

172
zeroidc/vendor/http/src/header/mod.rs vendored Normal file
View File

@@ -0,0 +1,172 @@
//! HTTP header types
//!
//! The module provides [`HeaderName`], [`HeaderMap`], and a number of types
//! used for interacting with `HeaderMap`. These types allow representing both
//! HTTP/1 and HTTP/2 headers.
//!
//! # `HeaderName`
//!
//! The `HeaderName` type represents both standard header names as well as
//! custom header names. The type handles the case insensitive nature of header
//! names and is used as the key portion of `HeaderMap`. Header names are
//! normalized to lower case. In other words, when creating a `HeaderName` with
//! a string, even if upper case characters are included, when getting a string
//! representation of the `HeaderName`, it will be all lower case. This allows
//! for faster `HeaderMap` comparison operations.
//!
//! The internal representation is optimized to efficiently handle the cases
//! most commonly encountered when working with HTTP. Standard header names are
//! special cased and are represented internally as an enum. Short custom
//! headers will be stored directly in the `HeaderName` struct and will not
//! incur any allocation overhead, however longer strings will require an
//! allocation for storage.
//!
//! ## Limitations
//!
//! `HeaderName` has a max length of 32,768 for header names. Attempting to
//! parse longer names will result in a panic.
//!
//! # `HeaderMap`
//!
//! `HeaderMap` is a map structure of header names highly optimized for use
//! cases common with HTTP. It is a [multimap] structure, where each header name
//! may have multiple associated header values. Given this, some of the APIs
//! diverge from [`HashMap`].
//!
//! ## Overview
//!
//! Just like `HashMap` in Rust's stdlib, `HeaderMap` is based on [Robin Hood
//! hashing]. This algorithm tends to reduce the worst case search times in the
//! table and enables high load factors without seriously affecting performance.
//! Internally, keys and values are stored in vectors. As such, each insertion
//! will not incur allocation overhead. However, once the underlying vector
//! storage is full, a larger vector must be allocated and all values copied.
//!
//! ## Deterministic ordering
//!
//! Unlike Rust's `HashMap`, values in `HeaderMap` are deterministically
//! ordered. Roughly, values are ordered by insertion. This means that a
//! function that deterministically operates on a header map can rely on the
//! iteration order to remain consistent across processes and platforms.
//!
//! ## Adaptive hashing
//!
//! `HeaderMap` uses an adaptive hashing strategy in order to efficiently handle
//! most common cases. All standard headers have statically computed hash values
//! which removes the need to perform any hashing of these headers at runtime.
//! The default hash function emphasizes performance over robustness. However,
//! `HeaderMap` detects high collision rates and switches to a secure hash
//! function in those events. The threshold is set such that only denial of
//! service attacks should trigger it.
//!
//! ## Limitations
//!
//! `HeaderMap` can store a maximum of 32,768 headers (header name / value
//! pairs). Attempting to insert more will result in a panic.
//!
//! [`HeaderName`]: struct.HeaderName.html
//! [`HeaderMap`]: struct.HeaderMap.html
//! [multimap]: https://en.wikipedia.org/wiki/Multimap
//! [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html
//! [Robin Hood hashing]: https://en.wikipedia.org/wiki/Hash_table#Robin_Hood_hashing
mod map;
mod name;
mod value;
pub use self::map::{
AsHeaderName, Drain, Entry, GetAll, HeaderMap, IntoHeaderName, IntoIter, Iter, IterMut, Keys,
OccupiedEntry, VacantEntry, ValueDrain, ValueIter, ValueIterMut, Values, ValuesMut,
};
pub use self::name::{HeaderName, InvalidHeaderName};
pub use self::value::{HeaderValue, InvalidHeaderValue, ToStrError};
// Use header name constants
pub use self::name::{
ACCEPT,
ACCEPT_CHARSET,
ACCEPT_ENCODING,
ACCEPT_LANGUAGE,
ACCEPT_RANGES,
ACCESS_CONTROL_ALLOW_CREDENTIALS,
ACCESS_CONTROL_ALLOW_HEADERS,
ACCESS_CONTROL_ALLOW_METHODS,
ACCESS_CONTROL_ALLOW_ORIGIN,
ACCESS_CONTROL_EXPOSE_HEADERS,
ACCESS_CONTROL_MAX_AGE,
ACCESS_CONTROL_REQUEST_HEADERS,
ACCESS_CONTROL_REQUEST_METHOD,
AGE,
ALLOW,
ALT_SVC,
AUTHORIZATION,
CACHE_CONTROL,
CONNECTION,
CONTENT_DISPOSITION,
CONTENT_ENCODING,
CONTENT_LANGUAGE,
CONTENT_LENGTH,
CONTENT_LOCATION,
CONTENT_RANGE,
CONTENT_SECURITY_POLICY,
CONTENT_SECURITY_POLICY_REPORT_ONLY,
CONTENT_TYPE,
COOKIE,
DNT,
DATE,
ETAG,
EXPECT,
EXPIRES,
FORWARDED,
FROM,
HOST,
IF_MATCH,
IF_MODIFIED_SINCE,
IF_NONE_MATCH,
IF_RANGE,
IF_UNMODIFIED_SINCE,
LAST_MODIFIED,
LINK,
LOCATION,
MAX_FORWARDS,
ORIGIN,
PRAGMA,
PROXY_AUTHENTICATE,
PROXY_AUTHORIZATION,
PUBLIC_KEY_PINS,
PUBLIC_KEY_PINS_REPORT_ONLY,
RANGE,
REFERER,
REFERRER_POLICY,
REFRESH,
RETRY_AFTER,
SEC_WEBSOCKET_ACCEPT,
SEC_WEBSOCKET_EXTENSIONS,
SEC_WEBSOCKET_KEY,
SEC_WEBSOCKET_PROTOCOL,
SEC_WEBSOCKET_VERSION,
SERVER,
SET_COOKIE,
STRICT_TRANSPORT_SECURITY,
TE,
TRAILER,
TRANSFER_ENCODING,
UPGRADE,
UPGRADE_INSECURE_REQUESTS,
USER_AGENT,
VARY,
VIA,
WARNING,
WWW_AUTHENTICATE,
X_CONTENT_TYPE_OPTIONS,
X_DNS_PREFETCH_CONTROL,
X_FRAME_OPTIONS,
X_XSS_PROTECTION,
};
/// Maximum length of a header name
///
/// Generally, 64kb for a header name is WAY too much than would ever be needed
/// in practice. Restricting it to this size enables using `u16` values to
/// represent offsets when dealing with header names.
const MAX_HEADER_NAME_LEN: usize = (1 << 16) - 1;

1856
zeroidc/vendor/http/src/header/name.rs vendored Normal file

File diff suppressed because it is too large Load Diff

795
zeroidc/vendor/http/src/header/value.rs vendored Normal file
View File

@@ -0,0 +1,795 @@
use bytes::{Bytes, BytesMut};
use std::convert::TryFrom;
use std::error::Error;
use std::fmt::Write;
use std::str::FromStr;
use std::{cmp, fmt, mem, str};
use crate::header::name::HeaderName;
/// Represents an HTTP header field value.
///
/// In practice, HTTP header field values are usually valid ASCII. However, the
/// HTTP spec allows for a header value to contain opaque bytes as well. In this
/// case, the header field value is not able to be represented as a string.
///
/// To handle this, the `HeaderValue` is useable as a type and can be compared
/// with strings and implements `Debug`. A `to_str` fn is provided that returns
/// an `Err` if the header value contains non visible ascii characters.
#[derive(Clone, Hash)]
pub struct HeaderValue {
inner: Bytes,
is_sensitive: bool,
}
/// A possible error when converting a `HeaderValue` from a string or byte
/// slice.
pub struct InvalidHeaderValue {
_priv: (),
}
/// A possible error when converting a `HeaderValue` to a string representation.
///
/// Header field values may contain opaque bytes, in which case it is not
/// possible to represent the value as a string.
#[derive(Debug)]
pub struct ToStrError {
_priv: (),
}
impl HeaderValue {
/// Convert a static string to a `HeaderValue`.
///
/// This function will not perform any copying, however the string is
/// checked to ensure that no invalid characters are present. Only visible
/// ASCII characters (32-127) are permitted.
///
/// # Panics
///
/// This function panics if the argument contains invalid header value
/// characters.
///
/// Until [Allow panicking in constants](https://github.com/rust-lang/rfcs/pull/2345)
/// makes its way into stable, the panic message at compile-time is
/// going to look cryptic, but should at least point at your header value:
///
/// ```text
/// error: any use of this value will cause an error
/// --> http/src/header/value.rs:67:17
/// |
/// 67 | ([] as [u8; 0])[0]; // Invalid header value
/// | ^^^^^^^^^^^^^^^^^^
/// | |
/// | index out of bounds: the length is 0 but the index is 0
/// | inside `HeaderValue::from_static` at http/src/header/value.rs:67:17
/// | inside `INVALID_HEADER` at src/main.rs:73:33
/// |
/// ::: src/main.rs:73:1
/// |
/// 73 | const INVALID_HEADER: HeaderValue = HeaderValue::from_static("жsome value");
/// | ----------------------------------------------------------------------------
/// ```
///
/// # Examples
///
/// ```
/// # use http::header::HeaderValue;
/// let val = HeaderValue::from_static("hello");
/// assert_eq!(val, "hello");
/// ```
#[inline]
#[allow(unconditional_panic)] // required for the panic circumvention
pub const fn from_static(src: &'static str) -> HeaderValue {
let bytes = src.as_bytes();
let mut i = 0;
while i < bytes.len() {
if !is_visible_ascii(bytes[i]) {
([] as [u8; 0])[0]; // Invalid header value
}
i += 1;
}
HeaderValue {
inner: Bytes::from_static(bytes),
is_sensitive: false,
}
}
/// Attempt to convert a string to a `HeaderValue`.
///
/// If the argument contains invalid header value characters, an error is
/// returned. Only visible ASCII characters (32-127) are permitted. Use
/// `from_bytes` to create a `HeaderValue` that includes opaque octets
/// (128-255).
///
/// This function is intended to be replaced in the future by a `TryFrom`
/// implementation once the trait is stabilized in std.
///
/// # Examples
///
/// ```
/// # use http::header::HeaderValue;
/// let val = HeaderValue::from_str("hello").unwrap();
/// assert_eq!(val, "hello");
/// ```
///
/// An invalid value
///
/// ```
/// # use http::header::HeaderValue;
/// let val = HeaderValue::from_str("\n");
/// assert!(val.is_err());
/// ```
#[inline]
pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> {
HeaderValue::try_from_generic(src, |s| Bytes::copy_from_slice(s.as_bytes()))
}
/// Converts a HeaderName into a HeaderValue
///
/// Since every valid HeaderName is a valid HeaderValue this is done infallibly.
///
/// # Examples
///
/// ```
/// # use http::header::{HeaderValue, HeaderName};
/// # use http::header::ACCEPT;
/// let val = HeaderValue::from_name(ACCEPT);
/// assert_eq!(val, HeaderValue::from_bytes(b"accept").unwrap());
/// ```
#[inline]
pub fn from_name(name: HeaderName) -> HeaderValue {
name.into()
}
/// Attempt to convert a byte slice to a `HeaderValue`.
///
/// If the argument contains invalid header value bytes, an error is
/// returned. Only byte values between 32 and 255 (inclusive) are permitted,
/// excluding byte 127 (DEL).
///
/// This function is intended to be replaced in the future by a `TryFrom`
/// implementation once the trait is stabilized in std.
///
/// # Examples
///
/// ```
/// # use http::header::HeaderValue;
/// let val = HeaderValue::from_bytes(b"hello\xfa").unwrap();
/// assert_eq!(val, &b"hello\xfa"[..]);
/// ```
///
/// An invalid value
///
/// ```
/// # use http::header::HeaderValue;
/// let val = HeaderValue::from_bytes(b"\n");
/// assert!(val.is_err());
/// ```
#[inline]
pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
HeaderValue::try_from_generic(src, Bytes::copy_from_slice)
}
/// Attempt to convert a `Bytes` buffer to a `HeaderValue`.
///
/// This will try to prevent a copy if the type passed is the type used
/// internally, and will copy the data if it is not.
pub fn from_maybe_shared<T>(src: T) -> Result<HeaderValue, InvalidHeaderValue>
where
T: AsRef<[u8]> + 'static,
{
if_downcast_into!(T, Bytes, src, {
return HeaderValue::from_shared(src);
});
HeaderValue::from_bytes(src.as_ref())
}
/// Convert a `Bytes` directly into a `HeaderValue` without validating.
///
/// This function does NOT validate that illegal bytes are not contained
/// within the buffer.
pub unsafe fn from_maybe_shared_unchecked<T>(src: T) -> HeaderValue
where
T: AsRef<[u8]> + 'static,
{
if cfg!(debug_assertions) {
match HeaderValue::from_maybe_shared(src) {
Ok(val) => val,
Err(_err) => {
panic!("HeaderValue::from_maybe_shared_unchecked() with invalid bytes");
}
}
} else {
if_downcast_into!(T, Bytes, src, {
return HeaderValue {
inner: src,
is_sensitive: false,
};
});
let src = Bytes::copy_from_slice(src.as_ref());
HeaderValue {
inner: src,
is_sensitive: false,
}
}
}
fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValue> {
HeaderValue::try_from_generic(src, std::convert::identity)
}
fn try_from_generic<T: AsRef<[u8]>, F: FnOnce(T) -> Bytes>(src: T, into: F) -> Result<HeaderValue, InvalidHeaderValue> {
for &b in src.as_ref() {
if !is_valid(b) {
return Err(InvalidHeaderValue { _priv: () });
}
}
Ok(HeaderValue {
inner: into(src),
is_sensitive: false,
})
}
/// Yields a `&str` slice if the `HeaderValue` only contains visible ASCII
/// chars.
///
/// This function will perform a scan of the header value, checking all the
/// characters.
///
/// # Examples
///
/// ```
/// # use http::header::HeaderValue;
/// let val = HeaderValue::from_static("hello");
/// assert_eq!(val.to_str().unwrap(), "hello");
/// ```
pub fn to_str(&self) -> Result<&str, ToStrError> {
let bytes = self.as_ref();
for &b in bytes {
if !is_visible_ascii(b) {
return Err(ToStrError { _priv: () });
}
}
unsafe { Ok(str::from_utf8_unchecked(bytes)) }
}
/// Returns the length of `self`.
///
/// This length is in bytes.
///
/// # Examples
///
/// ```
/// # use http::header::HeaderValue;
/// let val = HeaderValue::from_static("hello");
/// assert_eq!(val.len(), 5);
/// ```
#[inline]
pub fn len(&self) -> usize {
self.as_ref().len()
}
/// Returns true if the `HeaderValue` has a length of zero bytes.
///
/// # Examples
///
/// ```
/// # use http::header::HeaderValue;
/// let val = HeaderValue::from_static("");
/// assert!(val.is_empty());
///
/// let val = HeaderValue::from_static("hello");
/// assert!(!val.is_empty());
/// ```
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Converts a `HeaderValue` to a byte slice.
///
/// # Examples
///
/// ```
/// # use http::header::HeaderValue;
/// let val = HeaderValue::from_static("hello");
/// assert_eq!(val.as_bytes(), b"hello");
/// ```
#[inline]
pub fn as_bytes(&self) -> &[u8] {
self.as_ref()
}
/// Mark that the header value represents sensitive information.
///
/// # Examples
///
/// ```
/// # use http::header::HeaderValue;
/// let mut val = HeaderValue::from_static("my secret");
///
/// val.set_sensitive(true);
/// assert!(val.is_sensitive());
///
/// val.set_sensitive(false);
/// assert!(!val.is_sensitive());
/// ```
#[inline]
pub fn set_sensitive(&mut self, val: bool) {
self.is_sensitive = val;
}
/// Returns `true` if the value represents sensitive data.
///
/// Sensitive data could represent passwords or other data that should not
/// be stored on disk or in memory. By marking header values as sensitive,
/// components using this crate can be instructed to treat them with special
/// care for security reasons. For example, caches can avoid storing
/// sensitive values, and HPACK encoders used by HTTP/2.0 implementations
/// can choose not to compress them.
///
/// Additionally, sensitive values will be masked by the `Debug`
/// implementation of `HeaderValue`.
///
/// Note that sensitivity is not factored into equality or ordering.
///
/// # Examples
///
/// ```
/// # use http::header::HeaderValue;
/// let mut val = HeaderValue::from_static("my secret");
///
/// val.set_sensitive(true);
/// assert!(val.is_sensitive());
///
/// val.set_sensitive(false);
/// assert!(!val.is_sensitive());
/// ```
#[inline]
pub fn is_sensitive(&self) -> bool {
self.is_sensitive
}
}
impl AsRef<[u8]> for HeaderValue {
#[inline]
fn as_ref(&self) -> &[u8] {
self.inner.as_ref()
}
}
impl fmt::Debug for HeaderValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_sensitive {
f.write_str("Sensitive")
} else {
f.write_str("\"")?;
let mut from = 0;
let bytes = self.as_bytes();
for (i, &b) in bytes.iter().enumerate() {
if !is_visible_ascii(b) || b == b'"' {
if from != i {
f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..i]) })?;
}
if b == b'"' {
f.write_str("\\\"")?;
} else {
write!(f, "\\x{:x}", b)?;
}
from = i + 1;
}
}
f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..]) })?;
f.write_str("\"")
}
}
}
impl From<HeaderName> for HeaderValue {
#[inline]
fn from(h: HeaderName) -> HeaderValue {
HeaderValue {
inner: h.into_bytes(),
is_sensitive: false,
}
}
}
macro_rules! from_integers {
($($name:ident: $t:ident => $max_len:expr),*) => {$(
impl From<$t> for HeaderValue {
fn from(num: $t) -> HeaderValue {
let mut buf = if mem::size_of::<BytesMut>() - 1 < $max_len {
// On 32bit platforms, BytesMut max inline size
// is 15 bytes, but the $max_len could be bigger.
//
// The likelihood of the number *actually* being
// that big is very small, so only allocate
// if the number needs that space.
//
// The largest decimal number in 15 digits:
// It wold be 10.pow(15) - 1, but this is a constant
// version.
if num as u64 > 999_999_999_999_999_999 {
BytesMut::with_capacity($max_len)
} else {
// fits inline...
BytesMut::new()
}
} else {
// full value fits inline, so don't allocate!
BytesMut::new()
};
let _ = buf.write_str(::itoa::Buffer::new().format(num));
HeaderValue {
inner: buf.freeze(),
is_sensitive: false,
}
}
}
#[test]
fn $name() {
let n: $t = 55;
let val = HeaderValue::from(n);
assert_eq!(val, &n.to_string());
let n = ::std::$t::MAX;
let val = HeaderValue::from(n);
assert_eq!(val, &n.to_string());
}
)*};
}
from_integers! {
// integer type => maximum decimal length
// u8 purposely left off... HeaderValue::from(b'3') could be confusing
from_u16: u16 => 5,
from_i16: i16 => 6,
from_u32: u32 => 10,
from_i32: i32 => 11,
from_u64: u64 => 20,
from_i64: i64 => 20
}
#[cfg(target_pointer_width = "16")]
from_integers! {
from_usize: usize => 5,
from_isize: isize => 6
}
#[cfg(target_pointer_width = "32")]
from_integers! {
from_usize: usize => 10,
from_isize: isize => 11
}
#[cfg(target_pointer_width = "64")]
from_integers! {
from_usize: usize => 20,
from_isize: isize => 20
}
#[cfg(test)]
mod from_header_name_tests {
use super::*;
use crate::header::map::HeaderMap;
use crate::header::name;
#[test]
fn it_can_insert_header_name_as_header_value() {
let mut map = HeaderMap::new();
map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
map.insert(
name::ACCEPT,
name::HeaderName::from_bytes(b"hello-world").unwrap().into(),
);
assert_eq!(
map.get(name::UPGRADE).unwrap(),
HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
);
assert_eq!(
map.get(name::ACCEPT).unwrap(),
HeaderValue::from_bytes(b"hello-world").unwrap()
);
}
}
impl FromStr for HeaderValue {
type Err = InvalidHeaderValue;
#[inline]
fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
HeaderValue::from_str(s)
}
}
impl<'a> From<&'a HeaderValue> for HeaderValue {
#[inline]
fn from(t: &'a HeaderValue) -> Self {
t.clone()
}
}
impl<'a> TryFrom<&'a str> for HeaderValue {
type Error = InvalidHeaderValue;
#[inline]
fn try_from(t: &'a str) -> Result<Self, Self::Error> {
t.parse()
}
}
impl<'a> TryFrom<&'a String> for HeaderValue {
type Error = InvalidHeaderValue;
#[inline]
fn try_from(s: &'a String) -> Result<Self, Self::Error> {
Self::from_bytes(s.as_bytes())
}
}
impl<'a> TryFrom<&'a [u8]> for HeaderValue {
type Error = InvalidHeaderValue;
#[inline]
fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
HeaderValue::from_bytes(t)
}
}
impl TryFrom<String> for HeaderValue {
type Error = InvalidHeaderValue;
#[inline]
fn try_from(t: String) -> Result<Self, Self::Error> {
HeaderValue::from_shared(t.into())
}
}
impl TryFrom<Vec<u8>> for HeaderValue {
type Error = InvalidHeaderValue;
#[inline]
fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
HeaderValue::from_shared(vec.into())
}
}
#[cfg(test)]
mod try_from_header_name_tests {
use super::*;
use crate::header::name;
#[test]
fn it_converts_using_try_from() {
assert_eq!(
HeaderValue::try_from(name::UPGRADE).unwrap(),
HeaderValue::from_bytes(b"upgrade").unwrap()
);
}
}
const fn is_visible_ascii(b: u8) -> bool {
b >= 32 && b < 127 || b == b'\t'
}
#[inline]
fn is_valid(b: u8) -> bool {
b >= 32 && b != 127 || b == b'\t'
}
impl fmt::Debug for InvalidHeaderValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("InvalidHeaderValue")
// skip _priv noise
.finish()
}
}
impl fmt::Display for InvalidHeaderValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("failed to parse header value")
}
}
impl Error for InvalidHeaderValue {}
impl fmt::Display for ToStrError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("failed to convert header to a str")
}
}
impl Error for ToStrError {}
// ===== PartialEq / PartialOrd =====
impl PartialEq for HeaderValue {
#[inline]
fn eq(&self, other: &HeaderValue) -> bool {
self.inner == other.inner
}
}
impl Eq for HeaderValue {}
impl PartialOrd for HeaderValue {
#[inline]
fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
self.inner.partial_cmp(&other.inner)
}
}
impl Ord for HeaderValue {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.inner.cmp(&other.inner)
}
}
impl PartialEq<str> for HeaderValue {
#[inline]
fn eq(&self, other: &str) -> bool {
self.inner == other.as_bytes()
}
}
impl PartialEq<[u8]> for HeaderValue {
#[inline]
fn eq(&self, other: &[u8]) -> bool {
self.inner == other
}
}
impl PartialOrd<str> for HeaderValue {
#[inline]
fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
(*self.inner).partial_cmp(other.as_bytes())
}
}
impl PartialOrd<[u8]> for HeaderValue {
#[inline]
fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
(*self.inner).partial_cmp(other)
}
}
impl PartialEq<HeaderValue> for str {
#[inline]
fn eq(&self, other: &HeaderValue) -> bool {
*other == *self
}
}
impl PartialEq<HeaderValue> for [u8] {
#[inline]
fn eq(&self, other: &HeaderValue) -> bool {
*other == *self
}
}
impl PartialOrd<HeaderValue> for str {
#[inline]
fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
self.as_bytes().partial_cmp(other.as_bytes())
}
}
impl PartialOrd<HeaderValue> for [u8] {
#[inline]
fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
self.partial_cmp(other.as_bytes())
}
}
impl PartialEq<String> for HeaderValue {
#[inline]
fn eq(&self, other: &String) -> bool {
*self == &other[..]
}
}
impl PartialOrd<String> for HeaderValue {
#[inline]
fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
self.inner.partial_cmp(other.as_bytes())
}
}
impl PartialEq<HeaderValue> for String {
#[inline]
fn eq(&self, other: &HeaderValue) -> bool {
*other == *self
}
}
impl PartialOrd<HeaderValue> for String {
#[inline]
fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
self.as_bytes().partial_cmp(other.as_bytes())
}
}
impl<'a> PartialEq<HeaderValue> for &'a HeaderValue {
#[inline]
fn eq(&self, other: &HeaderValue) -> bool {
**self == *other
}
}
impl<'a> PartialOrd<HeaderValue> for &'a HeaderValue {
#[inline]
fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
(**self).partial_cmp(other)
}
}
impl<'a, T: ?Sized> PartialEq<&'a T> for HeaderValue
where
HeaderValue: PartialEq<T>,
{
#[inline]
fn eq(&self, other: &&'a T) -> bool {
*self == **other
}
}
impl<'a, T: ?Sized> PartialOrd<&'a T> for HeaderValue
where
HeaderValue: PartialOrd<T>,
{
#[inline]
fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
self.partial_cmp(*other)
}
}
impl<'a> PartialEq<HeaderValue> for &'a str {
#[inline]
fn eq(&self, other: &HeaderValue) -> bool {
*other == *self
}
}
impl<'a> PartialOrd<HeaderValue> for &'a str {
#[inline]
fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
self.as_bytes().partial_cmp(other.as_bytes())
}
}
#[test]
fn test_try_from() {
HeaderValue::try_from(vec![127]).unwrap_err();
}
#[test]
fn test_debug() {
let cases = &[
("hello", "\"hello\""),
("hello \"world\"", "\"hello \\\"world\\\"\""),
("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
];
for &(value, expected) in cases {
let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
let actual = format!("{:?}", val);
assert_eq!(expected, actual);
}
let mut sensitive = HeaderValue::from_static("password");
sensitive.set_sensitive(true);
assert_eq!("Sensitive", format!("{:?}", sensitive));
}

211
zeroidc/vendor/http/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,211 @@
#![doc(html_root_url = "https://docs.rs/http/0.2.8")]
//! A general purpose library of common HTTP types
//!
//! This crate is a general purpose library for common types found when working
//! with the HTTP protocol. You'll find `Request` and `Response` types for
//! working as either a client or a server as well as all of their components.
//! Notably you'll find `Uri` for what a `Request` is requesting, a `Method`
//! for how it's being requested, a `StatusCode` for what sort of response came
//! back, a `Version` for how this was communicated, and
//! `HeaderName`/`HeaderValue` definitions to get grouped in a `HeaderMap` to
//! work with request/response headers.
//!
//! You will notably *not* find an implementation of sending requests or
//! spinning up a server in this crate. It's intended that this crate is the
//! "standard library" for HTTP clients and servers without dictating any
//! particular implementation. Note that this crate is still early on in its
//! lifecycle so the support libraries that integrate with the `http` crate are
//! a work in progress! Stay tuned and we'll be sure to highlight crates here
//! in the future.
//!
//! ## Requests and Responses
//!
//! Perhaps the main two types in this crate are the `Request` and `Response`
//! types. A `Request` could either be constructed to get sent off as a client
//! or it can also be received to generate a `Response` for a server. Similarly
//! as a client a `Response` is what you get after sending a `Request`, whereas
//! on a server you'll be manufacturing a `Response` to send back to the client.
//!
//! Each type has a number of accessors for the component fields. For as a
//! server you might want to inspect a requests URI to dispatch it:
//!
//! ```
//! use http::{Request, Response};
//!
//! fn response(req: Request<()>) -> http::Result<Response<()>> {
//! match req.uri().path() {
//! "/" => index(req),
//! "/foo" => foo(req),
//! "/bar" => bar(req),
//! _ => not_found(req),
//! }
//! }
//! # fn index(_req: Request<()>) -> http::Result<Response<()>> { panic!() }
//! # fn foo(_req: Request<()>) -> http::Result<Response<()>> { panic!() }
//! # fn bar(_req: Request<()>) -> http::Result<Response<()>> { panic!() }
//! # fn not_found(_req: Request<()>) -> http::Result<Response<()>> { panic!() }
//! ```
//!
//! On a `Request` you'll also find accessors like `method` to return a
//! `Method` and `headers` to inspect the various headers. A `Response`
//! has similar methods for headers, the status code, etc.
//!
//! In addition to getters, request/response types also have mutable accessors
//! to edit the request/response:
//!
//! ```
//! use http::{HeaderValue, Response, StatusCode};
//! use http::header::CONTENT_TYPE;
//!
//! fn add_server_headers<T>(response: &mut Response<T>) {
//! response.headers_mut()
//! .insert(CONTENT_TYPE, HeaderValue::from_static("text/html"));
//! *response.status_mut() = StatusCode::OK;
//! }
//! ```
//!
//! And finally, one of the most important aspects of requests/responses, the
//! body! The `Request` and `Response` types in this crate are *generic* in
//! what their body is. This allows downstream libraries to use different
//! representations such as `Request<Vec<u8>>`, `Response<impl Read>`,
//! `Request<impl Stream<Item = Vec<u8>, Error = _>>`, or even
//! `Response<MyCustomType>` where the custom type was deserialized from JSON.
//!
//! The body representation is intentionally flexible to give downstream
//! libraries maximal flexibility in implementing the body as appropriate.
//!
//! ## HTTP Headers
//!
//! Another major piece of functionality in this library is HTTP header
//! interpretation and generation. The `HeaderName` type serves as a way to
//! define header *names*, or what's to the left of the colon. A `HeaderValue`
//! conversely is the header *value*, or what's to the right of a colon.
//!
//! For example, if you have an HTTP request that looks like:
//!
//! ```http
//! GET /foo HTTP/1.1
//! Accept: text/html
//! ```
//!
//! Then `"Accept"` is a `HeaderName` while `"text/html"` is a `HeaderValue`.
//! Each of these is a dedicated type to allow for a number of interesting
//! optimizations and to also encode the static guarantees of each type. For
//! example a `HeaderName` is always a valid `&str`, but a `HeaderValue` may
//! not be valid UTF-8.
//!
//! The most common header names are already defined for you as constant values
//! in the `header` module of this crate. For example:
//!
//! ```
//! use http::header::{self, HeaderName};
//!
//! let name: HeaderName = header::ACCEPT;
//! assert_eq!(name.as_str(), "accept");
//! ```
//!
//! You can, however, also parse header names from strings:
//!
//! ```
//! use http::header::{self, HeaderName};
//!
//! let name = "Accept".parse::<HeaderName>().unwrap();
//! assert_eq!(name, header::ACCEPT);
//! ```
//!
//! Header values can be created from string literals through the `from_static`
//! function:
//!
//! ```
//! use http::HeaderValue;
//!
//! let value = HeaderValue::from_static("text/html");
//! assert_eq!(value.as_bytes(), b"text/html");
//! ```
//!
//! And header values can also be parsed like names:
//!
//! ```
//! use http::HeaderValue;
//!
//! let value = "text/html";
//! let value = value.parse::<HeaderValue>().unwrap();
//! ```
//!
//! Most HTTP requests and responses tend to come with more than one header, so
//! it's not too useful to just work with names and values only! This crate also
//! provides a `HeaderMap` type which is a specialized hash map for keys as
//! `HeaderName` and generic values. This type, like header names, is optimized
//! for common usage but should continue to scale with your needs over time.
//!
//! # URIs
//!
//! Each HTTP `Request` has an associated URI with it. This may just be a path
//! like `/index.html` but it could also be an absolute URL such as
//! `https://www.rust-lang.org/index.html`. A `URI` has a number of accessors to
//! interpret it:
//!
//! ```
//! use http::Uri;
//! use http::uri::Scheme;
//!
//! let uri = "https://www.rust-lang.org/index.html".parse::<Uri>().unwrap();
//!
//! assert_eq!(uri.scheme(), Some(&Scheme::HTTPS));
//! assert_eq!(uri.host(), Some("www.rust-lang.org"));
//! assert_eq!(uri.path(), "/index.html");
//! assert_eq!(uri.query(), None);
//! ```
#![deny(warnings, missing_docs, missing_debug_implementations)]
#[cfg(test)]
#[macro_use]
extern crate doc_comment;
#[cfg(test)]
doctest!("../README.md");
#[macro_use]
mod convert;
pub mod header;
pub mod method;
pub mod request;
pub mod response;
pub mod status;
pub mod uri;
pub mod version;
mod byte_str;
mod error;
mod extensions;
pub use crate::error::{Error, Result};
pub use crate::extensions::Extensions;
#[doc(no_inline)]
pub use crate::header::{HeaderMap, HeaderValue};
pub use crate::method::Method;
pub use crate::request::Request;
pub use crate::response::Response;
pub use crate::status::StatusCode;
pub use crate::uri::Uri;
pub use crate::version::Version;
fn _assert_types() {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
assert_send::<Request<()>>();
assert_send::<Response<()>>();
assert_sync::<Request<()>>();
assert_sync::<Response<()>>();
}
mod sealed {
/// Private trait to this crate to prevent traits from being implemented in
/// downstream crates.
pub trait Sealed {}
}

473
zeroidc/vendor/http/src/method.rs vendored Normal file
View File

@@ -0,0 +1,473 @@
//! The HTTP request method
//!
//! This module contains HTTP-method related structs and errors and such. The
//! main type of this module, `Method`, is also reexported at the root of the
//! crate as `http::Method` and is intended for import through that location
//! primarily.
//!
//! # Examples
//!
//! ```
//! use http::Method;
//!
//! assert_eq!(Method::GET, Method::from_bytes(b"GET").unwrap());
//! assert!(Method::GET.is_idempotent());
//! assert_eq!(Method::POST.as_str(), "POST");
//! ```
use self::Inner::*;
use self::extension::{InlineExtension, AllocatedExtension};
use std::convert::AsRef;
use std::error::Error;
use std::str::FromStr;
use std::convert::TryFrom;
use std::{fmt, str};
/// The Request Method (VERB)
///
/// This type also contains constants for a number of common HTTP methods such
/// as GET, POST, etc.
///
/// Currently includes 8 variants representing the 8 methods defined in
/// [RFC 7230](https://tools.ietf.org/html/rfc7231#section-4.1), plus PATCH,
/// and an Extension variant for all extensions.
///
/// # Examples
///
/// ```
/// use http::Method;
///
/// assert_eq!(Method::GET, Method::from_bytes(b"GET").unwrap());
/// assert!(Method::GET.is_idempotent());
/// assert_eq!(Method::POST.as_str(), "POST");
/// ```
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Method(Inner);
/// A possible error value when converting `Method` from bytes.
pub struct InvalidMethod {
_priv: (),
}
#[derive(Clone, PartialEq, Eq, Hash)]
enum Inner {
Options,
Get,
Post,
Put,
Delete,
Head,
Trace,
Connect,
Patch,
// If the extension is short enough, store it inline
ExtensionInline(InlineExtension),
// Otherwise, allocate it
ExtensionAllocated(AllocatedExtension),
}
impl Method {
/// GET
pub const GET: Method = Method(Get);
/// POST
pub const POST: Method = Method(Post);
/// PUT
pub const PUT: Method = Method(Put);
/// DELETE
pub const DELETE: Method = Method(Delete);
/// HEAD
pub const HEAD: Method = Method(Head);
/// OPTIONS
pub const OPTIONS: Method = Method(Options);
/// CONNECT
pub const CONNECT: Method = Method(Connect);
/// PATCH
pub const PATCH: Method = Method(Patch);
/// TRACE
pub const TRACE: Method = Method(Trace);
/// Converts a slice of bytes to an HTTP method.
pub fn from_bytes(src: &[u8]) -> Result<Method, InvalidMethod> {
match src.len() {
0 => Err(InvalidMethod::new()),
3 => match src {
b"GET" => Ok(Method(Get)),
b"PUT" => Ok(Method(Put)),
_ => Method::extension_inline(src),
},
4 => match src {
b"POST" => Ok(Method(Post)),
b"HEAD" => Ok(Method(Head)),
_ => Method::extension_inline(src),
},
5 => match src {
b"PATCH" => Ok(Method(Patch)),
b"TRACE" => Ok(Method(Trace)),
_ => Method::extension_inline(src),
},
6 => match src {
b"DELETE" => Ok(Method(Delete)),
_ => Method::extension_inline(src),
},
7 => match src {
b"OPTIONS" => Ok(Method(Options)),
b"CONNECT" => Ok(Method(Connect)),
_ => Method::extension_inline(src),
},
_ => {
if src.len() < InlineExtension::MAX {
Method::extension_inline(src)
} else {
let allocated = AllocatedExtension::new(src)?;
Ok(Method(ExtensionAllocated(allocated)))
}
}
}
}
fn extension_inline(src: &[u8]) -> Result<Method, InvalidMethod> {
let inline = InlineExtension::new(src)?;
Ok(Method(ExtensionInline(inline)))
}
/// Whether a method is considered "safe", meaning the request is
/// essentially read-only.
///
/// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.1)
/// for more words.
pub fn is_safe(&self) -> bool {
match self.0 {
Get | Head | Options | Trace => true,
_ => false,
}
}
/// Whether a method is considered "idempotent", meaning the request has
/// the same result if executed multiple times.
///
/// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.2) for
/// more words.
pub fn is_idempotent(&self) -> bool {
match self.0 {
Put | Delete => true,
_ => self.is_safe(),
}
}
/// Return a &str representation of the HTTP method
#[inline]
pub fn as_str(&self) -> &str {
match self.0 {
Options => "OPTIONS",
Get => "GET",
Post => "POST",
Put => "PUT",
Delete => "DELETE",
Head => "HEAD",
Trace => "TRACE",
Connect => "CONNECT",
Patch => "PATCH",
ExtensionInline(ref inline) => inline.as_str(),
ExtensionAllocated(ref allocated) => allocated.as_str(),
}
}
}
impl AsRef<str> for Method {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<'a> PartialEq<&'a Method> for Method {
#[inline]
fn eq(&self, other: &&'a Method) -> bool {
self == *other
}
}
impl<'a> PartialEq<Method> for &'a Method {
#[inline]
fn eq(&self, other: &Method) -> bool {
*self == other
}
}
impl PartialEq<str> for Method {
#[inline]
fn eq(&self, other: &str) -> bool {
self.as_ref() == other
}
}
impl PartialEq<Method> for str {
#[inline]
fn eq(&self, other: &Method) -> bool {
self == other.as_ref()
}
}
impl<'a> PartialEq<&'a str> for Method {
#[inline]
fn eq(&self, other: &&'a str) -> bool {
self.as_ref() == *other
}
}
impl<'a> PartialEq<Method> for &'a str {
#[inline]
fn eq(&self, other: &Method) -> bool {
*self == other.as_ref()
}
}
impl fmt::Debug for Method {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_ref())
}
}
impl fmt::Display for Method {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str(self.as_ref())
}
}
impl Default for Method {
#[inline]
fn default() -> Method {
Method::GET
}
}
impl<'a> From<&'a Method> for Method {
#[inline]
fn from(t: &'a Method) -> Self {
t.clone()
}
}
impl<'a> TryFrom<&'a [u8]> for Method {
type Error = InvalidMethod;
#[inline]
fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
Method::from_bytes(t)
}
}
impl<'a> TryFrom<&'a str> for Method {
type Error = InvalidMethod;
#[inline]
fn try_from(t: &'a str) -> Result<Self, Self::Error> {
TryFrom::try_from(t.as_bytes())
}
}
impl FromStr for Method {
type Err = InvalidMethod;
#[inline]
fn from_str(t: &str) -> Result<Self, Self::Err> {
TryFrom::try_from(t)
}
}
impl InvalidMethod {
fn new() -> InvalidMethod {
InvalidMethod { _priv: () }
}
}
impl fmt::Debug for InvalidMethod {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("InvalidMethod")
// skip _priv noise
.finish()
}
}
impl fmt::Display for InvalidMethod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("invalid HTTP method")
}
}
impl Error for InvalidMethod {}
mod extension {
use super::InvalidMethod;
use std::str;
#[derive(Clone, PartialEq, Eq, Hash)]
// Invariant: the first self.1 bytes of self.0 are valid UTF-8.
pub struct InlineExtension([u8; InlineExtension::MAX], u8);
#[derive(Clone, PartialEq, Eq, Hash)]
// Invariant: self.0 contains valid UTF-8.
pub struct AllocatedExtension(Box<[u8]>);
impl InlineExtension {
// Method::from_bytes() assumes this is at least 7
pub const MAX: usize = 15;
pub fn new(src: &[u8]) -> Result<InlineExtension, InvalidMethod> {
let mut data: [u8; InlineExtension::MAX] = Default::default();
write_checked(src, &mut data)?;
// Invariant: write_checked ensures that the first src.len() bytes
// of data are valid UTF-8.
Ok(InlineExtension(data, src.len() as u8))
}
pub fn as_str(&self) -> &str {
let InlineExtension(ref data, len) = self;
// Safety: the invariant of InlineExtension ensures that the first
// len bytes of data contain valid UTF-8.
unsafe {str::from_utf8_unchecked(&data[..*len as usize])}
}
}
impl AllocatedExtension {
pub fn new(src: &[u8]) -> Result<AllocatedExtension, InvalidMethod> {
let mut data: Vec<u8> = vec![0; src.len()];
write_checked(src, &mut data)?;
// Invariant: data is exactly src.len() long and write_checked
// ensures that the first src.len() bytes of data are valid UTF-8.
Ok(AllocatedExtension(data.into_boxed_slice()))
}
pub fn as_str(&self) -> &str {
// Safety: the invariant of AllocatedExtension ensures that self.0
// contains valid UTF-8.
unsafe {str::from_utf8_unchecked(&self.0)}
}
}
// From the HTTP spec section 5.1.1, the HTTP method is case-sensitive and can
// contain the following characters:
//
// ```
// method = token
// token = 1*tchar
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
// ```
//
// https://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01#Method
//
// Note that this definition means that any &[u8] that consists solely of valid
// characters is also valid UTF-8 because the valid method characters are a
// subset of the valid 1 byte UTF-8 encoding.
const METHOD_CHARS: [u8; 256] = [
// 0 1 2 3 4 5 6 7 8 9
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 1x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 2x
b'\0', b'\0', b'\0', b'!', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 3x
b'\0', b'\0', b'*', b'+', b'\0', b'-', b'.', b'\0', b'0', b'1', // 4x
b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'\0', b'\0', // 5x
b'\0', b'\0', b'\0', b'\0', b'\0', b'A', b'B', b'C', b'D', b'E', // 6x
b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', // 7x
b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', // 8x
b'Z', b'\0', b'\0', b'\0', b'^', b'_', b'`', b'a', b'b', b'c', // 9x
b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', // 10x
b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', // 11x
b'x', b'y', b'z', b'\0', b'|', b'\0', b'~', b'\0', b'\0', b'\0', // 12x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 13x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 14x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 15x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 16x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 17x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 18x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 19x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 20x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 21x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 22x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 23x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 24x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0' // 25x
];
// write_checked ensures (among other things) that the first src.len() bytes
// of dst are valid UTF-8
fn write_checked(src: &[u8], dst: &mut [u8]) -> Result<(), InvalidMethod> {
for (i, &b) in src.iter().enumerate() {
let b = METHOD_CHARS[b as usize];
if b == 0 {
return Err(InvalidMethod::new());
}
dst[i] = b;
}
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_method_eq() {
assert_eq!(Method::GET, Method::GET);
assert_eq!(Method::GET, "GET");
assert_eq!(&Method::GET, "GET");
assert_eq!("GET", Method::GET);
assert_eq!("GET", &Method::GET);
assert_eq!(&Method::GET, Method::GET);
assert_eq!(Method::GET, &Method::GET);
}
#[test]
fn test_invalid_method() {
assert!(Method::from_str("").is_err());
assert!(Method::from_bytes(b"").is_err());
assert!(Method::from_bytes(&[0xC0]).is_err()); // invalid utf-8
assert!(Method::from_bytes(&[0x10]).is_err()); // invalid method characters
}
#[test]
fn test_is_idempotent() {
assert!(Method::OPTIONS.is_idempotent());
assert!(Method::GET.is_idempotent());
assert!(Method::PUT.is_idempotent());
assert!(Method::DELETE.is_idempotent());
assert!(Method::HEAD.is_idempotent());
assert!(Method::TRACE.is_idempotent());
assert!(!Method::POST.is_idempotent());
assert!(!Method::CONNECT.is_idempotent());
assert!(!Method::PATCH.is_idempotent());
}
#[test]
fn test_extention_method() {
assert_eq!(Method::from_str("WOW").unwrap(), "WOW");
assert_eq!(Method::from_str("wOw!!").unwrap(), "wOw!!");
let long_method = "This_is_a_very_long_method.It_is_valid_but_unlikely.";
assert_eq!(Method::from_str(&long_method).unwrap(), long_method);
}
}

1096
zeroidc/vendor/http/src/request.rs vendored Normal file

File diff suppressed because it is too large Load Diff

799
zeroidc/vendor/http/src/response.rs vendored Normal file
View File

@@ -0,0 +1,799 @@
//! HTTP response types.
//!
//! This module contains structs related to HTTP responses, notably the
//! `Response` type itself as well as a builder to create responses. Typically
//! you'll import the `http::Response` type rather than reaching into this
//! module itself.
//!
//! # Examples
//!
//! Creating a `Response` to return
//!
//! ```
//! use http::{Request, Response, StatusCode};
//!
//! fn respond_to(req: Request<()>) -> http::Result<Response<()>> {
//! let mut builder = Response::builder()
//! .header("Foo", "Bar")
//! .status(StatusCode::OK);
//!
//! if req.headers().contains_key("Another-Header") {
//! builder = builder.header("Another-Header", "Ack");
//! }
//!
//! builder.body(())
//! }
//! ```
//!
//! A simple 404 handler
//!
//! ```
//! use http::{Request, Response, StatusCode};
//!
//! fn not_found(_req: Request<()>) -> http::Result<Response<()>> {
//! Response::builder()
//! .status(StatusCode::NOT_FOUND)
//! .body(())
//! }
//! ```
//!
//! Or otherwise inspecting the result of a request:
//!
//! ```no_run
//! use http::{Request, Response};
//!
//! fn get(url: &str) -> http::Result<Response<()>> {
//! // ...
//! # panic!()
//! }
//!
//! let response = get("https://www.rust-lang.org/").unwrap();
//!
//! if !response.status().is_success() {
//! panic!("failed to get a successful response status!");
//! }
//!
//! if let Some(date) = response.headers().get("Date") {
//! // we've got a `Date` header!
//! }
//!
//! let body = response.body();
//! // ...
//! ```
use std::any::Any;
use std::convert::TryFrom;
use std::fmt;
use crate::header::{HeaderMap, HeaderName, HeaderValue};
use crate::status::StatusCode;
use crate::version::Version;
use crate::{Extensions, Result};
/// Represents an HTTP response
///
/// An HTTP response consists of a head and a potentially optional body. The body
/// component is generic, enabling arbitrary types to represent the HTTP body.
/// For example, the body could be `Vec<u8>`, a `Stream` of byte chunks, or a
/// value that has been deserialized.
///
/// Typically you'll work with responses on the client side as the result of
/// sending a `Request` and on the server you'll be generating a `Response` to
/// send back to the client.
///
/// # Examples
///
/// Creating a `Response` to return
///
/// ```
/// use http::{Request, Response, StatusCode};
///
/// fn respond_to(req: Request<()>) -> http::Result<Response<()>> {
/// let mut builder = Response::builder()
/// .header("Foo", "Bar")
/// .status(StatusCode::OK);
///
/// if req.headers().contains_key("Another-Header") {
/// builder = builder.header("Another-Header", "Ack");
/// }
///
/// builder.body(())
/// }
/// ```
///
/// A simple 404 handler
///
/// ```
/// use http::{Request, Response, StatusCode};
///
/// fn not_found(_req: Request<()>) -> http::Result<Response<()>> {
/// Response::builder()
/// .status(StatusCode::NOT_FOUND)
/// .body(())
/// }
/// ```
///
/// Or otherwise inspecting the result of a request:
///
/// ```no_run
/// use http::{Request, Response};
///
/// fn get(url: &str) -> http::Result<Response<()>> {
/// // ...
/// # panic!()
/// }
///
/// let response = get("https://www.rust-lang.org/").unwrap();
///
/// if !response.status().is_success() {
/// panic!("failed to get a successful response status!");
/// }
///
/// if let Some(date) = response.headers().get("Date") {
/// // we've got a `Date` header!
/// }
///
/// let body = response.body();
/// // ...
/// ```
///
/// Deserialize a response of bytes via json:
///
/// ```
/// # extern crate serde;
/// # extern crate serde_json;
/// # extern crate http;
/// use http::Response;
/// use serde::de;
///
/// fn deserialize<T>(res: Response<Vec<u8>>) -> serde_json::Result<Response<T>>
/// where for<'de> T: de::Deserialize<'de>,
/// {
/// let (parts, body) = res.into_parts();
/// let body = serde_json::from_slice(&body)?;
/// Ok(Response::from_parts(parts, body))
/// }
/// #
/// # fn main() {}
/// ```
///
/// Or alternatively, serialize the body of a response to json
///
/// ```
/// # extern crate serde;
/// # extern crate serde_json;
/// # extern crate http;
/// use http::Response;
/// use serde::ser;
///
/// fn serialize<T>(res: Response<T>) -> serde_json::Result<Response<Vec<u8>>>
/// where T: ser::Serialize,
/// {
/// let (parts, body) = res.into_parts();
/// let body = serde_json::to_vec(&body)?;
/// Ok(Response::from_parts(parts, body))
/// }
/// #
/// # fn main() {}
/// ```
pub struct Response<T> {
head: Parts,
body: T,
}
/// Component parts of an HTTP `Response`
///
/// The HTTP response head consists of a status, version, and a set of
/// header fields.
pub struct Parts {
/// The response's status
pub status: StatusCode,
/// The response's version
pub version: Version,
/// The response's headers
pub headers: HeaderMap<HeaderValue>,
/// The response's extensions
pub extensions: Extensions,
_priv: (),
}
/// An HTTP response builder
///
/// This type can be used to construct an instance of `Response` through a
/// builder-like pattern.
#[derive(Debug)]
pub struct Builder {
inner: Result<Parts>,
}
impl Response<()> {
/// Creates a new builder-style object to manufacture a `Response`
///
/// This method returns an instance of `Builder` which can be used to
/// create a `Response`.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response = Response::builder()
/// .status(200)
/// .header("X-Custom-Foo", "Bar")
/// .body(())
/// .unwrap();
/// ```
#[inline]
pub fn builder() -> Builder {
Builder::new()
}
}
impl<T> Response<T> {
/// Creates a new blank `Response` with the body
///
/// The component ports of this response will be set to their default, e.g.
/// the ok status, no headers, etc.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response = Response::new("hello world");
///
/// assert_eq!(response.status(), StatusCode::OK);
/// assert_eq!(*response.body(), "hello world");
/// ```
#[inline]
pub fn new(body: T) -> Response<T> {
Response {
head: Parts::new(),
body: body,
}
}
/// Creates a new `Response` with the given head and body
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response = Response::new("hello world");
/// let (mut parts, body) = response.into_parts();
///
/// parts.status = StatusCode::BAD_REQUEST;
/// let response = Response::from_parts(parts, body);
///
/// assert_eq!(response.status(), StatusCode::BAD_REQUEST);
/// assert_eq!(*response.body(), "hello world");
/// ```
#[inline]
pub fn from_parts(parts: Parts, body: T) -> Response<T> {
Response {
head: parts,
body: body,
}
}
/// Returns the `StatusCode`.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response: Response<()> = Response::default();
/// assert_eq!(response.status(), StatusCode::OK);
/// ```
#[inline]
pub fn status(&self) -> StatusCode {
self.head.status
}
/// Returns a mutable reference to the associated `StatusCode`.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let mut response: Response<()> = Response::default();
/// *response.status_mut() = StatusCode::CREATED;
/// assert_eq!(response.status(), StatusCode::CREATED);
/// ```
#[inline]
pub fn status_mut(&mut self) -> &mut StatusCode {
&mut self.head.status
}
/// Returns a reference to the associated version.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response: Response<()> = Response::default();
/// assert_eq!(response.version(), Version::HTTP_11);
/// ```
#[inline]
pub fn version(&self) -> Version {
self.head.version
}
/// Returns a mutable reference to the associated version.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let mut response: Response<()> = Response::default();
/// *response.version_mut() = Version::HTTP_2;
/// assert_eq!(response.version(), Version::HTTP_2);
/// ```
#[inline]
pub fn version_mut(&mut self) -> &mut Version {
&mut self.head.version
}
/// Returns a reference to the associated header field map.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response: Response<()> = Response::default();
/// assert!(response.headers().is_empty());
/// ```
#[inline]
pub fn headers(&self) -> &HeaderMap<HeaderValue> {
&self.head.headers
}
/// Returns a mutable reference to the associated header field map.
///
/// # Examples
///
/// ```
/// # use http::*;
/// # use http::header::*;
/// let mut response: Response<()> = Response::default();
/// response.headers_mut().insert(HOST, HeaderValue::from_static("world"));
/// assert!(!response.headers().is_empty());
/// ```
#[inline]
pub fn headers_mut(&mut self) -> &mut HeaderMap<HeaderValue> {
&mut self.head.headers
}
/// Returns a reference to the associated extensions.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response: Response<()> = Response::default();
/// assert!(response.extensions().get::<i32>().is_none());
/// ```
#[inline]
pub fn extensions(&self) -> &Extensions {
&self.head.extensions
}
/// Returns a mutable reference to the associated extensions.
///
/// # Examples
///
/// ```
/// # use http::*;
/// # use http::header::*;
/// let mut response: Response<()> = Response::default();
/// response.extensions_mut().insert("hello");
/// assert_eq!(response.extensions().get(), Some(&"hello"));
/// ```
#[inline]
pub fn extensions_mut(&mut self) -> &mut Extensions {
&mut self.head.extensions
}
/// Returns a reference to the associated HTTP body.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response: Response<String> = Response::default();
/// assert!(response.body().is_empty());
/// ```
#[inline]
pub fn body(&self) -> &T {
&self.body
}
/// Returns a mutable reference to the associated HTTP body.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let mut response: Response<String> = Response::default();
/// response.body_mut().push_str("hello world");
/// assert!(!response.body().is_empty());
/// ```
#[inline]
pub fn body_mut(&mut self) -> &mut T {
&mut self.body
}
/// Consumes the response, returning just the body.
///
/// # Examples
///
/// ```
/// # use http::Response;
/// let response = Response::new(10);
/// let body = response.into_body();
/// assert_eq!(body, 10);
/// ```
#[inline]
pub fn into_body(self) -> T {
self.body
}
/// Consumes the response returning the head and body parts.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response: Response<()> = Response::default();
/// let (parts, body) = response.into_parts();
/// assert_eq!(parts.status, StatusCode::OK);
/// ```
#[inline]
pub fn into_parts(self) -> (Parts, T) {
(self.head, self.body)
}
/// Consumes the response returning a new response with body mapped to the
/// return type of the passed in function.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response = Response::builder().body("some string").unwrap();
/// let mapped_response: Response<&[u8]> = response.map(|b| {
/// assert_eq!(b, "some string");
/// b.as_bytes()
/// });
/// assert_eq!(mapped_response.body(), &"some string".as_bytes());
/// ```
#[inline]
pub fn map<F, U>(self, f: F) -> Response<U>
where
F: FnOnce(T) -> U,
{
Response {
body: f(self.body),
head: self.head,
}
}
}
impl<T: Default> Default for Response<T> {
#[inline]
fn default() -> Response<T> {
Response::new(T::default())
}
}
impl<T: fmt::Debug> fmt::Debug for Response<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Response")
.field("status", &self.status())
.field("version", &self.version())
.field("headers", self.headers())
// omits Extensions because not useful
.field("body", self.body())
.finish()
}
}
impl Parts {
/// Creates a new default instance of `Parts`
fn new() -> Parts {
Parts {
status: StatusCode::default(),
version: Version::default(),
headers: HeaderMap::default(),
extensions: Extensions::default(),
_priv: (),
}
}
}
impl fmt::Debug for Parts {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Parts")
.field("status", &self.status)
.field("version", &self.version)
.field("headers", &self.headers)
// omits Extensions because not useful
// omits _priv because not useful
.finish()
}
}
impl Builder {
/// Creates a new default instance of `Builder` to construct either a
/// `Head` or a `Response`.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let response = response::Builder::new()
/// .status(200)
/// .body(())
/// .unwrap();
/// ```
#[inline]
pub fn new() -> Builder {
Builder::default()
}
/// Set the HTTP status for this response.
///
/// This function will configure the HTTP status code of the `Response` that
/// will be returned from `Builder::build`.
///
/// By default this is `200`.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let response = Response::builder()
/// .status(200)
/// .body(())
/// .unwrap();
/// ```
pub fn status<T>(self, status: T) -> Builder
where
StatusCode: TryFrom<T>,
<StatusCode as TryFrom<T>>::Error: Into<crate::Error>,
{
self.and_then(move |mut head| {
head.status = TryFrom::try_from(status).map_err(Into::into)?;
Ok(head)
})
}
/// Set the HTTP version for this response.
///
/// This function will configure the HTTP version of the `Response` that
/// will be returned from `Builder::build`.
///
/// By default this is HTTP/1.1
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let response = Response::builder()
/// .version(Version::HTTP_2)
/// .body(())
/// .unwrap();
/// ```
pub fn version(self, version: Version) -> Builder {
self.and_then(move |mut head| {
head.version = version;
Ok(head)
})
}
/// Appends a header to this response builder.
///
/// This function will append the provided key/value as a header to the
/// internal `HeaderMap` being constructed. Essentially this is equivalent
/// to calling `HeaderMap::append`.
///
/// # Examples
///
/// ```
/// # use http::*;
/// # use http::header::HeaderValue;
///
/// let response = Response::builder()
/// .header("Content-Type", "text/html")
/// .header("X-Custom-Foo", "bar")
/// .header("content-length", 0)
/// .body(())
/// .unwrap();
/// ```
pub fn header<K, V>(self, key: K, value: V) -> Builder
where
HeaderName: TryFrom<K>,
<HeaderName as TryFrom<K>>::Error: Into<crate::Error>,
HeaderValue: TryFrom<V>,
<HeaderValue as TryFrom<V>>::Error: Into<crate::Error>,
{
self.and_then(move |mut head| {
let name = <HeaderName as TryFrom<K>>::try_from(key).map_err(Into::into)?;
let value = <HeaderValue as TryFrom<V>>::try_from(value).map_err(Into::into)?;
head.headers.append(name, value);
Ok(head)
})
}
/// Get header on this response builder.
///
/// When builder has error returns None.
///
/// # Example
///
/// ```
/// # use http::Response;
/// # use http::header::HeaderValue;
/// let res = Response::builder()
/// .header("Accept", "text/html")
/// .header("X-Custom-Foo", "bar");
/// let headers = res.headers_ref().unwrap();
/// assert_eq!( headers["Accept"], "text/html" );
/// assert_eq!( headers["X-Custom-Foo"], "bar" );
/// ```
pub fn headers_ref(&self) -> Option<&HeaderMap<HeaderValue>> {
self.inner.as_ref().ok().map(|h| &h.headers)
}
/// Get header on this response builder.
/// when builder has error returns None
///
/// # Example
///
/// ```
/// # use http::*;
/// # use http::header::HeaderValue;
/// # use http::response::Builder;
/// let mut res = Response::builder();
/// {
/// let headers = res.headers_mut().unwrap();
/// headers.insert("Accept", HeaderValue::from_static("text/html"));
/// headers.insert("X-Custom-Foo", HeaderValue::from_static("bar"));
/// }
/// let headers = res.headers_ref().unwrap();
/// assert_eq!( headers["Accept"], "text/html" );
/// assert_eq!( headers["X-Custom-Foo"], "bar" );
/// ```
pub fn headers_mut(&mut self) -> Option<&mut HeaderMap<HeaderValue>> {
self.inner.as_mut().ok().map(|h| &mut h.headers)
}
/// Adds an extension to this builder
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let response = Response::builder()
/// .extension("My Extension")
/// .body(())
/// .unwrap();
///
/// assert_eq!(response.extensions().get::<&'static str>(),
/// Some(&"My Extension"));
/// ```
pub fn extension<T>(self, extension: T) -> Builder
where
T: Any + Send + Sync + 'static,
{
self.and_then(move |mut head| {
head.extensions.insert(extension);
Ok(head)
})
}
/// Get a reference to the extensions for this response builder.
///
/// If the builder has an error, this returns `None`.
///
/// # Example
///
/// ```
/// # use http::Response;
/// let res = Response::builder().extension("My Extension").extension(5u32);
/// let extensions = res.extensions_ref().unwrap();
/// assert_eq!(extensions.get::<&'static str>(), Some(&"My Extension"));
/// assert_eq!(extensions.get::<u32>(), Some(&5u32));
/// ```
pub fn extensions_ref(&self) -> Option<&Extensions> {
self.inner.as_ref().ok().map(|h| &h.extensions)
}
/// Get a mutable reference to the extensions for this response builder.
///
/// If the builder has an error, this returns `None`.
///
/// # Example
///
/// ```
/// # use http::Response;
/// let mut res = Response::builder().extension("My Extension");
/// let mut extensions = res.extensions_mut().unwrap();
/// assert_eq!(extensions.get::<&'static str>(), Some(&"My Extension"));
/// extensions.insert(5u32);
/// assert_eq!(extensions.get::<u32>(), Some(&5u32));
/// ```
pub fn extensions_mut(&mut self) -> Option<&mut Extensions> {
self.inner.as_mut().ok().map(|h| &mut h.extensions)
}
/// "Consumes" this builder, using the provided `body` to return a
/// constructed `Response`.
///
/// # Errors
///
/// This function may return an error if any previously configured argument
/// failed to parse or get converted to the internal representation. For
/// example if an invalid `head` was specified via `header("Foo",
/// "Bar\r\n")` the error will be returned when this function is called
/// rather than when `header` was called.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let response = Response::builder()
/// .body(())
/// .unwrap();
/// ```
pub fn body<T>(self, body: T) -> Result<Response<T>> {
self.inner.map(move |head| {
Response {
head,
body,
}
})
}
// private
fn and_then<F>(self, func: F) -> Self
where
F: FnOnce(Parts) -> Result<Parts>
{
Builder {
inner: self.inner.and_then(func),
}
}
}
impl Default for Builder {
#[inline]
fn default() -> Builder {
Builder {
inner: Ok(Parts::new()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_can_map_a_body_from_one_type_to_another() {
let response = Response::builder().body("some string").unwrap();
let mapped_response = response.map(|s| {
assert_eq!(s, "some string");
123u32
});
assert_eq!(mapped_response.body(), &123u32);
}
}

588
zeroidc/vendor/http/src/status.rs vendored Normal file
View File

@@ -0,0 +1,588 @@
//! HTTP status codes
//!
//! This module contains HTTP-status code related structs an errors. The main
//! type in this module is `StatusCode` which is not intended to be used through
//! this module but rather the `http::StatusCode` type.
//!
//! # Examples
//!
//! ```
//! use http::StatusCode;
//!
//! assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK);
//! assert_eq!(StatusCode::NOT_FOUND, 404);
//! assert!(StatusCode::OK.is_success());
//! ```
use std::convert::TryFrom;
use std::num::NonZeroU16;
use std::error::Error;
use std::fmt;
use std::str::FromStr;
/// An HTTP status code (`status-code` in RFC 7230 et al.).
///
/// Constants are provided for known status codes, including those in the IANA
/// [HTTP Status Code Registry](
/// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml).
///
/// Status code values in the range 100-999 (inclusive) are supported by this
/// type. Values in the range 100-599 are semantically classified by the most
/// significant digit. See [`StatusCode::is_success`], etc. Values above 599
/// are unclassified but allowed for legacy compatibility, though their use is
/// discouraged. Applications may interpret such values as protocol errors.
///
/// # Examples
///
/// ```
/// use http::StatusCode;
///
/// assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK);
/// assert_eq!(StatusCode::NOT_FOUND.as_u16(), 404);
/// assert!(StatusCode::OK.is_success());
/// ```
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StatusCode(NonZeroU16);
/// A possible error value when converting a `StatusCode` from a `u16` or `&str`
///
/// This error indicates that the supplied input was not a valid number, was less
/// than 100, or was greater than 999.
pub struct InvalidStatusCode {
_priv: (),
}
impl StatusCode {
/// Converts a u16 to a status code.
///
/// The function validates the correctness of the supplied u16. It must be
/// greater or equal to 100 and less than 1000.
///
/// # Example
///
/// ```
/// use http::StatusCode;
///
/// let ok = StatusCode::from_u16(200).unwrap();
/// assert_eq!(ok, StatusCode::OK);
///
/// let err = StatusCode::from_u16(99);
/// assert!(err.is_err());
/// ```
#[inline]
pub fn from_u16(src: u16) -> Result<StatusCode, InvalidStatusCode> {
if src < 100 || src >= 1000 {
return Err(InvalidStatusCode::new());
}
NonZeroU16::new(src)
.map(StatusCode)
.ok_or_else(InvalidStatusCode::new)
}
/// Converts a &[u8] to a status code
pub fn from_bytes(src: &[u8]) -> Result<StatusCode, InvalidStatusCode> {
if src.len() != 3 {
return Err(InvalidStatusCode::new());
}
let a = src[0].wrapping_sub(b'0') as u16;
let b = src[1].wrapping_sub(b'0') as u16;
let c = src[2].wrapping_sub(b'0') as u16;
if a == 0 || a > 9 || b > 9 || c > 9 {
return Err(InvalidStatusCode::new());
}
let status = (a * 100) + (b * 10) + c;
NonZeroU16::new(status)
.map(StatusCode)
.ok_or_else(InvalidStatusCode::new)
}
/// Returns the `u16` corresponding to this `StatusCode`.
///
/// # Note
///
/// This is the same as the `From<StatusCode>` implementation, but
/// included as an inherent method because that implementation doesn't
/// appear in rustdocs, as well as a way to force the type instead of
/// relying on inference.
///
/// # Example
///
/// ```
/// let status = http::StatusCode::OK;
/// assert_eq!(status.as_u16(), 200);
/// ```
#[inline]
pub fn as_u16(&self) -> u16 {
(*self).into()
}
/// Returns a &str representation of the `StatusCode`
///
/// The return value only includes a numerical representation of the
/// status code. The canonical reason is not included.
///
/// # Example
///
/// ```
/// let status = http::StatusCode::OK;
/// assert_eq!(status.as_str(), "200");
/// ```
#[inline]
pub fn as_str(&self) -> &str {
let offset = (self.0.get() - 100) as usize;
let offset = offset * 3;
// Invariant: self has checked range [100, 999] and CODE_DIGITS is
// ASCII-only, of length 900 * 3 = 2700 bytes
#[cfg(debug_assertions)]
{ &CODE_DIGITS[offset..offset+3] }
#[cfg(not(debug_assertions))]
unsafe { CODE_DIGITS.get_unchecked(offset..offset+3) }
}
/// Get the standardised `reason-phrase` for this status code.
///
/// This is mostly here for servers writing responses, but could potentially have application
/// at other times.
///
/// The reason phrase is defined as being exclusively for human readers. You should avoid
/// deriving any meaning from it at all costs.
///
/// Bear in mind also that in HTTP/2.0 and HTTP/3.0 the reason phrase is abolished from
/// transmission, and so this canonical reason phrase really is the only reason phrase youll
/// find.
///
/// # Example
///
/// ```
/// let status = http::StatusCode::OK;
/// assert_eq!(status.canonical_reason(), Some("OK"));
/// ```
pub fn canonical_reason(&self) -> Option<&'static str> {
canonical_reason(self.0.get())
}
/// Check if status is within 100-199.
#[inline]
pub fn is_informational(&self) -> bool {
200 > self.0.get() && self.0.get() >= 100
}
/// Check if status is within 200-299.
#[inline]
pub fn is_success(&self) -> bool {
300 > self.0.get() && self.0.get() >= 200
}
/// Check if status is within 300-399.
#[inline]
pub fn is_redirection(&self) -> bool {
400 > self.0.get() && self.0.get() >= 300
}
/// Check if status is within 400-499.
#[inline]
pub fn is_client_error(&self) -> bool {
500 > self.0.get() && self.0.get() >= 400
}
/// Check if status is within 500-599.
#[inline]
pub fn is_server_error(&self) -> bool {
600 > self.0.get() && self.0.get() >= 500
}
}
impl fmt::Debug for StatusCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
/// Formats the status code, *including* the canonical reason.
///
/// # Example
///
/// ```
/// # use http::StatusCode;
/// assert_eq!(format!("{}", StatusCode::OK), "200 OK");
/// ```
impl fmt::Display for StatusCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} {}",
u16::from(*self),
self.canonical_reason().unwrap_or("<unknown status code>")
)
}
}
impl Default for StatusCode {
#[inline]
fn default() -> StatusCode {
StatusCode::OK
}
}
impl PartialEq<u16> for StatusCode {
#[inline]
fn eq(&self, other: &u16) -> bool {
self.as_u16() == *other
}
}
impl PartialEq<StatusCode> for u16 {
#[inline]
fn eq(&self, other: &StatusCode) -> bool {
*self == other.as_u16()
}
}
impl From<StatusCode> for u16 {
#[inline]
fn from(status: StatusCode) -> u16 {
status.0.get()
}
}
impl FromStr for StatusCode {
type Err = InvalidStatusCode;
fn from_str(s: &str) -> Result<StatusCode, InvalidStatusCode> {
StatusCode::from_bytes(s.as_ref())
}
}
impl<'a> From<&'a StatusCode> for StatusCode {
#[inline]
fn from(t: &'a StatusCode) -> Self {
t.clone()
}
}
impl<'a> TryFrom<&'a [u8]> for StatusCode {
type Error = InvalidStatusCode;
#[inline]
fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
StatusCode::from_bytes(t)
}
}
impl<'a> TryFrom<&'a str> for StatusCode {
type Error = InvalidStatusCode;
#[inline]
fn try_from(t: &'a str) -> Result<Self, Self::Error> {
t.parse()
}
}
impl TryFrom<u16> for StatusCode {
type Error = InvalidStatusCode;
#[inline]
fn try_from(t: u16) -> Result<Self, Self::Error> {
StatusCode::from_u16(t)
}
}
macro_rules! status_codes {
(
$(
$(#[$docs:meta])*
($num:expr, $konst:ident, $phrase:expr);
)+
) => {
impl StatusCode {
$(
$(#[$docs])*
pub const $konst: StatusCode = StatusCode(unsafe { NonZeroU16::new_unchecked($num) });
)+
}
fn canonical_reason(num: u16) -> Option<&'static str> {
match num {
$(
$num => Some($phrase),
)+
_ => None
}
}
}
}
status_codes! {
/// 100 Continue
/// [[RFC7231, Section 6.2.1](https://tools.ietf.org/html/rfc7231#section-6.2.1)]
(100, CONTINUE, "Continue");
/// 101 Switching Protocols
/// [[RFC7231, Section 6.2.2](https://tools.ietf.org/html/rfc7231#section-6.2.2)]
(101, SWITCHING_PROTOCOLS, "Switching Protocols");
/// 102 Processing
/// [[RFC2518](https://tools.ietf.org/html/rfc2518)]
(102, PROCESSING, "Processing");
/// 200 OK
/// [[RFC7231, Section 6.3.1](https://tools.ietf.org/html/rfc7231#section-6.3.1)]
(200, OK, "OK");
/// 201 Created
/// [[RFC7231, Section 6.3.2](https://tools.ietf.org/html/rfc7231#section-6.3.2)]
(201, CREATED, "Created");
/// 202 Accepted
/// [[RFC7231, Section 6.3.3](https://tools.ietf.org/html/rfc7231#section-6.3.3)]
(202, ACCEPTED, "Accepted");
/// 203 Non-Authoritative Information
/// [[RFC7231, Section 6.3.4](https://tools.ietf.org/html/rfc7231#section-6.3.4)]
(203, NON_AUTHORITATIVE_INFORMATION, "Non Authoritative Information");
/// 204 No Content
/// [[RFC7231, Section 6.3.5](https://tools.ietf.org/html/rfc7231#section-6.3.5)]
(204, NO_CONTENT, "No Content");
/// 205 Reset Content
/// [[RFC7231, Section 6.3.6](https://tools.ietf.org/html/rfc7231#section-6.3.6)]
(205, RESET_CONTENT, "Reset Content");
/// 206 Partial Content
/// [[RFC7233, Section 4.1](https://tools.ietf.org/html/rfc7233#section-4.1)]
(206, PARTIAL_CONTENT, "Partial Content");
/// 207 Multi-Status
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(207, MULTI_STATUS, "Multi-Status");
/// 208 Already Reported
/// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
(208, ALREADY_REPORTED, "Already Reported");
/// 226 IM Used
/// [[RFC3229](https://tools.ietf.org/html/rfc3229)]
(226, IM_USED, "IM Used");
/// 300 Multiple Choices
/// [[RFC7231, Section 6.4.1](https://tools.ietf.org/html/rfc7231#section-6.4.1)]
(300, MULTIPLE_CHOICES, "Multiple Choices");
/// 301 Moved Permanently
/// [[RFC7231, Section 6.4.2](https://tools.ietf.org/html/rfc7231#section-6.4.2)]
(301, MOVED_PERMANENTLY, "Moved Permanently");
/// 302 Found
/// [[RFC7231, Section 6.4.3](https://tools.ietf.org/html/rfc7231#section-6.4.3)]
(302, FOUND, "Found");
/// 303 See Other
/// [[RFC7231, Section 6.4.4](https://tools.ietf.org/html/rfc7231#section-6.4.4)]
(303, SEE_OTHER, "See Other");
/// 304 Not Modified
/// [[RFC7232, Section 4.1](https://tools.ietf.org/html/rfc7232#section-4.1)]
(304, NOT_MODIFIED, "Not Modified");
/// 305 Use Proxy
/// [[RFC7231, Section 6.4.5](https://tools.ietf.org/html/rfc7231#section-6.4.5)]
(305, USE_PROXY, "Use Proxy");
/// 307 Temporary Redirect
/// [[RFC7231, Section 6.4.7](https://tools.ietf.org/html/rfc7231#section-6.4.7)]
(307, TEMPORARY_REDIRECT, "Temporary Redirect");
/// 308 Permanent Redirect
/// [[RFC7238](https://tools.ietf.org/html/rfc7238)]
(308, PERMANENT_REDIRECT, "Permanent Redirect");
/// 400 Bad Request
/// [[RFC7231, Section 6.5.1](https://tools.ietf.org/html/rfc7231#section-6.5.1)]
(400, BAD_REQUEST, "Bad Request");
/// 401 Unauthorized
/// [[RFC7235, Section 3.1](https://tools.ietf.org/html/rfc7235#section-3.1)]
(401, UNAUTHORIZED, "Unauthorized");
/// 402 Payment Required
/// [[RFC7231, Section 6.5.2](https://tools.ietf.org/html/rfc7231#section-6.5.2)]
(402, PAYMENT_REQUIRED, "Payment Required");
/// 403 Forbidden
/// [[RFC7231, Section 6.5.3](https://tools.ietf.org/html/rfc7231#section-6.5.3)]
(403, FORBIDDEN, "Forbidden");
/// 404 Not Found
/// [[RFC7231, Section 6.5.4](https://tools.ietf.org/html/rfc7231#section-6.5.4)]
(404, NOT_FOUND, "Not Found");
/// 405 Method Not Allowed
/// [[RFC7231, Section 6.5.5](https://tools.ietf.org/html/rfc7231#section-6.5.5)]
(405, METHOD_NOT_ALLOWED, "Method Not Allowed");
/// 406 Not Acceptable
/// [[RFC7231, Section 6.5.6](https://tools.ietf.org/html/rfc7231#section-6.5.6)]
(406, NOT_ACCEPTABLE, "Not Acceptable");
/// 407 Proxy Authentication Required
/// [[RFC7235, Section 3.2](https://tools.ietf.org/html/rfc7235#section-3.2)]
(407, PROXY_AUTHENTICATION_REQUIRED, "Proxy Authentication Required");
/// 408 Request Timeout
/// [[RFC7231, Section 6.5.7](https://tools.ietf.org/html/rfc7231#section-6.5.7)]
(408, REQUEST_TIMEOUT, "Request Timeout");
/// 409 Conflict
/// [[RFC7231, Section 6.5.8](https://tools.ietf.org/html/rfc7231#section-6.5.8)]
(409, CONFLICT, "Conflict");
/// 410 Gone
/// [[RFC7231, Section 6.5.9](https://tools.ietf.org/html/rfc7231#section-6.5.9)]
(410, GONE, "Gone");
/// 411 Length Required
/// [[RFC7231, Section 6.5.10](https://tools.ietf.org/html/rfc7231#section-6.5.10)]
(411, LENGTH_REQUIRED, "Length Required");
/// 412 Precondition Failed
/// [[RFC7232, Section 4.2](https://tools.ietf.org/html/rfc7232#section-4.2)]
(412, PRECONDITION_FAILED, "Precondition Failed");
/// 413 Payload Too Large
/// [[RFC7231, Section 6.5.11](https://tools.ietf.org/html/rfc7231#section-6.5.11)]
(413, PAYLOAD_TOO_LARGE, "Payload Too Large");
/// 414 URI Too Long
/// [[RFC7231, Section 6.5.12](https://tools.ietf.org/html/rfc7231#section-6.5.12)]
(414, URI_TOO_LONG, "URI Too Long");
/// 415 Unsupported Media Type
/// [[RFC7231, Section 6.5.13](https://tools.ietf.org/html/rfc7231#section-6.5.13)]
(415, UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
/// 416 Range Not Satisfiable
/// [[RFC7233, Section 4.4](https://tools.ietf.org/html/rfc7233#section-4.4)]
(416, RANGE_NOT_SATISFIABLE, "Range Not Satisfiable");
/// 417 Expectation Failed
/// [[RFC7231, Section 6.5.14](https://tools.ietf.org/html/rfc7231#section-6.5.14)]
(417, EXPECTATION_FAILED, "Expectation Failed");
/// 418 I'm a teapot
/// [curiously not registered by IANA but [RFC2324](https://tools.ietf.org/html/rfc2324)]
(418, IM_A_TEAPOT, "I'm a teapot");
/// 421 Misdirected Request
/// [RFC7540, Section 9.1.2](http://tools.ietf.org/html/rfc7540#section-9.1.2)
(421, MISDIRECTED_REQUEST, "Misdirected Request");
/// 422 Unprocessable Entity
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(422, UNPROCESSABLE_ENTITY, "Unprocessable Entity");
/// 423 Locked
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(423, LOCKED, "Locked");
/// 424 Failed Dependency
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(424, FAILED_DEPENDENCY, "Failed Dependency");
/// 426 Upgrade Required
/// [[RFC7231, Section 6.5.15](https://tools.ietf.org/html/rfc7231#section-6.5.15)]
(426, UPGRADE_REQUIRED, "Upgrade Required");
/// 428 Precondition Required
/// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
(428, PRECONDITION_REQUIRED, "Precondition Required");
/// 429 Too Many Requests
/// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
(429, TOO_MANY_REQUESTS, "Too Many Requests");
/// 431 Request Header Fields Too Large
/// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
(431, REQUEST_HEADER_FIELDS_TOO_LARGE, "Request Header Fields Too Large");
/// 451 Unavailable For Legal Reasons
/// [[RFC7725](http://tools.ietf.org/html/rfc7725)]
(451, UNAVAILABLE_FOR_LEGAL_REASONS, "Unavailable For Legal Reasons");
/// 500 Internal Server Error
/// [[RFC7231, Section 6.6.1](https://tools.ietf.org/html/rfc7231#section-6.6.1)]
(500, INTERNAL_SERVER_ERROR, "Internal Server Error");
/// 501 Not Implemented
/// [[RFC7231, Section 6.6.2](https://tools.ietf.org/html/rfc7231#section-6.6.2)]
(501, NOT_IMPLEMENTED, "Not Implemented");
/// 502 Bad Gateway
/// [[RFC7231, Section 6.6.3](https://tools.ietf.org/html/rfc7231#section-6.6.3)]
(502, BAD_GATEWAY, "Bad Gateway");
/// 503 Service Unavailable
/// [[RFC7231, Section 6.6.4](https://tools.ietf.org/html/rfc7231#section-6.6.4)]
(503, SERVICE_UNAVAILABLE, "Service Unavailable");
/// 504 Gateway Timeout
/// [[RFC7231, Section 6.6.5](https://tools.ietf.org/html/rfc7231#section-6.6.5)]
(504, GATEWAY_TIMEOUT, "Gateway Timeout");
/// 505 HTTP Version Not Supported
/// [[RFC7231, Section 6.6.6](https://tools.ietf.org/html/rfc7231#section-6.6.6)]
(505, HTTP_VERSION_NOT_SUPPORTED, "HTTP Version Not Supported");
/// 506 Variant Also Negotiates
/// [[RFC2295](https://tools.ietf.org/html/rfc2295)]
(506, VARIANT_ALSO_NEGOTIATES, "Variant Also Negotiates");
/// 507 Insufficient Storage
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(507, INSUFFICIENT_STORAGE, "Insufficient Storage");
/// 508 Loop Detected
/// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
(508, LOOP_DETECTED, "Loop Detected");
/// 510 Not Extended
/// [[RFC2774](https://tools.ietf.org/html/rfc2774)]
(510, NOT_EXTENDED, "Not Extended");
/// 511 Network Authentication Required
/// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
(511, NETWORK_AUTHENTICATION_REQUIRED, "Network Authentication Required");
}
impl InvalidStatusCode {
fn new() -> InvalidStatusCode {
InvalidStatusCode {
_priv: (),
}
}
}
impl fmt::Debug for InvalidStatusCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("InvalidStatusCode")
// skip _priv noise
.finish()
}
}
impl fmt::Display for InvalidStatusCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("invalid status code")
}
}
impl Error for InvalidStatusCode {}
// A string of packed 3-ASCII-digit status code values for the supported range
// of [100, 999] (900 codes, 2700 bytes).
const CODE_DIGITS: &'static str = "\
100101102103104105106107108109110111112113114115116117118119\
120121122123124125126127128129130131132133134135136137138139\
140141142143144145146147148149150151152153154155156157158159\
160161162163164165166167168169170171172173174175176177178179\
180181182183184185186187188189190191192193194195196197198199\
200201202203204205206207208209210211212213214215216217218219\
220221222223224225226227228229230231232233234235236237238239\
240241242243244245246247248249250251252253254255256257258259\
260261262263264265266267268269270271272273274275276277278279\
280281282283284285286287288289290291292293294295296297298299\
300301302303304305306307308309310311312313314315316317318319\
320321322323324325326327328329330331332333334335336337338339\
340341342343344345346347348349350351352353354355356357358359\
360361362363364365366367368369370371372373374375376377378379\
380381382383384385386387388389390391392393394395396397398399\
400401402403404405406407408409410411412413414415416417418419\
420421422423424425426427428429430431432433434435436437438439\
440441442443444445446447448449450451452453454455456457458459\
460461462463464465466467468469470471472473474475476477478479\
480481482483484485486487488489490491492493494495496497498499\
500501502503504505506507508509510511512513514515516517518519\
520521522523524525526527528529530531532533534535536537538539\
540541542543544545546547548549550551552553554555556557558559\
560561562563564565566567568569570571572573574575576577578579\
580581582583584585586587588589590591592593594595596597598599\
600601602603604605606607608609610611612613614615616617618619\
620621622623624625626627628629630631632633634635636637638639\
640641642643644645646647648649650651652653654655656657658659\
660661662663664665666667668669670671672673674675676677678679\
680681682683684685686687688689690691692693694695696697698699\
700701702703704705706707708709710711712713714715716717718719\
720721722723724725726727728729730731732733734735736737738739\
740741742743744745746747748749750751752753754755756757758759\
760761762763764765766767768769770771772773774775776777778779\
780781782783784785786787788789790791792793794795796797798799\
800801802803804805806807808809810811812813814815816817818819\
820821822823824825826827828829830831832833834835836837838839\
840841842843844845846847848849850851852853854855856857858859\
860861862863864865866867868869870871872873874875876877878879\
880881882883884885886887888889890891892893894895896897898899\
900901902903904905906907908909910911912913914915916917918919\
920921922923924925926927928929930931932933934935936937938939\
940941942943944945946947948949950951952953954955956957958959\
960961962963964965966967968969970971972973974975976977978979\
980981982983984985986987988989990991992993994995996997998999";

671
zeroidc/vendor/http/src/uri/authority.rs vendored Normal file
View File

@@ -0,0 +1,671 @@
use std::convert::TryFrom;
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use std::{cmp, fmt, str};
use bytes::Bytes;
use super::{ErrorKind, InvalidUri, Port, URI_CHARS};
use crate::byte_str::ByteStr;
/// Represents the authority component of a URI.
#[derive(Clone)]
pub struct Authority {
pub(super) data: ByteStr,
}
impl Authority {
pub(super) fn empty() -> Self {
Authority {
data: ByteStr::new(),
}
}
// Not public while `bytes` is unstable.
pub(super) fn from_shared(s: Bytes) -> Result<Self, InvalidUri> {
// Precondition on create_authority: trivially satisfied by the
// identity clousre
create_authority(s, |s| s)
}
/// Attempt to convert an `Authority` from a static string.
///
/// This function will not perform any copying, and the string will be
/// checked if it is empty or contains an invalid character.
///
/// # Panics
///
/// This function panics if the argument contains invalid characters or
/// is empty.
///
/// # Examples
///
/// ```
/// # use http::uri::Authority;
/// let authority = Authority::from_static("example.com");
/// assert_eq!(authority.host(), "example.com");
/// ```
pub fn from_static(src: &'static str) -> Self {
Authority::from_shared(Bytes::from_static(src.as_bytes()))
.expect("static str is not valid authority")
}
/// Attempt to convert a `Bytes` buffer to a `Authority`.
///
/// This will try to prevent a copy if the type passed is the type used
/// internally, and will copy the data if it is not.
pub fn from_maybe_shared<T>(src: T) -> Result<Self, InvalidUri>
where
T: AsRef<[u8]> + 'static,
{
if_downcast_into!(T, Bytes, src, {
return Authority::from_shared(src);
});
Authority::try_from(src.as_ref())
}
// Note: this may return an *empty* Authority. You might want `parse_non_empty`.
// Postcondition: for all Ok() returns, s[..ret.unwrap()] is valid UTF-8 where
// ret is the return value.
pub(super) fn parse(s: &[u8]) -> Result<usize, InvalidUri> {
let mut colon_cnt = 0;
let mut start_bracket = false;
let mut end_bracket = false;
let mut has_percent = false;
let mut end = s.len();
let mut at_sign_pos = None;
// Among other things, this loop checks that every byte in s up to the
// first '/', '?', or '#' is a valid URI character (or in some contexts,
// a '%'). This means that each such byte is a valid single-byte UTF-8
// code point.
for (i, &b) in s.iter().enumerate() {
match URI_CHARS[b as usize] {
b'/' | b'?' | b'#' => {
end = i;
break;
}
b':' => {
colon_cnt += 1;
}
b'[' => {
if has_percent || start_bracket {
// Something other than the userinfo has a `%`, so reject it.
return Err(ErrorKind::InvalidAuthority.into());
}
start_bracket = true;
}
b']' => {
if end_bracket {
return Err(ErrorKind::InvalidAuthority.into());
}
end_bracket = true;
// Those were part of an IPv6 hostname, so forget them...
colon_cnt = 0;
has_percent = false;
}
b'@' => {
at_sign_pos = Some(i);
// Those weren't a port colon, but part of the
// userinfo, so it needs to be forgotten.
colon_cnt = 0;
has_percent = false;
}
0 if b == b'%' => {
// Per https://tools.ietf.org/html/rfc3986#section-3.2.1 and
// https://url.spec.whatwg.org/#authority-state
// the userinfo can have a percent-encoded username and password,
// so record that a `%` was found. If this turns out to be
// part of the userinfo, this flag will be cleared.
// Also per https://tools.ietf.org/html/rfc6874, percent-encoding can
// be used to indicate a zone identifier.
// If the flag hasn't been cleared at the end, that means this
// was part of the hostname (and not part of an IPv6 address), and
// will fail with an error.
has_percent = true;
}
0 => {
return Err(ErrorKind::InvalidUriChar.into());
}
_ => {}
}
}
if start_bracket ^ end_bracket {
return Err(ErrorKind::InvalidAuthority.into());
}
if colon_cnt > 1 {
// Things like 'localhost:8080:3030' are rejected.
return Err(ErrorKind::InvalidAuthority.into());
}
if end > 0 && at_sign_pos == Some(end - 1) {
// If there's nothing after an `@`, this is bonkers.
return Err(ErrorKind::InvalidAuthority.into());
}
if has_percent {
// Something after the userinfo has a `%`, so reject it.
return Err(ErrorKind::InvalidAuthority.into());
}
Ok(end)
}
// Parse bytes as an Authority, not allowing an empty string.
//
// This should be used by functions that allow a user to parse
// an `Authority` by itself.
//
// Postcondition: for all Ok() returns, s[..ret.unwrap()] is valid UTF-8 where
// ret is the return value.
fn parse_non_empty(s: &[u8]) -> Result<usize, InvalidUri> {
if s.is_empty() {
return Err(ErrorKind::Empty.into());
}
Authority::parse(s)
}
/// Get the host of this `Authority`.
///
/// The host subcomponent of authority is identified by an IP literal
/// encapsulated within square brackets, an IPv4 address in dotted- decimal
/// form, or a registered name. The host subcomponent is **case-insensitive**.
///
/// ```notrust
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |---------|
/// |
/// host
/// ```
///
/// # Examples
///
/// ```
/// # use http::uri::*;
/// let authority: Authority = "example.org:80".parse().unwrap();
///
/// assert_eq!(authority.host(), "example.org");
/// ```
#[inline]
pub fn host(&self) -> &str {
host(self.as_str())
}
/// Get the port part of this `Authority`.
///
/// The port subcomponent of authority is designated by an optional port
/// number following the host and delimited from it by a single colon (":")
/// character. It can be turned into a decimal port number with the `as_u16`
/// method or as a `str` with the `as_str` method.
///
/// ```notrust
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |-|
/// |
/// port
/// ```
///
/// # Examples
///
/// Authority with port
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "example.org:80".parse().unwrap();
///
/// let port = authority.port().unwrap();
/// assert_eq!(port.as_u16(), 80);
/// assert_eq!(port.as_str(), "80");
/// ```
///
/// Authority without port
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "example.org".parse().unwrap();
///
/// assert!(authority.port().is_none());
/// ```
pub fn port(&self) -> Option<Port<&str>> {
let bytes = self.as_str();
bytes
.rfind(":")
.and_then(|i| Port::from_str(&bytes[i + 1..]).ok())
}
/// Get the port of this `Authority` as a `u16`.
///
/// # Example
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "example.org:80".parse().unwrap();
///
/// assert_eq!(authority.port_u16(), Some(80));
/// ```
pub fn port_u16(&self) -> Option<u16> {
self.port().and_then(|p| Some(p.as_u16()))
}
/// Return a str representation of the authority
#[inline]
pub fn as_str(&self) -> &str {
&self.data[..]
}
}
// Purposefully not public while `bytes` is unstable.
// impl TryFrom<Bytes> for Authority
impl AsRef<str> for Authority {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl PartialEq for Authority {
fn eq(&self, other: &Authority) -> bool {
self.data.eq_ignore_ascii_case(&other.data)
}
}
impl Eq for Authority {}
/// Case-insensitive equality
///
/// # Examples
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "HELLO.com".parse().unwrap();
/// assert_eq!(authority, "hello.coM");
/// assert_eq!("hello.com", authority);
/// ```
impl PartialEq<str> for Authority {
fn eq(&self, other: &str) -> bool {
self.data.eq_ignore_ascii_case(other)
}
}
impl PartialEq<Authority> for str {
fn eq(&self, other: &Authority) -> bool {
self.eq_ignore_ascii_case(other.as_str())
}
}
impl<'a> PartialEq<Authority> for &'a str {
fn eq(&self, other: &Authority) -> bool {
self.eq_ignore_ascii_case(other.as_str())
}
}
impl<'a> PartialEq<&'a str> for Authority {
fn eq(&self, other: &&'a str) -> bool {
self.data.eq_ignore_ascii_case(other)
}
}
impl PartialEq<String> for Authority {
fn eq(&self, other: &String) -> bool {
self.data.eq_ignore_ascii_case(other.as_str())
}
}
impl PartialEq<Authority> for String {
fn eq(&self, other: &Authority) -> bool {
self.as_str().eq_ignore_ascii_case(other.as_str())
}
}
/// Case-insensitive ordering
///
/// # Examples
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "DEF.com".parse().unwrap();
/// assert!(authority < "ghi.com");
/// assert!(authority > "abc.com");
/// ```
impl PartialOrd for Authority {
fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
impl PartialOrd<str> for Authority {
fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
impl PartialOrd<Authority> for str {
fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
impl<'a> PartialOrd<Authority> for &'a str {
fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
impl<'a> PartialOrd<&'a str> for Authority {
fn partial_cmp(&self, other: &&'a str) -> Option<cmp::Ordering> {
let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
impl PartialOrd<String> for Authority {
fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
impl PartialOrd<Authority> for String {
fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
/// Case-insensitive hashing
///
/// # Examples
///
/// ```
/// # use http::uri::Authority;
/// # use std::hash::{Hash, Hasher};
/// # use std::collections::hash_map::DefaultHasher;
///
/// let a: Authority = "HELLO.com".parse().unwrap();
/// let b: Authority = "hello.coM".parse().unwrap();
///
/// let mut s = DefaultHasher::new();
/// a.hash(&mut s);
/// let a = s.finish();
///
/// let mut s = DefaultHasher::new();
/// b.hash(&mut s);
/// let b = s.finish();
///
/// assert_eq!(a, b);
/// ```
impl Hash for Authority {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.data.len().hash(state);
for &b in self.data.as_bytes() {
state.write_u8(b.to_ascii_lowercase());
}
}
}
impl<'a> TryFrom<&'a [u8]> for Authority {
type Error = InvalidUri;
#[inline]
fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
// parse first, and only turn into Bytes if valid
// Preconditon on create_authority: copy_from_slice() copies all of
// bytes from the [u8] parameter into a new Bytes
create_authority(s, |s| Bytes::copy_from_slice(s))
}
}
impl<'a> TryFrom<&'a str> for Authority {
type Error = InvalidUri;
#[inline]
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
TryFrom::try_from(s.as_bytes())
}
}
impl TryFrom<Vec<u8>> for Authority {
type Error = InvalidUri;
#[inline]
fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
Authority::from_shared(vec.into())
}
}
impl TryFrom<String> for Authority {
type Error = InvalidUri;
#[inline]
fn try_from(t: String) -> Result<Self, Self::Error> {
Authority::from_shared(t.into())
}
}
impl FromStr for Authority {
type Err = InvalidUri;
fn from_str(s: &str) -> Result<Self, InvalidUri> {
TryFrom::try_from(s)
}
}
impl fmt::Debug for Authority {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl fmt::Display for Authority {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
fn host(auth: &str) -> &str {
let host_port = auth
.rsplitn(2, '@')
.next()
.expect("split always has at least 1 item");
if host_port.as_bytes()[0] == b'[' {
let i = host_port
.find(']')
.expect("parsing should validate brackets");
// ..= ranges aren't available in 1.20, our minimum Rust version...
&host_port[0..i + 1]
} else {
host_port
.split(':')
.next()
.expect("split always has at least 1 item")
}
}
// Precondition: f converts all of the bytes in the passed in B into the
// returned Bytes.
fn create_authority<B, F>(b: B, f: F) -> Result<Authority, InvalidUri>
where
B: AsRef<[u8]>,
F: FnOnce(B) -> Bytes,
{
let s = b.as_ref();
let authority_end = Authority::parse_non_empty(s)?;
if authority_end != s.len() {
return Err(ErrorKind::InvalidUriChar.into());
}
let bytes = f(b);
Ok(Authority {
// Safety: the postcondition on parse_non_empty() and the check against
// s.len() ensure that b is valid UTF-8. The precondition on f ensures
// that this is carried through to bytes.
data: unsafe { ByteStr::from_utf8_unchecked(bytes) },
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_empty_string_is_error() {
let err = Authority::parse_non_empty(b"").unwrap_err();
assert_eq!(err.0, ErrorKind::Empty);
}
#[test]
fn equal_to_self_of_same_authority() {
let authority1: Authority = "example.com".parse().unwrap();
let authority2: Authority = "EXAMPLE.COM".parse().unwrap();
assert_eq!(authority1, authority2);
assert_eq!(authority2, authority1);
}
#[test]
fn not_equal_to_self_of_different_authority() {
let authority1: Authority = "example.com".parse().unwrap();
let authority2: Authority = "test.com".parse().unwrap();
assert_ne!(authority1, authority2);
assert_ne!(authority2, authority1);
}
#[test]
fn equates_with_a_str() {
let authority: Authority = "example.com".parse().unwrap();
assert_eq!(&authority, "EXAMPLE.com");
assert_eq!("EXAMPLE.com", &authority);
assert_eq!(authority, "EXAMPLE.com");
assert_eq!("EXAMPLE.com", authority);
}
#[test]
fn from_static_equates_with_a_str() {
let authority = Authority::from_static("example.com");
assert_eq!(authority, "example.com");
}
#[test]
fn not_equal_with_a_str_of_a_different_authority() {
let authority: Authority = "example.com".parse().unwrap();
assert_ne!(&authority, "test.com");
assert_ne!("test.com", &authority);
assert_ne!(authority, "test.com");
assert_ne!("test.com", authority);
}
#[test]
fn equates_with_a_string() {
let authority: Authority = "example.com".parse().unwrap();
assert_eq!(authority, "EXAMPLE.com".to_string());
assert_eq!("EXAMPLE.com".to_string(), authority);
}
#[test]
fn equates_with_a_string_of_a_different_authority() {
let authority: Authority = "example.com".parse().unwrap();
assert_ne!(authority, "test.com".to_string());
assert_ne!("test.com".to_string(), authority);
}
#[test]
fn compares_to_self() {
let authority1: Authority = "abc.com".parse().unwrap();
let authority2: Authority = "def.com".parse().unwrap();
assert!(authority1 < authority2);
assert!(authority2 > authority1);
}
#[test]
fn compares_with_a_str() {
let authority: Authority = "def.com".parse().unwrap();
// with ref
assert!(&authority < "ghi.com");
assert!("ghi.com" > &authority);
assert!(&authority > "abc.com");
assert!("abc.com" < &authority);
// no ref
assert!(authority < "ghi.com");
assert!("ghi.com" > authority);
assert!(authority > "abc.com");
assert!("abc.com" < authority);
}
#[test]
fn compares_with_a_string() {
let authority: Authority = "def.com".parse().unwrap();
assert!(authority < "ghi.com".to_string());
assert!("ghi.com".to_string() > authority);
assert!(authority > "abc.com".to_string());
assert!("abc.com".to_string() < authority);
}
#[test]
fn allows_percent_in_userinfo() {
let authority_str = "a%2f:b%2f@example.com";
let authority: Authority = authority_str.parse().unwrap();
assert_eq!(authority, authority_str);
}
#[test]
fn rejects_percent_in_hostname() {
let err = Authority::parse_non_empty(b"example%2f.com").unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidAuthority);
let err = Authority::parse_non_empty(b"a%2f:b%2f@example%2f.com").unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidAuthority);
}
#[test]
fn allows_percent_in_ipv6_address() {
let authority_str = "[fe80::1:2:3:4%25eth0]";
let result: Authority = authority_str.parse().unwrap();
assert_eq!(result, authority_str);
}
#[test]
fn rejects_percent_outside_ipv6_address() {
let err = Authority::parse_non_empty(b"1234%20[fe80::1:2:3:4]").unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidAuthority);
let err = Authority::parse_non_empty(b"[fe80::1:2:3:4]%20").unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidAuthority);
}
#[test]
fn rejects_invalid_utf8() {
let err = Authority::try_from([0xc0u8].as_ref()).unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidUriChar);
let err = Authority::from_shared(Bytes::from_static([0xc0u8].as_ref()))
.unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidUriChar);
}
#[test]
fn rejects_invalid_use_of_brackets() {
let err = Authority::parse_non_empty(b"[]@[").unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidAuthority);
}
}

197
zeroidc/vendor/http/src/uri/builder.rs vendored Normal file
View File

@@ -0,0 +1,197 @@
use std::convert::{TryFrom, TryInto};
use super::{Authority, Parts, PathAndQuery, Scheme};
use crate::Uri;
/// A builder for `Uri`s.
///
/// This type can be used to construct an instance of `Uri`
/// through a builder pattern.
#[derive(Debug)]
pub struct Builder {
parts: Result<Parts, crate::Error>,
}
impl Builder {
/// Creates a new default instance of `Builder` to construct a `Uri`.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let uri = uri::Builder::new()
/// .scheme("https")
/// .authority("hyper.rs")
/// .path_and_query("/")
/// .build()
/// .unwrap();
/// ```
#[inline]
pub fn new() -> Builder {
Builder::default()
}
/// Set the `Scheme` for this URI.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let mut builder = uri::Builder::new();
/// builder.scheme("https");
/// ```
pub fn scheme<T>(self, scheme: T) -> Self
where
Scheme: TryFrom<T>,
<Scheme as TryFrom<T>>::Error: Into<crate::Error>,
{
self.map(move |mut parts| {
let scheme = scheme.try_into().map_err(Into::into)?;
parts.scheme = Some(scheme);
Ok(parts)
})
}
/// Set the `Authority` for this URI.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let uri = uri::Builder::new()
/// .authority("tokio.rs")
/// .build()
/// .unwrap();
/// ```
pub fn authority<T>(self, auth: T) -> Self
where
Authority: TryFrom<T>,
<Authority as TryFrom<T>>::Error: Into<crate::Error>,
{
self.map(move |mut parts| {
let auth = auth.try_into().map_err(Into::into)?;
parts.authority = Some(auth);
Ok(parts)
})
}
/// Set the `PathAndQuery` for this URI.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let uri = uri::Builder::new()
/// .path_and_query("/hello?foo=bar")
/// .build()
/// .unwrap();
/// ```
pub fn path_and_query<T>(self, p_and_q: T) -> Self
where
PathAndQuery: TryFrom<T>,
<PathAndQuery as TryFrom<T>>::Error: Into<crate::Error>,
{
self.map(move |mut parts| {
let p_and_q = p_and_q.try_into().map_err(Into::into)?;
parts.path_and_query = Some(p_and_q);
Ok(parts)
})
}
/// Consumes this builder, and tries to construct a valid `Uri` from
/// the configured pieces.
///
/// # Errors
///
/// This function may return an error if any previously configured argument
/// failed to parse or get converted to the internal representation. For
/// example if an invalid `scheme` was specified via `scheme("!@#%/^")`
/// the error will be returned when this function is called rather than
/// when `scheme` was called.
///
/// Additionally, the various forms of URI require certain combinations of
/// parts to be set to be valid. If the parts don't fit into any of the
/// valid forms of URI, a new error is returned.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let uri = Uri::builder()
/// .build()
/// .unwrap();
/// ```
pub fn build(self) -> Result<Uri, crate::Error> {
let parts = self.parts?;
Uri::from_parts(parts).map_err(Into::into)
}
// private
fn map<F>(self, func: F) -> Self
where
F: FnOnce(Parts) -> Result<Parts, crate::Error>,
{
Builder {
parts: self.parts.and_then(func),
}
}
}
impl Default for Builder {
#[inline]
fn default() -> Builder {
Builder {
parts: Ok(Parts::default()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn build_from_str() {
let uri = Builder::new()
.scheme(Scheme::HTTP)
.authority("hyper.rs")
.path_and_query("/foo?a=1")
.build()
.unwrap();
assert_eq!(uri.scheme_str(), Some("http"));
assert_eq!(uri.authority().unwrap().host(), "hyper.rs");
assert_eq!(uri.path(), "/foo");
assert_eq!(uri.query(), Some("a=1"));
}
#[test]
fn build_from_string() {
for i in 1..10 {
let uri = Builder::new()
.path_and_query(format!("/foo?a={}", i))
.build()
.unwrap();
let expected_query = format!("a={}", i);
assert_eq!(uri.path(), "/foo");
assert_eq!(uri.query(), Some(expected_query.as_str()));
}
}
#[test]
fn build_from_string_ref() {
for i in 1..10 {
let p_a_q = format!("/foo?a={}", i);
let uri = Builder::new().path_and_query(&p_a_q).build().unwrap();
let expected_query = format!("a={}", i);
assert_eq!(uri.path(), "/foo");
assert_eq!(uri.query(), Some(expected_query.as_str()));
}
}
}

1118
zeroidc/vendor/http/src/uri/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

558
zeroidc/vendor/http/src/uri/path.rs vendored Normal file
View File

@@ -0,0 +1,558 @@
use std::convert::TryFrom;
use std::str::FromStr;
use std::{cmp, fmt, str};
use bytes::Bytes;
use super::{ErrorKind, InvalidUri};
use crate::byte_str::ByteStr;
/// Represents the path component of a URI
#[derive(Clone)]
pub struct PathAndQuery {
pub(super) data: ByteStr,
pub(super) query: u16,
}
const NONE: u16 = ::std::u16::MAX;
impl PathAndQuery {
// Not public while `bytes` is unstable.
pub(super) fn from_shared(mut src: Bytes) -> Result<Self, InvalidUri> {
let mut query = NONE;
let mut fragment = None;
// block for iterator borrow
{
let mut iter = src.as_ref().iter().enumerate();
// path ...
for (i, &b) in &mut iter {
// See https://url.spec.whatwg.org/#path-state
match b {
b'?' => {
debug_assert_eq!(query, NONE);
query = i as u16;
break;
}
b'#' => {
fragment = Some(i);
break;
}
// This is the range of bytes that don't need to be
// percent-encoded in the path. If it should have been
// percent-encoded, then error.
0x21 |
0x24..=0x3B |
0x3D |
0x40..=0x5F |
0x61..=0x7A |
0x7C |
0x7E => {},
// These are code points that are supposed to be
// percent-encoded in the path but there are clients
// out there sending them as is and httparse accepts
// to parse those requests, so they are allowed here
// for parity.
//
// For reference, those are code points that are used
// to send requests with JSON directly embedded in
// the URI path. Yes, those things happen for real.
b'"' |
b'{' | b'}' => {},
_ => return Err(ErrorKind::InvalidUriChar.into()),
}
}
// query ...
if query != NONE {
for (i, &b) in iter {
match b {
// While queries *should* be percent-encoded, most
// bytes are actually allowed...
// See https://url.spec.whatwg.org/#query-state
//
// Allowed: 0x21 / 0x24 - 0x3B / 0x3D / 0x3F - 0x7E
0x21 |
0x24..=0x3B |
0x3D |
0x3F..=0x7E => {},
b'#' => {
fragment = Some(i);
break;
}
_ => return Err(ErrorKind::InvalidUriChar.into()),
}
}
}
}
if let Some(i) = fragment {
src.truncate(i);
}
Ok(PathAndQuery {
data: unsafe { ByteStr::from_utf8_unchecked(src) },
query: query,
})
}
/// Convert a `PathAndQuery` from a static string.
///
/// This function will not perform any copying, however the string is
/// checked to ensure that it is valid.
///
/// # Panics
///
/// This function panics if the argument is an invalid path and query.
///
/// # Examples
///
/// ```
/// # use http::uri::*;
/// let v = PathAndQuery::from_static("/hello?world");
///
/// assert_eq!(v.path(), "/hello");
/// assert_eq!(v.query(), Some("world"));
/// ```
#[inline]
pub fn from_static(src: &'static str) -> Self {
let src = Bytes::from_static(src.as_bytes());
PathAndQuery::from_shared(src).unwrap()
}
/// Attempt to convert a `Bytes` buffer to a `PathAndQuery`.
///
/// This will try to prevent a copy if the type passed is the type used
/// internally, and will copy the data if it is not.
pub fn from_maybe_shared<T>(src: T) -> Result<Self, InvalidUri>
where
T: AsRef<[u8]> + 'static,
{
if_downcast_into!(T, Bytes, src, {
return PathAndQuery::from_shared(src);
});
PathAndQuery::try_from(src.as_ref())
}
pub(super) fn empty() -> Self {
PathAndQuery {
data: ByteStr::new(),
query: NONE,
}
}
pub(super) fn slash() -> Self {
PathAndQuery {
data: ByteStr::from_static("/"),
query: NONE,
}
}
pub(super) fn star() -> Self {
PathAndQuery {
data: ByteStr::from_static("*"),
query: NONE,
}
}
/// Returns the path component
///
/// The path component is **case sensitive**.
///
/// ```notrust
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |--------|
/// |
/// path
/// ```
///
/// If the URI is `*` then the path component is equal to `*`.
///
/// # Examples
///
/// ```
/// # use http::uri::*;
///
/// let path_and_query: PathAndQuery = "/hello/world".parse().unwrap();
///
/// assert_eq!(path_and_query.path(), "/hello/world");
/// ```
#[inline]
pub fn path(&self) -> &str {
let ret = if self.query == NONE {
&self.data[..]
} else {
&self.data[..self.query as usize]
};
if ret.is_empty() {
return "/";
}
ret
}
/// Returns the query string component
///
/// The query component contains non-hierarchical data that, along with data
/// in the path component, serves to identify a resource within the scope of
/// the URI's scheme and naming authority (if any). The query component is
/// indicated by the first question mark ("?") character and terminated by a
/// number sign ("#") character or by the end of the URI.
///
/// ```notrust
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |-------------------|
/// |
/// query
/// ```
///
/// # Examples
///
/// With a query string component
///
/// ```
/// # use http::uri::*;
/// let path_and_query: PathAndQuery = "/hello/world?key=value&foo=bar".parse().unwrap();
///
/// assert_eq!(path_and_query.query(), Some("key=value&foo=bar"));
/// ```
///
/// Without a query string component
///
/// ```
/// # use http::uri::*;
/// let path_and_query: PathAndQuery = "/hello/world".parse().unwrap();
///
/// assert!(path_and_query.query().is_none());
/// ```
#[inline]
pub fn query(&self) -> Option<&str> {
if self.query == NONE {
None
} else {
let i = self.query + 1;
Some(&self.data[i as usize..])
}
}
/// Returns the path and query as a string component.
///
/// # Examples
///
/// With a query string component
///
/// ```
/// # use http::uri::*;
/// let path_and_query: PathAndQuery = "/hello/world?key=value&foo=bar".parse().unwrap();
///
/// assert_eq!(path_and_query.as_str(), "/hello/world?key=value&foo=bar");
/// ```
///
/// Without a query string component
///
/// ```
/// # use http::uri::*;
/// let path_and_query: PathAndQuery = "/hello/world".parse().unwrap();
///
/// assert_eq!(path_and_query.as_str(), "/hello/world");
/// ```
#[inline]
pub fn as_str(&self) -> &str {
let ret = &self.data[..];
if ret.is_empty() {
return "/";
}
ret
}
}
impl<'a> TryFrom<&'a [u8]> for PathAndQuery {
type Error = InvalidUri;
#[inline]
fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
PathAndQuery::from_shared(Bytes::copy_from_slice(s))
}
}
impl<'a> TryFrom<&'a str> for PathAndQuery {
type Error = InvalidUri;
#[inline]
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
TryFrom::try_from(s.as_bytes())
}
}
impl<'a> TryFrom<Vec<u8>> for PathAndQuery {
type Error = InvalidUri;
#[inline]
fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
PathAndQuery::from_shared(vec.into())
}
}
impl TryFrom<String> for PathAndQuery {
type Error = InvalidUri;
#[inline]
fn try_from(s: String) -> Result<Self, Self::Error> {
PathAndQuery::from_shared(s.into())
}
}
impl TryFrom<&String> for PathAndQuery {
type Error = InvalidUri;
#[inline]
fn try_from(s: &String) -> Result<Self, Self::Error> {
TryFrom::try_from(s.as_bytes())
}
}
impl FromStr for PathAndQuery {
type Err = InvalidUri;
#[inline]
fn from_str(s: &str) -> Result<Self, InvalidUri> {
TryFrom::try_from(s)
}
}
impl fmt::Debug for PathAndQuery {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for PathAndQuery {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
if !self.data.is_empty() {
match self.data.as_bytes()[0] {
b'/' | b'*' => write!(fmt, "{}", &self.data[..]),
_ => write!(fmt, "/{}", &self.data[..]),
}
} else {
write!(fmt, "/")
}
}
}
// ===== PartialEq / PartialOrd =====
impl PartialEq for PathAndQuery {
#[inline]
fn eq(&self, other: &PathAndQuery) -> bool {
self.data == other.data
}
}
impl Eq for PathAndQuery {}
impl PartialEq<str> for PathAndQuery {
#[inline]
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl<'a> PartialEq<PathAndQuery> for &'a str {
#[inline]
fn eq(&self, other: &PathAndQuery) -> bool {
self == &other.as_str()
}
}
impl<'a> PartialEq<&'a str> for PathAndQuery {
#[inline]
fn eq(&self, other: &&'a str) -> bool {
self.as_str() == *other
}
}
impl PartialEq<PathAndQuery> for str {
#[inline]
fn eq(&self, other: &PathAndQuery) -> bool {
self == other.as_str()
}
}
impl PartialEq<String> for PathAndQuery {
#[inline]
fn eq(&self, other: &String) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<PathAndQuery> for String {
#[inline]
fn eq(&self, other: &PathAndQuery) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialOrd for PathAndQuery {
#[inline]
fn partial_cmp(&self, other: &PathAndQuery) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other.as_str())
}
}
impl PartialOrd<str> for PathAndQuery {
#[inline]
fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other)
}
}
impl PartialOrd<PathAndQuery> for str {
#[inline]
fn partial_cmp(&self, other: &PathAndQuery) -> Option<cmp::Ordering> {
self.partial_cmp(other.as_str())
}
}
impl<'a> PartialOrd<&'a str> for PathAndQuery {
#[inline]
fn partial_cmp(&self, other: &&'a str) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(*other)
}
}
impl<'a> PartialOrd<PathAndQuery> for &'a str {
#[inline]
fn partial_cmp(&self, other: &PathAndQuery) -> Option<cmp::Ordering> {
self.partial_cmp(&other.as_str())
}
}
impl PartialOrd<String> for PathAndQuery {
#[inline]
fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other.as_str())
}
}
impl PartialOrd<PathAndQuery> for String {
#[inline]
fn partial_cmp(&self, other: &PathAndQuery) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other.as_str())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn equal_to_self_of_same_path() {
let p1: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
let p2: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
assert_eq!(p1, p2);
assert_eq!(p2, p1);
}
#[test]
fn not_equal_to_self_of_different_path() {
let p1: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
let p2: PathAndQuery = "/world&foo=bar".parse().unwrap();
assert_ne!(p1, p2);
assert_ne!(p2, p1);
}
#[test]
fn equates_with_a_str() {
let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
assert_eq!(&path_and_query, "/hello/world&foo=bar");
assert_eq!("/hello/world&foo=bar", &path_and_query);
assert_eq!(path_and_query, "/hello/world&foo=bar");
assert_eq!("/hello/world&foo=bar", path_and_query);
}
#[test]
fn not_equal_with_a_str_of_a_different_path() {
let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
// as a reference
assert_ne!(&path_and_query, "/hello&foo=bar");
assert_ne!("/hello&foo=bar", &path_and_query);
// without reference
assert_ne!(path_and_query, "/hello&foo=bar");
assert_ne!("/hello&foo=bar", path_and_query);
}
#[test]
fn equates_with_a_string() {
let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
assert_eq!(path_and_query, "/hello/world&foo=bar".to_string());
assert_eq!("/hello/world&foo=bar".to_string(), path_and_query);
}
#[test]
fn not_equal_with_a_string_of_a_different_path() {
let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
assert_ne!(path_and_query, "/hello&foo=bar".to_string());
assert_ne!("/hello&foo=bar".to_string(), path_and_query);
}
#[test]
fn compares_to_self() {
let p1: PathAndQuery = "/a/world&foo=bar".parse().unwrap();
let p2: PathAndQuery = "/b/world&foo=bar".parse().unwrap();
assert!(p1 < p2);
assert!(p2 > p1);
}
#[test]
fn compares_with_a_str() {
let path_and_query: PathAndQuery = "/b/world&foo=bar".parse().unwrap();
// by ref
assert!(&path_and_query < "/c/world&foo=bar");
assert!("/c/world&foo=bar" > &path_and_query);
assert!(&path_and_query > "/a/world&foo=bar");
assert!("/a/world&foo=bar" < &path_and_query);
// by val
assert!(path_and_query < "/c/world&foo=bar");
assert!("/c/world&foo=bar" > path_and_query);
assert!(path_and_query > "/a/world&foo=bar");
assert!("/a/world&foo=bar" < path_and_query);
}
#[test]
fn compares_with_a_string() {
let path_and_query: PathAndQuery = "/b/world&foo=bar".parse().unwrap();
assert!(path_and_query < "/c/world&foo=bar".to_string());
assert!("/c/world&foo=bar".to_string() > path_and_query);
assert!(path_and_query > "/a/world&foo=bar".to_string());
assert!("/a/world&foo=bar".to_string() < path_and_query);
}
#[test]
fn ignores_valid_percent_encodings() {
assert_eq!("/a%20b", pq("/a%20b?r=1").path());
assert_eq!("qr=%31", pq("/a/b?qr=%31").query().unwrap());
}
#[test]
fn ignores_invalid_percent_encodings() {
assert_eq!("/a%%b", pq("/a%%b?r=1").path());
assert_eq!("/aaa%", pq("/aaa%").path());
assert_eq!("/aaa%", pq("/aaa%?r=1").path());
assert_eq!("/aa%2", pq("/aa%2").path());
assert_eq!("/aa%2", pq("/aa%2?r=1").path());
assert_eq!("qr=%3", pq("/a/b?qr=%3").query().unwrap());
}
#[test]
fn json_is_fine() {
assert_eq!(r#"/{"bread":"baguette"}"#, pq(r#"/{"bread":"baguette"}"#).path());
}
fn pq(s: &str) -> PathAndQuery {
s.parse().expect(&format!("parsing {}", s))
}
}

151
zeroidc/vendor/http/src/uri/port.rs vendored Normal file
View File

@@ -0,0 +1,151 @@
use std::fmt;
use super::{ErrorKind, InvalidUri};
/// The port component of a URI.
pub struct Port<T> {
port: u16,
repr: T,
}
impl<T> Port<T> {
/// Returns the port number as a `u16`.
///
/// # Examples
///
/// Port as `u16`.
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "example.org:80".parse().unwrap();
///
/// let port = authority.port().unwrap();
/// assert_eq!(port.as_u16(), 80);
/// ```
pub fn as_u16(&self) -> u16 {
self.port
}
}
impl<T> Port<T>
where
T: AsRef<str>,
{
/// Converts a `str` to a port number.
///
/// The supplied `str` must be a valid u16.
pub(crate) fn from_str(bytes: T) -> Result<Self, InvalidUri> {
bytes
.as_ref()
.parse::<u16>()
.map(|port| Port { port, repr: bytes })
.map_err(|_| ErrorKind::InvalidPort.into())
}
/// Returns the port number as a `str`.
///
/// # Examples
///
/// Port as `str`.
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "example.org:80".parse().unwrap();
///
/// let port = authority.port().unwrap();
/// assert_eq!(port.as_str(), "80");
/// ```
pub fn as_str(&self) -> &str {
self.repr.as_ref()
}
}
impl<T> fmt::Debug for Port<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Port").field(&self.port).finish()
}
}
impl<T> fmt::Display for Port<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Use `u16::fmt` so that it respects any formatting flags that
// may have been set (like padding, align, etc).
fmt::Display::fmt(&self.port, f)
}
}
impl<T> From<Port<T>> for u16 {
fn from(port: Port<T>) -> Self {
port.as_u16()
}
}
impl<T> AsRef<str> for Port<T>
where
T: AsRef<str>,
{
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<T, U> PartialEq<Port<U>> for Port<T> {
fn eq(&self, other: &Port<U>) -> bool {
self.port == other.port
}
}
impl<T> PartialEq<u16> for Port<T> {
fn eq(&self, other: &u16) -> bool {
self.port == *other
}
}
impl<T> PartialEq<Port<T>> for u16 {
fn eq(&self, other: &Port<T>) -> bool {
other.port == *self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn partialeq_port() {
let port_a = Port::from_str("8080").unwrap();
let port_b = Port::from_str("8080").unwrap();
assert_eq!(port_a, port_b);
}
#[test]
fn partialeq_port_different_reprs() {
let port_a = Port {
repr: "8081",
port: 8081,
};
let port_b = Port {
repr: String::from("8081"),
port: 8081,
};
assert_eq!(port_a, port_b);
assert_eq!(port_b, port_a);
}
#[test]
fn partialeq_u16() {
let port = Port::from_str("8080").unwrap();
// test equals in both directions
assert_eq!(port, 8080);
assert_eq!(8080, port);
}
#[test]
fn u16_from_port() {
let port = Port::from_str("8080").unwrap();
assert_eq!(8080, u16::from(port));
}
}

363
zeroidc/vendor/http/src/uri/scheme.rs vendored Normal file
View File

@@ -0,0 +1,363 @@
use std::convert::TryFrom;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use bytes::Bytes;
use super::{ErrorKind, InvalidUri};
use crate::byte_str::ByteStr;
/// Represents the scheme component of a URI
#[derive(Clone)]
pub struct Scheme {
pub(super) inner: Scheme2,
}
#[derive(Clone, Debug)]
pub(super) enum Scheme2<T = Box<ByteStr>> {
None,
Standard(Protocol),
Other(T),
}
#[derive(Copy, Clone, Debug)]
pub(super) enum Protocol {
Http,
Https,
}
impl Scheme {
/// HTTP protocol scheme
pub const HTTP: Scheme = Scheme {
inner: Scheme2::Standard(Protocol::Http),
};
/// HTTP protocol over TLS.
pub const HTTPS: Scheme = Scheme {
inner: Scheme2::Standard(Protocol::Https),
};
pub(super) fn empty() -> Self {
Scheme {
inner: Scheme2::None,
}
}
/// Return a str representation of the scheme
///
/// # Examples
///
/// ```
/// # use http::uri::*;
/// let scheme: Scheme = "http".parse().unwrap();
/// assert_eq!(scheme.as_str(), "http");
/// ```
#[inline]
pub fn as_str(&self) -> &str {
use self::Protocol::*;
use self::Scheme2::*;
match self.inner {
Standard(Http) => "http",
Standard(Https) => "https",
Other(ref v) => &v[..],
None => unreachable!(),
}
}
}
impl<'a> TryFrom<&'a [u8]> for Scheme {
type Error = InvalidUri;
#[inline]
fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
use self::Scheme2::*;
match Scheme2::parse_exact(s)? {
None => Err(ErrorKind::InvalidScheme.into()),
Standard(p) => Ok(Standard(p).into()),
Other(_) => {
let bytes = Bytes::copy_from_slice(s);
// Safety: postcondition on parse_exact() means that s and
// hence bytes are valid UTF-8.
let string = unsafe { ByteStr::from_utf8_unchecked(bytes) };
Ok(Other(Box::new(string)).into())
}
}
}
}
impl<'a> TryFrom<&'a str> for Scheme {
type Error = InvalidUri;
#[inline]
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
TryFrom::try_from(s.as_bytes())
}
}
impl FromStr for Scheme {
type Err = InvalidUri;
fn from_str(s: &str) -> Result<Self, Self::Err> {
TryFrom::try_from(s)
}
}
impl fmt::Debug for Scheme {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.as_str(), f)
}
}
impl fmt::Display for Scheme {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl AsRef<str> for Scheme {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl PartialEq for Scheme {
fn eq(&self, other: &Scheme) -> bool {
use self::Protocol::*;
use self::Scheme2::*;
match (&self.inner, &other.inner) {
(&Standard(Http), &Standard(Http)) => true,
(&Standard(Https), &Standard(Https)) => true,
(&Other(ref a), &Other(ref b)) => a.eq_ignore_ascii_case(b),
(&None, _) | (_, &None) => unreachable!(),
_ => false,
}
}
}
impl Eq for Scheme {}
/// Case-insensitive equality
///
/// # Examples
///
/// ```
/// # use http::uri::Scheme;
/// let scheme: Scheme = "HTTP".parse().unwrap();
/// assert_eq!(scheme, *"http");
/// ```
impl PartialEq<str> for Scheme {
fn eq(&self, other: &str) -> bool {
self.as_str().eq_ignore_ascii_case(other)
}
}
/// Case-insensitive equality
impl PartialEq<Scheme> for str {
fn eq(&self, other: &Scheme) -> bool {
other == self
}
}
/// Case-insensitive hashing
impl Hash for Scheme {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
match self.inner {
Scheme2::None => (),
Scheme2::Standard(Protocol::Http) => state.write_u8(1),
Scheme2::Standard(Protocol::Https) => state.write_u8(2),
Scheme2::Other(ref other) => {
other.len().hash(state);
for &b in other.as_bytes() {
state.write_u8(b.to_ascii_lowercase());
}
}
}
}
}
impl<T> Scheme2<T> {
pub(super) fn is_none(&self) -> bool {
match *self {
Scheme2::None => true,
_ => false,
}
}
}
// Require the scheme to not be too long in order to enable further
// optimizations later.
const MAX_SCHEME_LEN: usize = 64;
// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
//
// SCHEME_CHARS is a table of valid characters in the scheme part of a URI. An
// entry in the table is 0 for invalid characters. For valid characters the
// entry is itself (i.e. the entry for 43 is b'+' because b'+' == 43u8). An
// important characteristic of this table is that all entries above 127 are
// invalid. This makes all of the valid entries a valid single-byte UTF-8 code
// point. This means that a slice of such valid entries is valid UTF-8.
const SCHEME_CHARS: [u8; 256] = [
// 0 1 2 3 4 5 6 7 8 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3x
0, 0, 0, b'+', 0, b'-', b'.', 0, b'0', b'1', // 4x
b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b':', 0, // 5x
0, 0, 0, 0, 0, b'A', b'B', b'C', b'D', b'E', // 6x
b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', // 7x
b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', // 8x
b'Z', 0, 0, 0, 0, 0, 0, b'a', b'b', b'c', // 9x
b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', // 10x
b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', // 11x
b'x', b'y', b'z', 0, 0, 0, b'~', 0, 0, 0, // 12x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 13x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 14x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 15x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 17x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 18x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 19x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 22x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 23x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 24x
0, 0, 0, 0, 0, 0 // 25x
];
impl Scheme2<usize> {
// Postcondition: On all Ok() returns, s is valid UTF-8
fn parse_exact(s: &[u8]) -> Result<Scheme2<()>, InvalidUri> {
match s {
b"http" => Ok(Protocol::Http.into()),
b"https" => Ok(Protocol::Https.into()),
_ => {
if s.len() > MAX_SCHEME_LEN {
return Err(ErrorKind::SchemeTooLong.into());
}
// check that each byte in s is a SCHEME_CHARS which implies
// that it is a valid single byte UTF-8 code point.
for &b in s {
match SCHEME_CHARS[b as usize] {
b':' => {
// Don't want :// here
return Err(ErrorKind::InvalidScheme.into());
}
0 => {
return Err(ErrorKind::InvalidScheme.into());
}
_ => {}
}
}
Ok(Scheme2::Other(()))
}
}
}
pub(super) fn parse(s: &[u8]) -> Result<Scheme2<usize>, InvalidUri> {
if s.len() >= 7 {
// Check for HTTP
if s[..7].eq_ignore_ascii_case(b"http://") {
// Prefix will be striped
return Ok(Protocol::Http.into());
}
}
if s.len() >= 8 {
// Check for HTTPs
if s[..8].eq_ignore_ascii_case(b"https://") {
return Ok(Protocol::Https.into());
}
}
if s.len() > 3 {
for i in 0..s.len() {
let b = s[i];
match SCHEME_CHARS[b as usize] {
b':' => {
// Not enough data remaining
if s.len() < i + 3 {
break;
}
// Not a scheme
if &s[i + 1..i + 3] != b"//" {
break;
}
if i > MAX_SCHEME_LEN {
return Err(ErrorKind::SchemeTooLong.into());
}
// Return scheme
return Ok(Scheme2::Other(i));
}
// Invald scheme character, abort
0 => break,
_ => {}
}
}
}
Ok(Scheme2::None)
}
}
impl Protocol {
pub(super) fn len(&self) -> usize {
match *self {
Protocol::Http => 4,
Protocol::Https => 5,
}
}
}
impl<T> From<Protocol> for Scheme2<T> {
fn from(src: Protocol) -> Self {
Scheme2::Standard(src)
}
}
#[doc(hidden)]
impl From<Scheme2> for Scheme {
fn from(src: Scheme2) -> Self {
Scheme { inner: src }
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn scheme_eq_to_str() {
assert_eq!(&scheme("http"), "http");
assert_eq!(&scheme("https"), "https");
assert_eq!(&scheme("ftp"), "ftp");
assert_eq!(&scheme("my+funky+scheme"), "my+funky+scheme");
}
#[test]
fn invalid_scheme_is_error() {
Scheme::try_from("my_funky_scheme").expect_err("Unexpectly valid Scheme");
// Invalid UTF-8
Scheme::try_from([0xC0].as_ref()).expect_err("Unexpectly valid Scheme");
}
fn scheme(s: &str) -> Scheme {
s.parse().expect(&format!("Invalid scheme: {}", s))
}
}

519
zeroidc/vendor/http/src/uri/tests.rs vendored Normal file
View File

@@ -0,0 +1,519 @@
use std::str::FromStr;
use super::{ErrorKind, InvalidUri, Port, Uri, URI_CHARS};
#[test]
fn test_char_table() {
for (i, &v) in URI_CHARS.iter().enumerate() {
if v != 0 {
assert_eq!(i, v as usize);
}
}
}
macro_rules! part {
($s:expr) => {
Some(&$s.parse().unwrap())
};
}
macro_rules! test_parse {
(
$test_name:ident,
$str:expr,
$alt:expr,
$($method:ident = $value:expr,)*
) => (
#[test]
fn $test_name() {
let orig_str = $str;
let uri = match Uri::from_str(orig_str) {
Ok(uri) => uri,
Err(err) => {
panic!("parse error {:?} from {:?}", err, orig_str);
},
};
$(
assert_eq!(uri.$method(), $value, "{}: uri = {:?}", stringify!($method), uri);
)+
assert_eq!(uri, orig_str, "partial eq to original str");
assert_eq!(uri, uri.clone(), "clones are equal");
let new_str = uri.to_string();
let new_uri = Uri::from_str(&new_str).expect("to_string output parses again as a Uri");
assert_eq!(new_uri, orig_str, "round trip still equals original str");
const ALT: &'static [&'static str] = &$alt;
for &alt in ALT.iter() {
let other: Uri = alt.parse().unwrap();
assert_eq!(uri, *alt);
assert_eq!(uri, other);
}
}
);
}
test_parse! {
test_uri_parse_path_and_query,
"/some/path/here?and=then&hello#and-bye",
[],
scheme = None,
authority = None,
path = "/some/path/here",
query = Some("and=then&hello"),
host = None,
}
test_parse! {
test_uri_parse_absolute_form,
"http://127.0.0.1:61761/chunks",
[],
scheme = part!("http"),
authority = part!("127.0.0.1:61761"),
path = "/chunks",
query = None,
host = Some("127.0.0.1"),
port = Port::from_str("61761").ok(),
}
test_parse! {
test_uri_parse_absolute_form_without_path,
"https://127.0.0.1:61761",
["https://127.0.0.1:61761/"],
scheme = part!("https"),
authority = part!("127.0.0.1:61761"),
path = "/",
query = None,
host = Some("127.0.0.1"),
port = Port::from_str("61761").ok(),
}
test_parse! {
test_uri_parse_asterisk_form,
"*",
[],
scheme = None,
authority = None,
path = "*",
query = None,
host = None,
}
test_parse! {
test_uri_parse_authority_no_port,
"localhost",
["LOCALHOST", "LocaLHOSt"],
scheme = None,
authority = part!("localhost"),
path = "",
query = None,
port = None,
host = Some("localhost"),
}
test_parse! {
test_uri_authority_only_one_character_issue_197,
"S",
[],
scheme = None,
authority = part!("S"),
path = "",
query = None,
port = None,
host = Some("S"),
}
test_parse! {
test_uri_parse_authority_form,
"localhost:3000",
["localhosT:3000"],
scheme = None,
authority = part!("localhost:3000"),
path = "",
query = None,
host = Some("localhost"),
port = Port::from_str("3000").ok(),
}
test_parse! {
test_uri_parse_absolute_with_default_port_http,
"http://127.0.0.1:80",
["http://127.0.0.1:80/"],
scheme = part!("http"),
authority = part!("127.0.0.1:80"),
host = Some("127.0.0.1"),
path = "/",
query = None,
port = Port::from_str("80").ok(),
}
test_parse! {
test_uri_parse_absolute_with_default_port_https,
"https://127.0.0.1:443",
["https://127.0.0.1:443/"],
scheme = part!("https"),
authority = part!("127.0.0.1:443"),
host = Some("127.0.0.1"),
path = "/",
query = None,
port = Port::from_str("443").ok(),
}
test_parse! {
test_uri_parse_fragment_questionmark,
"http://127.0.0.1/#?",
[],
scheme = part!("http"),
authority = part!("127.0.0.1"),
host = Some("127.0.0.1"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_uri_parse_path_with_terminating_questionmark,
"http://127.0.0.1/path?",
[],
scheme = part!("http"),
authority = part!("127.0.0.1"),
path = "/path",
query = Some(""),
port = None,
}
test_parse! {
test_uri_parse_absolute_form_with_empty_path_and_nonempty_query,
"http://127.0.0.1?foo=bar",
[],
scheme = part!("http"),
authority = part!("127.0.0.1"),
path = "/",
query = Some("foo=bar"),
port = None,
}
test_parse! {
test_uri_parse_absolute_form_with_empty_path_and_fragment_with_slash,
"http://127.0.0.1#foo/bar",
[],
scheme = part!("http"),
authority = part!("127.0.0.1"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_uri_parse_absolute_form_with_empty_path_and_fragment_with_questionmark,
"http://127.0.0.1#foo?bar",
[],
scheme = part!("http"),
authority = part!("127.0.0.1"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_uri_parse_long_host_with_no_scheme,
"thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost",
[],
scheme = None,
authority = part!("thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost"),
path = "",
query = None,
port = None,
}
test_parse! {
test_uri_parse_long_host_with_port_and_no_scheme,
"thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost:1234",
[],
scheme = None,
authority = part!("thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost:1234"),
path = "",
query = None,
port = Port::from_str("1234").ok(),
}
test_parse! {
test_userinfo1,
"http://a:b@127.0.0.1:1234/",
[],
scheme = part!("http"),
authority = part!("a:b@127.0.0.1:1234"),
host = Some("127.0.0.1"),
path = "/",
query = None,
port = Port::from_str("1234").ok(),
}
test_parse! {
test_userinfo2,
"http://a:b@127.0.0.1/",
[],
scheme = part!("http"),
authority = part!("a:b@127.0.0.1"),
host = Some("127.0.0.1"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_userinfo3,
"http://a@127.0.0.1/",
[],
scheme = part!("http"),
authority = part!("a@127.0.0.1"),
host = Some("127.0.0.1"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_userinfo_with_port,
"user@localhost:3000",
[],
scheme = None,
authority = part!("user@localhost:3000"),
path = "",
query = None,
host = Some("localhost"),
port = Port::from_str("3000").ok(),
}
test_parse! {
test_userinfo_pass_with_port,
"user:pass@localhost:3000",
[],
scheme = None,
authority = part!("user:pass@localhost:3000"),
path = "",
query = None,
host = Some("localhost"),
port = Port::from_str("3000").ok(),
}
test_parse! {
test_ipv6,
"http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/",
[],
scheme = part!("http"),
authority = part!("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"),
host = Some("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_ipv6_shorthand,
"http://[::1]/",
[],
scheme = part!("http"),
authority = part!("[::1]"),
host = Some("[::1]"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_ipv6_shorthand2,
"http://[::]/",
[],
scheme = part!("http"),
authority = part!("[::]"),
host = Some("[::]"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_ipv6_shorthand3,
"http://[2001:db8::2:1]/",
[],
scheme = part!("http"),
authority = part!("[2001:db8::2:1]"),
host = Some("[2001:db8::2:1]"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_ipv6_with_port,
"http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008/",
[],
scheme = part!("http"),
authority = part!("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008"),
host = Some("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"),
path = "/",
query = None,
port = Port::from_str("8008").ok(),
}
test_parse! {
test_percentage_encoded_path,
"/echo/abcdefgh_i-j%20/abcdefg_i-j%20478",
[],
scheme = None,
authority = None,
host = None,
path = "/echo/abcdefgh_i-j%20/abcdefg_i-j%20478",
query = None,
port = None,
}
test_parse! {
test_path_permissive,
"/foo=bar|baz\\^~%",
[],
path = "/foo=bar|baz\\^~%",
}
test_parse! {
test_query_permissive,
"/?foo={bar|baz}\\^`",
[],
query = Some("foo={bar|baz}\\^`"),
}
#[test]
fn test_uri_parse_error() {
fn err(s: &str) {
Uri::from_str(s).unwrap_err();
}
err("http://");
err("htt:p//host");
err("hyper.rs/");
err("hyper.rs?key=val");
err("?key=val");
err("localhost/");
err("localhost?key=val");
err("\0");
err("http://[::1");
err("http://::1]");
err("localhost:8080:3030");
err("@");
err("http://username:password@/wut");
// illegal queries
err("/?foo\rbar");
err("/?foo\nbar");
err("/?<");
err("/?>");
}
#[test]
fn test_max_uri_len() {
let mut uri = vec![];
uri.extend(b"http://localhost/");
uri.extend(vec![b'a'; 70 * 1024]);
let uri = String::from_utf8(uri).unwrap();
let res: Result<Uri, InvalidUri> = uri.parse();
assert_eq!(res.unwrap_err().0, ErrorKind::TooLong);
}
#[test]
fn test_overflowing_scheme() {
let mut uri = vec![];
uri.extend(vec![b'a'; 256]);
uri.extend(b"://localhost/");
let uri = String::from_utf8(uri).unwrap();
let res: Result<Uri, InvalidUri> = uri.parse();
assert_eq!(res.unwrap_err().0, ErrorKind::SchemeTooLong);
}
#[test]
fn test_max_length_scheme() {
let mut uri = vec![];
uri.extend(vec![b'a'; 64]);
uri.extend(b"://localhost/");
let uri = String::from_utf8(uri).unwrap();
let uri: Uri = uri.parse().unwrap();
assert_eq!(uri.scheme_str().unwrap().len(), 64);
}
#[test]
fn test_uri_to_path_and_query() {
let cases = vec![
("/", "/"),
("/foo?bar", "/foo?bar"),
("/foo?bar#nope", "/foo?bar"),
("http://hyper.rs", "/"),
("http://hyper.rs/", "/"),
("http://hyper.rs/path", "/path"),
("http://hyper.rs?query", "/?query"),
("*", "*"),
];
for case in cases {
let uri = Uri::from_str(case.0).unwrap();
let s = uri.path_and_query().unwrap().to_string();
assert_eq!(s, case.1);
}
}
#[test]
fn test_authority_uri_parts_round_trip() {
let s = "hyper.rs";
let uri = Uri::from_str(s).expect("first parse");
assert_eq!(uri, s);
assert_eq!(uri.to_string(), s);
let parts = uri.into_parts();
let uri2 = Uri::from_parts(parts).expect("from_parts");
assert_eq!(uri2, s);
assert_eq!(uri2.to_string(), s);
}
#[test]
fn test_partial_eq_path_with_terminating_questionmark() {
let a = "/path";
let uri = Uri::from_str("/path?").expect("first parse");
assert_eq!(uri, a);
}

75
zeroidc/vendor/http/src/version.rs vendored Normal file
View File

@@ -0,0 +1,75 @@
//! HTTP version
//!
//! This module contains a definition of the `Version` type. The `Version`
//! type is intended to be accessed through the root of the crate
//! (`http::Version`) rather than this module.
//!
//! The `Version` type contains constants that represent the various versions
//! of the HTTP protocol.
//!
//! # Examples
//!
//! ```
//! use http::Version;
//!
//! let http11 = Version::HTTP_11;
//! let http2 = Version::HTTP_2;
//! assert!(http11 != http2);
//!
//! println!("{:?}", http2);
//! ```
use std::fmt;
/// Represents a version of the HTTP spec.
#[derive(PartialEq, PartialOrd, Copy, Clone, Eq, Ord, Hash)]
pub struct Version(Http);
impl Version {
/// `HTTP/0.9`
pub const HTTP_09: Version = Version(Http::Http09);
/// `HTTP/1.0`
pub const HTTP_10: Version = Version(Http::Http10);
/// `HTTP/1.1`
pub const HTTP_11: Version = Version(Http::Http11);
/// `HTTP/2.0`
pub const HTTP_2: Version = Version(Http::H2);
/// `HTTP/3.0`
pub const HTTP_3: Version = Version(Http::H3);
}
#[derive(PartialEq, PartialOrd, Copy, Clone, Eq, Ord, Hash)]
enum Http {
Http09,
Http10,
Http11,
H2,
H3,
__NonExhaustive,
}
impl Default for Version {
#[inline]
fn default() -> Version {
Version::HTTP_11
}
}
impl fmt::Debug for Version {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::Http::*;
f.write_str(match self.0 {
Http09 => "HTTP/0.9",
Http10 => "HTTP/1.0",
Http11 => "HTTP/1.1",
H2 => "HTTP/2.0",
H3 => "HTTP/3.0",
__NonExhaustive => unreachable!(),
})
}
}

636
zeroidc/vendor/http/tests/header_map.rs vendored Normal file
View File

@@ -0,0 +1,636 @@
use http::header::*;
use http::*;
#[test]
fn smoke() {
let mut headers = HeaderMap::new();
assert!(headers.get("hello").is_none());
let name: HeaderName = "hello".parse().unwrap();
match headers.entry(&name) {
Entry::Vacant(e) => {
e.insert("world".parse().unwrap());
}
_ => panic!(),
}
assert!(headers.get("hello").is_some());
match headers.entry(&name) {
Entry::Occupied(mut e) => {
assert_eq!(e.get(), &"world");
// Push another value
e.append("zomg".parse().unwrap());
let mut i = e.iter();
assert_eq!(*i.next().unwrap(), "world");
assert_eq!(*i.next().unwrap(), "zomg");
assert!(i.next().is_none());
}
_ => panic!(),
}
}
#[test]
#[should_panic]
fn reserve_over_capacity() {
// See https://github.com/hyperium/http/issues/352
let mut headers = HeaderMap::<u32>::with_capacity(32);
headers.reserve(50_000); // over MAX_SIZE
}
#[test]
fn with_capacity_max() {
// The largest capacity such that (cap + cap / 3) < MAX_SIZE.
HeaderMap::<u32>::with_capacity(24_576);
}
#[test]
#[should_panic]
fn with_capacity_overflow() {
HeaderMap::<u32>::with_capacity(24_577);
}
#[test]
#[should_panic]
fn reserve_overflow() {
// See https://github.com/hyperium/http/issues/352
let mut headers = HeaderMap::<u32>::with_capacity(0);
headers.reserve(std::usize::MAX); // next_power_of_two overflows
}
#[test]
fn drain() {
let mut headers = HeaderMap::new();
// Insert a single value
let name: HeaderName = "hello".parse().unwrap();
headers.insert(name, "world".parse().unwrap());
{
let mut iter = headers.drain();
let (name, value) = iter.next().unwrap();
assert_eq!(name.unwrap().as_str(), "hello");
assert_eq!(value, "world");
assert!(iter.next().is_none());
}
assert!(headers.is_empty());
// Insert two sequential values
headers.insert(
"hello".parse::<HeaderName>().unwrap(),
"world".parse().unwrap(),
);
headers.insert(
"zomg".parse::<HeaderName>().unwrap(),
"bar".parse().unwrap(),
);
headers.append(
"hello".parse::<HeaderName>().unwrap(),
"world2".parse().unwrap(),
);
// Drain...
{
let mut iter = headers.drain();
let (name, value) = iter.next().unwrap();
assert_eq!(name.unwrap().as_str(), "hello");
assert_eq!(value, "world");
let (name, value) = iter.next().unwrap();
assert_eq!(name, None);
assert_eq!(value, "world2");
let (name, value) = iter.next().unwrap();
assert_eq!(name.unwrap().as_str(), "zomg");
assert_eq!(value, "bar");
assert!(iter.next().is_none());
}
}
#[test]
fn drain_drop_immediately() {
// test mem::forgetting does not double-free
let mut headers = HeaderMap::new();
headers.insert("hello", "world".parse().unwrap());
headers.insert("zomg", "bar".parse().unwrap());
headers.append("hello", "world2".parse().unwrap());
let iter = headers.drain();
assert_eq!(iter.size_hint(), (2, Some(3)));
// not consuming `iter`
}
#[test]
fn drain_forget() {
// test mem::forgetting does not double-free
let mut headers = HeaderMap::<HeaderValue>::new();
headers.insert("hello", "world".parse().unwrap());
headers.insert("zomg", "bar".parse().unwrap());
assert_eq!(headers.len(), 2);
{
let mut iter = headers.drain();
assert_eq!(iter.size_hint(), (2, Some(2)));
let _ = iter.next().unwrap();
std::mem::forget(iter);
}
assert_eq!(headers.len(), 0);
}
#[test]
fn drain_entry() {
let mut headers = HeaderMap::new();
headers.insert(
"hello".parse::<HeaderName>().unwrap(),
"world".parse().unwrap(),
);
headers.insert(
"zomg".parse::<HeaderName>().unwrap(),
"foo".parse().unwrap(),
);
headers.append(
"hello".parse::<HeaderName>().unwrap(),
"world2".parse().unwrap(),
);
headers.insert(
"more".parse::<HeaderName>().unwrap(),
"words".parse().unwrap(),
);
headers.append(
"more".parse::<HeaderName>().unwrap(),
"insertions".parse().unwrap(),
);
assert_eq!(5, headers.len());
// Using insert_mult
{
let mut e = match headers.entry("hello") {
Entry::Occupied(e) => e,
_ => panic!(),
};
let vals: Vec<_> = e.insert_mult("wat".parse().unwrap()).collect();
assert_eq!(2, vals.len());
assert_eq!(vals[0], "world");
assert_eq!(vals[1], "world2");
}
assert_eq!(5-2+1, headers.len());
}
#[test]
fn eq() {
let mut a = HeaderMap::new();
let mut b = HeaderMap::new();
assert_eq!(a, b);
a.insert(
"hello".parse::<HeaderName>().unwrap(),
"world".parse().unwrap(),
);
assert_ne!(a, b);
b.insert(
"hello".parse::<HeaderName>().unwrap(),
"world".parse().unwrap(),
);
assert_eq!(a, b);
a.insert("foo".parse::<HeaderName>().unwrap(), "bar".parse().unwrap());
a.append("foo".parse::<HeaderName>().unwrap(), "baz".parse().unwrap());
assert_ne!(a, b);
b.insert("foo".parse::<HeaderName>().unwrap(), "bar".parse().unwrap());
assert_ne!(a, b);
b.append("foo".parse::<HeaderName>().unwrap(), "baz".parse().unwrap());
assert_eq!(a, b);
a.append("a".parse::<HeaderName>().unwrap(), "a".parse().unwrap());
a.append("a".parse::<HeaderName>().unwrap(), "b".parse().unwrap());
b.append("a".parse::<HeaderName>().unwrap(), "b".parse().unwrap());
b.append("a".parse::<HeaderName>().unwrap(), "a".parse().unwrap());
assert_ne!(a, b);
}
#[test]
fn into_header_name() {
let mut m = HeaderMap::new();
m.insert(HOST, "localhost".parse().unwrap());
m.insert(&ACCEPT, "*/*".parse().unwrap());
m.insert("connection", "keep-alive".parse().unwrap());
m.append(LOCATION, "/".parse().unwrap());
m.append(&VIA, "bob".parse().unwrap());
m.append("transfer-encoding", "chunked".parse().unwrap());
assert_eq!(m.len(), 6);
}
#[test]
fn as_header_name() {
let mut m = HeaderMap::new();
let v: HeaderValue = "localhost".parse().unwrap();
m.insert(HOST, v.clone());
let expected = Some(&v);
assert_eq!(m.get("host"), expected);
assert_eq!(m.get(&HOST), expected);
let s = String::from("host");
assert_eq!(m.get(&s), expected);
assert_eq!(m.get(s.as_str()), expected);
}
#[test]
fn insert_all_std_headers() {
let mut m = HeaderMap::new();
for (i, hdr) in STD.iter().enumerate() {
m.insert(hdr.clone(), hdr.as_str().parse().unwrap());
for j in 0..(i + 1) {
assert_eq!(m[&STD[j]], STD[j].as_str());
}
if i != 0 {
for j in (i + 1)..STD.len() {
assert!(
m.get(&STD[j]).is_none(),
"contained {}; j={}",
STD[j].as_str(),
j
);
}
}
}
}
#[test]
fn insert_79_custom_std_headers() {
let mut h = HeaderMap::new();
let hdrs = custom_std(79);
for (i, hdr) in hdrs.iter().enumerate() {
h.insert(hdr.clone(), hdr.as_str().parse().unwrap());
for j in 0..(i + 1) {
assert_eq!(h[&hdrs[j]], hdrs[j].as_str());
}
for j in (i + 1)..hdrs.len() {
assert!(h.get(&hdrs[j]).is_none());
}
}
}
#[test]
fn append_multiple_values() {
let mut map = HeaderMap::new();
map.append(header::CONTENT_TYPE, "json".parse().unwrap());
map.append(header::CONTENT_TYPE, "html".parse().unwrap());
map.append(header::CONTENT_TYPE, "xml".parse().unwrap());
let vals = map
.get_all(&header::CONTENT_TYPE)
.iter()
.collect::<Vec<_>>();
assert_eq!(&vals, &[&"json", &"html", &"xml"]);
}
fn custom_std(n: usize) -> Vec<HeaderName> {
(0..n)
.map(|i| {
let s = format!("{}-{}", STD[i % STD.len()].as_str(), i);
s.parse().unwrap()
})
.collect()
}
const STD: &'static [HeaderName] = &[
ACCEPT,
ACCEPT_CHARSET,
ACCEPT_ENCODING,
ACCEPT_LANGUAGE,
ACCEPT_RANGES,
ACCESS_CONTROL_ALLOW_CREDENTIALS,
ACCESS_CONTROL_ALLOW_HEADERS,
ACCESS_CONTROL_ALLOW_METHODS,
ACCESS_CONTROL_ALLOW_ORIGIN,
ACCESS_CONTROL_EXPOSE_HEADERS,
ACCESS_CONTROL_MAX_AGE,
ACCESS_CONTROL_REQUEST_HEADERS,
ACCESS_CONTROL_REQUEST_METHOD,
AGE,
ALLOW,
ALT_SVC,
AUTHORIZATION,
CACHE_CONTROL,
CONNECTION,
CONTENT_DISPOSITION,
CONTENT_ENCODING,
CONTENT_LANGUAGE,
CONTENT_LENGTH,
CONTENT_LOCATION,
CONTENT_RANGE,
CONTENT_SECURITY_POLICY,
CONTENT_SECURITY_POLICY_REPORT_ONLY,
CONTENT_TYPE,
COOKIE,
DNT,
DATE,
ETAG,
EXPECT,
EXPIRES,
FORWARDED,
FROM,
HOST,
IF_MATCH,
IF_MODIFIED_SINCE,
IF_NONE_MATCH,
IF_RANGE,
IF_UNMODIFIED_SINCE,
LAST_MODIFIED,
LINK,
LOCATION,
MAX_FORWARDS,
ORIGIN,
PRAGMA,
PROXY_AUTHENTICATE,
PROXY_AUTHORIZATION,
PUBLIC_KEY_PINS,
PUBLIC_KEY_PINS_REPORT_ONLY,
RANGE,
REFERER,
REFERRER_POLICY,
RETRY_AFTER,
SERVER,
SET_COOKIE,
STRICT_TRANSPORT_SECURITY,
TE,
TRAILER,
TRANSFER_ENCODING,
USER_AGENT,
UPGRADE,
UPGRADE_INSECURE_REQUESTS,
VARY,
VIA,
WARNING,
WWW_AUTHENTICATE,
X_CONTENT_TYPE_OPTIONS,
X_DNS_PREFETCH_CONTROL,
X_FRAME_OPTIONS,
X_XSS_PROTECTION,
];
#[test]
fn get_invalid() {
let mut headers = HeaderMap::new();
headers.insert("foo", "bar".parse().unwrap());
assert!(headers.get("Evil\r\nKey").is_none());
}
#[test]
#[should_panic]
fn insert_invalid() {
let mut headers = HeaderMap::new();
headers.insert("evil\r\nfoo", "bar".parse().unwrap());
}
#[test]
fn value_htab() {
// RFC 7230 Section 3.2:
// > field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
HeaderValue::from_static("hello\tworld");
HeaderValue::from_str("hello\tworld").unwrap();
}
#[test]
fn remove_multiple_a() {
let mut headers = HeaderMap::new();
headers.insert(VIA, "1.1 example.com".parse().unwrap());
headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap());
headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap());
headers.append(VIA, "1.1 other.com".parse().unwrap());
headers.append(SET_COOKIE, "cookie_3=value 3".parse().unwrap());
headers.insert(VARY, "*".parse().unwrap());
assert_eq!(headers.len(), 6);
let cookie = headers.remove(SET_COOKIE);
assert_eq!(cookie, Some("cookie_1=value 1".parse().unwrap()));
assert_eq!(headers.len(), 3);
let via = headers.remove(VIA);
assert_eq!(via, Some("1.1 example.com".parse().unwrap()));
assert_eq!(headers.len(), 1);
let vary = headers.remove(VARY);
assert_eq!(vary, Some("*".parse().unwrap()));
assert_eq!(headers.len(), 0);
}
#[test]
fn remove_multiple_b() {
let mut headers = HeaderMap::new();
headers.insert(VIA, "1.1 example.com".parse().unwrap());
headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap());
headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap());
headers.append(VIA, "1.1 other.com".parse().unwrap());
headers.append(SET_COOKIE, "cookie_3=value 3".parse().unwrap());
headers.insert(VARY, "*".parse().unwrap());
assert_eq!(headers.len(), 6);
let vary = headers.remove(VARY);
assert_eq!(vary, Some("*".parse().unwrap()));
assert_eq!(headers.len(), 5);
let via = headers.remove(VIA);
assert_eq!(via, Some("1.1 example.com".parse().unwrap()));
assert_eq!(headers.len(), 3);
let cookie = headers.remove(SET_COOKIE);
assert_eq!(cookie, Some("cookie_1=value 1".parse().unwrap()));
assert_eq!(headers.len(), 0);
}
#[test]
fn remove_entry_multi_0() {
let mut headers = HeaderMap::new();
let cookies = remove_all_values(&mut headers, SET_COOKIE);
assert_eq!(cookies.len(), 0);
assert_eq!(headers.len(), 0);
}
#[test]
fn remove_entry_multi_0_others() {
let mut headers = HeaderMap::new();
headers.insert(VIA, "1.1 example.com".parse().unwrap());
headers.append(VIA, "1.1 other.com".parse().unwrap());
let cookies = remove_all_values(&mut headers, SET_COOKIE);
assert_eq!(cookies.len(), 0);
assert_eq!(headers.len(), 2);
}
#[test]
fn remove_entry_multi_1() {
let mut headers = HeaderMap::new();
headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap());
let cookies = remove_all_values(&mut headers, SET_COOKIE);
assert_eq!(cookies.len(), 1);
assert_eq!(headers.len(), 0);
}
#[test]
fn remove_entry_multi_1_other() {
let mut headers = HeaderMap::new();
headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap());
headers.insert(VIA, "1.1 example.com".parse().unwrap());
let cookies = remove_all_values(&mut headers, SET_COOKIE);
assert_eq!(cookies.len(), 1);
assert_eq!(headers.len(), 1);
let vias = remove_all_values(&mut headers, VIA);
assert_eq!(vias.len(), 1);
assert_eq!(headers.len(), 0);
}
// For issue hyperimum/http#446
#[test]
fn remove_entry_multi_2() {
let mut headers = HeaderMap::new();
headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap());
headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap());
let cookies = remove_all_values(&mut headers, SET_COOKIE);
assert_eq!(cookies.len(), 2);
assert_eq!(headers.len(), 0);
}
#[test]
fn remove_entry_multi_3() {
let mut headers = HeaderMap::new();
headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap());
headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap());
headers.append(SET_COOKIE, "cookie_3=value 3".parse().unwrap());
let cookies = remove_all_values(&mut headers, SET_COOKIE);
assert_eq!(cookies.len(), 3);
assert_eq!(headers.len(), 0);
}
#[test]
fn remove_entry_multi_3_others() {
let mut headers = HeaderMap::new();
headers.insert(VIA, "1.1 example.com".parse().unwrap());
headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap());
headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap());
headers.append(VIA, "1.1 other.com".parse().unwrap());
headers.append(SET_COOKIE, "cookie_3=value 3".parse().unwrap());
headers.insert(VARY, "*".parse().unwrap());
let cookies = remove_all_values(&mut headers, SET_COOKIE);
assert_eq!(cookies.len(), 3);
assert_eq!(headers.len(), 3);
let vias = remove_all_values(&mut headers, VIA);
assert_eq!(vias.len(), 2);
assert_eq!(headers.len(), 1);
let varies = remove_all_values(&mut headers, VARY);
assert_eq!(varies.len(), 1);
assert_eq!(headers.len(), 0);
}
fn remove_all_values<K>(headers: &mut HeaderMap, key: K) -> Vec<HeaderValue>
where K: IntoHeaderName
{
match headers.entry(key) {
Entry::Occupied(e) => e.remove_entry_mult().1.collect(),
Entry::Vacant(_) => vec![],
}
}
#[test]
fn remove_entry_3_others_a() {
let mut headers = HeaderMap::new();
headers.insert(VIA, "1.1 example.com".parse().unwrap());
headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap());
headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap());
headers.append(VIA, "1.1 other.com".parse().unwrap());
headers.append(SET_COOKIE, "cookie_3=value 3".parse().unwrap());
headers.insert(VARY, "*".parse().unwrap());
assert_eq!(headers.len(), 6);
let cookie = remove_values(&mut headers, SET_COOKIE);
assert_eq!(cookie, Some("cookie_1=value 1".parse().unwrap()));
assert_eq!(headers.len(), 3);
let via = remove_values(&mut headers, VIA);
assert_eq!(via, Some("1.1 example.com".parse().unwrap()));
assert_eq!(headers.len(), 1);
let vary = remove_values(&mut headers, VARY);
assert_eq!(vary, Some("*".parse().unwrap()));
assert_eq!(headers.len(), 0);
}
#[test]
fn remove_entry_3_others_b() {
let mut headers = HeaderMap::new();
headers.insert(VIA, "1.1 example.com".parse().unwrap());
headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap());
headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap());
headers.append(VIA, "1.1 other.com".parse().unwrap());
headers.append(SET_COOKIE, "cookie_3=value 3".parse().unwrap());
headers.insert(VARY, "*".parse().unwrap());
assert_eq!(headers.len(), 6);
let vary = remove_values(&mut headers, VARY);
assert_eq!(vary, Some("*".parse().unwrap()));
assert_eq!(headers.len(), 5);
let via = remove_values(&mut headers, VIA);
assert_eq!(via, Some("1.1 example.com".parse().unwrap()));
assert_eq!(headers.len(), 3);
let cookie = remove_values(&mut headers, SET_COOKIE);
assert_eq!(cookie, Some("cookie_1=value 1".parse().unwrap()));
assert_eq!(headers.len(), 0);
}
fn remove_values<K>(headers: &mut HeaderMap, key: K) -> Option<HeaderValue>
where K: IntoHeaderName
{
match headers.entry(key) {
Entry::Occupied(e) => Some(e.remove_entry().1),
Entry::Vacant(_) => None,
}
}

View File

@@ -0,0 +1,372 @@
use http::header::*;
use http::*;
use quickcheck::{Arbitrary, Gen, QuickCheck, TestResult};
use rand::rngs::StdRng;
use rand::seq::SliceRandom;
use rand::{Rng, SeedableRng};
use std::collections::HashMap;
#[test]
fn header_map_fuzz() {
fn prop(fuzz: Fuzz) -> TestResult {
fuzz.run();
TestResult::from_bool(true)
}
QuickCheck::new().quickcheck(prop as fn(Fuzz) -> TestResult)
}
#[derive(Debug, Clone)]
struct Fuzz {
// The magic seed that makes the test case reproducible
seed: [u8; 32],
// Actions to perform
steps: Vec<Step>,
// Number of steps to drop
reduce: usize,
}
#[derive(Debug)]
struct Weight {
insert: usize,
remove: usize,
append: usize,
}
#[derive(Debug, Clone)]
struct Step {
action: Action,
expect: AltMap,
}
#[derive(Debug, Clone)]
enum Action {
Insert {
name: HeaderName, // Name to insert
val: HeaderValue, // Value to insert
old: Option<HeaderValue>, // Old value
},
Append {
name: HeaderName,
val: HeaderValue,
ret: bool,
},
Remove {
name: HeaderName, // Name to remove
val: Option<HeaderValue>, // Value to get
},
}
// An alternate implementation of HeaderMap backed by HashMap
#[derive(Debug, Clone, Default)]
struct AltMap {
map: HashMap<HeaderName, Vec<HeaderValue>>,
}
impl Fuzz {
fn new(seed: [u8; 32]) -> Fuzz {
// Seed the RNG
let mut rng = StdRng::from_seed(seed);
let mut steps = vec![];
let mut expect = AltMap::default();
let num = rng.gen_range(5, 500);
let weight = Weight {
insert: rng.gen_range(1, 10),
remove: rng.gen_range(1, 10),
append: rng.gen_range(1, 10),
};
while steps.len() < num {
steps.push(expect.gen_step(&weight, &mut rng));
}
Fuzz {
seed: seed,
steps: steps,
reduce: 0,
}
}
fn run(self) {
// Create a new header map
let mut map = HeaderMap::new();
// Number of steps to perform
let take = self.steps.len() - self.reduce;
for step in self.steps.into_iter().take(take) {
step.action.apply(&mut map);
step.expect.assert_identical(&map);
}
}
}
impl Arbitrary for Fuzz {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
Fuzz::new(Rng::gen(g))
}
}
impl AltMap {
fn gen_step(&mut self, weight: &Weight, rng: &mut StdRng) -> Step {
let action = self.gen_action(weight, rng);
Step {
action: action,
expect: self.clone(),
}
}
/// This will also apply the action against `self`
fn gen_action(&mut self, weight: &Weight, rng: &mut StdRng) -> Action {
let sum = weight.insert + weight.remove + weight.append;
let mut num = rng.gen_range(0, sum);
if num < weight.insert {
return self.gen_insert(rng);
}
num -= weight.insert;
if num < weight.remove {
return self.gen_remove(rng);
}
num -= weight.remove;
if num < weight.append {
return self.gen_append(rng);
}
unreachable!();
}
fn gen_insert(&mut self, rng: &mut StdRng) -> Action {
let name = self.gen_name(4, rng);
let val = gen_header_value(rng);
let old = self.insert(name.clone(), val.clone());
Action::Insert {
name: name,
val: val,
old: old,
}
}
fn gen_remove(&mut self, rng: &mut StdRng) -> Action {
let name = self.gen_name(-4, rng);
let val = self.remove(&name);
Action::Remove {
name: name,
val: val,
}
}
fn gen_append(&mut self, rng: &mut StdRng) -> Action {
let name = self.gen_name(-5, rng);
let val = gen_header_value(rng);
let vals = self.map.entry(name.clone()).or_insert(vec![]);
let ret = !vals.is_empty();
vals.push(val.clone());
Action::Append {
name: name,
val: val,
ret: ret,
}
}
/// Negative numbers weigh finding an existing header higher
fn gen_name(&self, weight: i32, rng: &mut StdRng) -> HeaderName {
let mut existing = rng.gen_ratio(1, weight.abs() as u32);
if weight < 0 {
existing = !existing;
}
if existing {
// Existing header
if let Some(name) = self.find_random_name(rng) {
name
} else {
gen_header_name(rng)
}
} else {
gen_header_name(rng)
}
}
fn find_random_name(&self, rng: &mut StdRng) -> Option<HeaderName> {
if self.map.is_empty() {
None
} else {
let n = rng.gen_range(0, self.map.len());
self.map.keys().nth(n).map(Clone::clone)
}
}
fn insert(&mut self, name: HeaderName, val: HeaderValue) -> Option<HeaderValue> {
let old = self.map.insert(name, vec![val]);
old.and_then(|v| v.into_iter().next())
}
fn remove(&mut self, name: &HeaderName) -> Option<HeaderValue> {
self.map.remove(name).and_then(|v| v.into_iter().next())
}
fn assert_identical(&self, other: &HeaderMap<HeaderValue>) {
assert_eq!(self.map.len(), other.keys_len());
for (key, val) in &self.map {
// Test get
assert_eq!(other.get(key), val.get(0));
// Test get_all
let vals = other.get_all(key);
let actual: Vec<_> = vals.iter().collect();
assert_eq!(&actual[..], &val[..]);
}
}
}
impl Action {
fn apply(self, map: &mut HeaderMap<HeaderValue>) {
match self {
Action::Insert { name, val, old } => {
let actual = map.insert(name, val);
assert_eq!(actual, old);
}
Action::Remove { name, val } => {
// Just to help track the state, load all associated values.
let _ = map.get_all(&name).iter().collect::<Vec<_>>();
let actual = map.remove(&name);
assert_eq!(actual, val);
}
Action::Append { name, val, ret } => {
assert_eq!(ret, map.append(name, val));
}
}
}
}
fn gen_header_name(g: &mut StdRng) -> HeaderName {
const STANDARD_HEADERS: &'static [HeaderName] = &[
header::ACCEPT,
header::ACCEPT_CHARSET,
header::ACCEPT_ENCODING,
header::ACCEPT_LANGUAGE,
header::ACCEPT_RANGES,
header::ACCESS_CONTROL_ALLOW_CREDENTIALS,
header::ACCESS_CONTROL_ALLOW_HEADERS,
header::ACCESS_CONTROL_ALLOW_METHODS,
header::ACCESS_CONTROL_ALLOW_ORIGIN,
header::ACCESS_CONTROL_EXPOSE_HEADERS,
header::ACCESS_CONTROL_MAX_AGE,
header::ACCESS_CONTROL_REQUEST_HEADERS,
header::ACCESS_CONTROL_REQUEST_METHOD,
header::AGE,
header::ALLOW,
header::ALT_SVC,
header::AUTHORIZATION,
header::CACHE_CONTROL,
header::CONNECTION,
header::CONTENT_DISPOSITION,
header::CONTENT_ENCODING,
header::CONTENT_LANGUAGE,
header::CONTENT_LENGTH,
header::CONTENT_LOCATION,
header::CONTENT_RANGE,
header::CONTENT_SECURITY_POLICY,
header::CONTENT_SECURITY_POLICY_REPORT_ONLY,
header::CONTENT_TYPE,
header::COOKIE,
header::DNT,
header::DATE,
header::ETAG,
header::EXPECT,
header::EXPIRES,
header::FORWARDED,
header::FROM,
header::HOST,
header::IF_MATCH,
header::IF_MODIFIED_SINCE,
header::IF_NONE_MATCH,
header::IF_RANGE,
header::IF_UNMODIFIED_SINCE,
header::LAST_MODIFIED,
header::LINK,
header::LOCATION,
header::MAX_FORWARDS,
header::ORIGIN,
header::PRAGMA,
header::PROXY_AUTHENTICATE,
header::PROXY_AUTHORIZATION,
header::PUBLIC_KEY_PINS,
header::PUBLIC_KEY_PINS_REPORT_ONLY,
header::RANGE,
header::REFERER,
header::REFERRER_POLICY,
header::REFRESH,
header::RETRY_AFTER,
header::SEC_WEBSOCKET_ACCEPT,
header::SEC_WEBSOCKET_EXTENSIONS,
header::SEC_WEBSOCKET_KEY,
header::SEC_WEBSOCKET_PROTOCOL,
header::SEC_WEBSOCKET_VERSION,
header::SERVER,
header::SET_COOKIE,
header::STRICT_TRANSPORT_SECURITY,
header::TE,
header::TRAILER,
header::TRANSFER_ENCODING,
header::UPGRADE,
header::UPGRADE_INSECURE_REQUESTS,
header::USER_AGENT,
header::VARY,
header::VIA,
header::WARNING,
header::WWW_AUTHENTICATE,
header::X_CONTENT_TYPE_OPTIONS,
header::X_DNS_PREFETCH_CONTROL,
header::X_FRAME_OPTIONS,
header::X_XSS_PROTECTION,
];
if g.gen_ratio(1, 2) {
STANDARD_HEADERS.choose(g).unwrap().clone()
} else {
let value = gen_string(g, 1, 25);
HeaderName::from_bytes(value.as_bytes()).unwrap()
}
}
fn gen_header_value(g: &mut StdRng) -> HeaderValue {
let value = gen_string(g, 0, 70);
HeaderValue::from_bytes(value.as_bytes()).unwrap()
}
fn gen_string(g: &mut StdRng, min: usize, max: usize) -> String {
let bytes: Vec<_> = (min..max)
.map(|_| {
// Chars to pick from
b"ABCDEFGHIJKLMNOPQRSTUVabcdefghilpqrstuvwxyz----"
.choose(g)
.unwrap()
.clone()
})
.collect();
String::from_utf8(bytes).unwrap()
}

View File

@@ -0,0 +1,82 @@
use http::*;
#[test]
fn from_bytes() {
for ok in &[
"100", "101", "199", "200", "250", "299", "321", "399", "499", "599", "600", "999"
] {
assert!(StatusCode::from_bytes(ok.as_bytes()).is_ok());
}
for not_ok in &[
"0", "00", "10", "40", "99", "000", "010", "099", "1000", "1999",
] {
assert!(StatusCode::from_bytes(not_ok.as_bytes()).is_err());
}
}
#[test]
fn equates_with_u16() {
let status = StatusCode::from_u16(200u16).unwrap();
assert_eq!(200u16, status);
assert_eq!(status, 200u16);
}
#[test]
fn roundtrip() {
for s in 100..1000 {
let sstr = s.to_string();
let status = StatusCode::from_bytes(sstr.as_bytes()).unwrap();
assert_eq!(s, u16::from(status));
assert_eq!(sstr, status.as_str());
}
}
#[test]
fn is_informational() {
assert!(status_code(100).is_informational());
assert!(status_code(199).is_informational());
assert!(!status_code(200).is_informational());
}
#[test]
fn is_success() {
assert!(status_code(200).is_success());
assert!(status_code(299).is_success());
assert!(!status_code(199).is_success());
assert!(!status_code(300).is_success());
}
#[test]
fn is_redirection() {
assert!(status_code(300).is_redirection());
assert!(status_code(399).is_redirection());
assert!(!status_code(299).is_redirection());
assert!(!status_code(400).is_redirection());
}
#[test]
fn is_client_error() {
assert!(status_code(400).is_client_error());
assert!(status_code(499).is_client_error());
assert!(!status_code(399).is_client_error());
assert!(!status_code(500).is_client_error());
}
#[test]
fn is_server_error() {
assert!(status_code(500).is_server_error());
assert!(status_code(599).is_server_error());
assert!(!status_code(499).is_server_error());
assert!(!status_code(600).is_server_error());
}
/// Helper method for readability
fn status_code(status_code: u16) -> StatusCode {
StatusCode::from_u16(status_code).unwrap()
}