[Pkg-rust-maintainers] Bug#988945: rust-http: diff for NMU version 0.1.21-0.1

Jonas Smedegaard dr at jones.dk
Sun Apr 10 20:42:56 BST 2022


Control: tags 988945 + patch
Control: tags 988945 + pending

Dear maintainer,

I've prepared an NMU for rust-http (versioned as 0.1.21-0.1) and
uploaded it without delay, due to current package being completely broken.


Regards,

 - Jonas

diff -Nru rust-http-0.1.19/Cargo.toml rust-http-0.1.21/Cargo.toml
--- rust-http-0.1.19/Cargo.toml	1970-01-01 01:00:00.000000000 +0100
+++ rust-http-0.1.21/Cargo.toml	2019-12-02 20:18:55.000000000 +0100
@@ -1,26 +1,38 @@
-# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
-#
-# When uploading crates to the registry Cargo will automatically
-# "normalize" Cargo.toml files for maximal compatibility
-# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
-#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
-
 [package]
 name = "http"
-version = "0.1.19"
-authors = ["Alex Crichton <alex at alexcrichton.com>", "Carl Lerche <me at carllerche.com>", "Sean McArthur <sean at seanmonstar.com>"]
-description = "A set of types for representing HTTP requests and responses.\n"
-documentation = "https://docs.rs/http"
+# When releasing to crates.io:
+# - Update html_root_url in lib.rs.
+# - Update CHANGELOG.md.
+# - Create git tag
+version = "0.1.21"
 readme = "README.md"
+documentation = "https://docs.rs/http"
+repository = "https://github.com/hyperium/http"
+license = "MIT/Apache-2.0"
+authors = [
+  "Alex Crichton <alex at alexcrichton.com>",
+  "Carl Lerche <me at carllerche.com>",
+  "Sean McArthur <sean at seanmonstar.com>",
+]
+description = """
+A set of types for representing HTTP requests and responses.
+"""
 keywords = ["http"]
 categories = ["web-programming"]
-license = "MIT/Apache-2.0"
-repository = "https://github.com/hyperium/http"
+
+[dependencies]
+bytes = "0.4"
+fnv = "1.0.5"
+itoa = "0.4.1"
+
+[dev-dependencies]
+indexmap = "1.0"
+quickcheck = "0.6"
+rand = "0.4"
+seahash = "3.0.5"
+serde = "1.0"
+serde_json = "1.0"
+doc-comment = "0.3"
 
 [[bench]]
 name = "header_map"
@@ -37,31 +49,3 @@
 [[bench]]
 name = "uri"
 path = "benches/uri.rs"
-[dependencies.bytes]
-version = "0.4"
-
-[dependencies.fnv]
-version = "1.0.5"
-
-[dependencies.itoa]
-version = "0.4.1"
-[dev-dependencies.doc-comment]
-version = "0.3"
-
-[dev-dependencies.indexmap]
-version = "1.0"
-
-[dev-dependencies.quickcheck]
-version = "0.6"
-
-[dev-dependencies.rand]
-version = "0.4"
-
-[dev-dependencies.seahash]
-version = "3.0.5"
-
-[dev-dependencies.serde]
-version = "1.0"
-
-[dev-dependencies.serde_json]
-version = "1.0"
diff -Nru rust-http-0.1.19/Cargo.toml.orig rust-http-0.1.21/Cargo.toml.orig
--- rust-http-0.1.19/Cargo.toml.orig	2019-10-15 20:44:13.000000000 +0200
+++ rust-http-0.1.21/Cargo.toml.orig	1970-01-01 01:00:00.000000000 +0100
@@ -1,51 +0,0 @@
-[package]
-name = "http"
-# When releasing to crates.io:
-# - Update html_root_url in lib.rs.
-# - Update CHANGELOG.md.
-# - Create git tag
-version = "0.1.19"
-readme = "README.md"
-documentation = "https://docs.rs/http"
-repository = "https://github.com/hyperium/http"
-license = "MIT/Apache-2.0"
-authors = [
-  "Alex Crichton <alex at alexcrichton.com>",
-  "Carl Lerche <me at carllerche.com>",
-  "Sean McArthur <sean at seanmonstar.com>",
-]
-description = """
-A set of types for representing HTTP requests and responses.
-"""
-keywords = ["http"]
-categories = ["web-programming"]
-
-[dependencies]
-bytes = "0.4"
-fnv = "1.0.5"
-itoa = "0.4.1"
-
-[dev-dependencies]
-indexmap = "1.0"
-quickcheck = "0.6"
-rand = "0.4"
-seahash = "3.0.5"
-serde = "1.0"
-serde_json = "1.0"
-doc-comment = "0.3"
-
-[[bench]]
-name = "header_map"
-path = "benches/header_map/mod.rs"
-
-[[bench]]
-name = "header_name"
-path = "benches/header_name.rs"
-
-[[bench]]
-name = "header_value"
-path = "benches/header_value.rs"
-
-[[bench]]
-name = "uri"
-path = "benches/uri.rs"
diff -Nru rust-http-0.1.19/.cargo_vcs_info.json rust-http-0.1.21/.cargo_vcs_info.json
--- rust-http-0.1.19/.cargo_vcs_info.json	1970-01-01 01:00:00.000000000 +0100
+++ rust-http-0.1.21/.cargo_vcs_info.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-{
-  "git": {
-    "sha1": "9c05e391e00474abaa8c14a86bcb0fc5eff1120e"
-  }
-}
diff -Nru rust-http-0.1.19/CHANGELOG.md rust-http-0.1.21/CHANGELOG.md
--- rust-http-0.1.19/CHANGELOG.md	2019-10-15 20:45:44.000000000 +0200
+++ rust-http-0.1.21/CHANGELOG.md	2019-12-02 20:18:55.000000000 +0100
@@ -1,3 +1,14 @@
+# 0.1.21 (December 2, 2019)
+
+* Fix `Method::is_idempotent` returning `false` for `PUT` and `DELETE.
+
+# 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).
diff -Nru rust-http-0.1.19/debian/changelog rust-http-0.1.21/debian/changelog
--- rust-http-0.1.19/debian/changelog	2021-03-08 07:19:34.000000000 +0100
+++ rust-http-0.1.21/debian/changelog	2022-04-10 21:36:10.000000000 +0200
@@ -1,3 +1,28 @@
+rust-http (0.1.21-0.1) unstable; urgency=medium
+
+  * non-maintainer upload
+  * upgrade to new upstream release 0.2.21;
+    closes: bug#988945, thanks to Moritz Muehlenhoff;
+    CVE-2019-25009
+  * drop patch cherry-picked upstream now applied
+  * fix unsatisfiable dependencies and failure to build from source:
+    + add patches to use newer release of crate bytes
+    + build-depend and autopkgtest-depend
+      on librust-block-bytes-1+default-dev
+      (not older version gone since 2021-11-28)
+    + add patch to avoid crates quickcheck rand:
+      same-API quickcheck not in Debian;
+      see <https://github.com/BurntSushi/quickcheck/pull/271#issue-784946462=>
+    + add patch to avoid crate seahash:
+      used only for benchmark
+    + drop autopkgtest dependencies on
+      librust-quickcheck-1+default-dev
+      librust-rand-0.8+default-dev
+      librust-seahash-4+default-dev
+      (some of which were never in Debian)
+
+ -- Jonas Smedegaard <dr at jones.dk>  Sun, 10 Apr 2022 21:36:10 +0200
+
 rust-http (0.1.19-2) unstable; urgency=medium
 
   * Package http 0.1.19 from crates.io using debcargo 2.4.3
diff -Nru rust-http-0.1.19/debian/control rust-http-0.1.21/debian/control
--- rust-http-0.1.19/debian/control	2021-03-08 07:19:34.000000000 +0100
+++ rust-http-0.1.21/debian/control	2022-04-10 21:36:07.000000000 +0200
@@ -6,7 +6,7 @@
  cargo:native <!nocheck>,
  rustc:native <!nocheck>,
  libstd-rust-dev <!nocheck>,
- librust-bytes-0.4+default-dev <!nocheck>,
+ librust-bytes-1+default-dev <!nocheck>,
  librust-fnv-1+default-dev (>= 1.0.5-~~) <!nocheck>,
  librust-itoa-0.4+default-dev (>= 0.4.1-~~) <!nocheck>
 Maintainer: Debian Rust Maintainers <pkg-rust-maintainers at alioth-lists.debian.net>
@@ -22,7 +22,7 @@
 Multi-Arch: same
 Depends:
  ${misc:Depends},
- librust-bytes-0.4+default-dev,
+ librust-bytes-1+default-dev,
  librust-fnv-1+default-dev (>= 1.0.5-~~),
  librust-itoa-0.4+default-dev (>= 0.4.1-~~)
 Provides:
@@ -31,8 +31,8 @@
  librust-http-0+default-dev (= ${binary:Version}),
  librust-http-0.1-dev (= ${binary:Version}),
  librust-http-0.1+default-dev (= ${binary:Version}),
- librust-http-0.1.19-dev (= ${binary:Version}),
- librust-http-0.1.19+default-dev (= ${binary:Version})
+ librust-http-0.1.21-dev (= ${binary:Version}),
+ librust-http-0.1.21+default-dev (= ${binary:Version})
 Description: Set of types for representing HTTP requests and responses - Rust source code
  This package contains the source for the Rust http crate, packaged by debcargo
  for use with cargo and dh-cargo.
diff -Nru rust-http-0.1.19/debian/patches/avoid_quickcheck.patch rust-http-0.1.21/debian/patches/avoid_quickcheck.patch
--- rust-http-0.1.19/debian/patches/avoid_quickcheck.patch	1970-01-01 01:00:00.000000000 +0100
+++ rust-http-0.1.21/debian/patches/avoid_quickcheck.patch	2022-04-10 21:28:44.000000000 +0200
@@ -0,0 +1,31 @@
+Description: avoid crate quickcheck
+ Uses old release of quickcheck unavailable in Debian.
+Author: Jonas Smedegaard <dr at jones.dk>
+Last-Update: 2022-04-10
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+--- a/Cargo.toml
++++ b/Cargo.toml
+@@ -27,8 +27,8 @@
+ 
+ [dev-dependencies]
+ indexmap = "1.0"
+-quickcheck = "0.6"
+-rand = "0.4"
++#quickcheck = "0.6"
++#rand = "0.4"
+ seahash = "3.0.5"
+ serde = "1.0"
+ serde_json = "1.0"
+--- a/tests/header_map_fuzz.rs
++++ b/tests/header_map_fuzz.rs
+@@ -1,3 +1,4 @@
++/*
+ extern crate http;
+ extern crate rand;
+ extern crate quickcheck;
+@@ -363,3 +364,4 @@
+ 
+     String::from_utf8(bytes).unwrap()
+ }
++*/
diff -Nru rust-http-0.1.19/debian/patches/avoid_seahash.patch rust-http-0.1.21/debian/patches/avoid_seahash.patch
--- rust-http-0.1.19/debian/patches/avoid_seahash.patch	1970-01-01 01:00:00.000000000 +0100
+++ rust-http-0.1.21/debian/patches/avoid_seahash.patch	2022-04-10 21:27:52.000000000 +0200
@@ -0,0 +1,49 @@
+Description: avoid crate seahash
+ Crate seahash is used only in a benchmark
+ that cannot build with stable rust.
+ .
+ While at it, disable all benchmarks,
+ as none of them can buil with stable rust.
+Author: Jonas Smedegaard <dr at jones.dk>
+Last-Update: 2022-04-10
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+--- a/Cargo.toml
++++ b/Cargo.toml
+@@ -29,23 +29,23 @@
+ indexmap = "1.0"
+ #quickcheck = "0.6"
+ #rand = "0.4"
+-seahash = "3.0.5"
++#seahash = "3.0.5"
+ serde = "1.0"
+ serde_json = "1.0"
+ doc-comment = "0.3"
+ 
+-[[bench]]
+-name = "header_map"
+-path = "benches/header_map/mod.rs"
++#[[bench]]
++#name = "header_map"
++#path = "benches/header_map/mod.rs"
+ 
+-[[bench]]
+-name = "header_name"
+-path = "benches/header_name.rs"
++#[[bench]]
++#name = "header_name"
++#path = "benches/header_name.rs"
+ 
+-[[bench]]
+-name = "header_value"
+-path = "benches/header_value.rs"
++#[[bench]]
++#name = "header_value"
++#path = "benches/header_value.rs"
+ 
+-[[bench]]
+-name = "uri"
+-path = "benches/uri.rs"
++#[[bench]]
++#name = "uri"
++#path = "benches/uri.rs"
diff -Nru rust-http-0.1.19/debian/patches/fix-capacity-overflows-in-headermap-reserve.patch rust-http-0.1.21/debian/patches/fix-capacity-overflows-in-headermap-reserve.patch
--- rust-http-0.1.19/debian/patches/fix-capacity-overflows-in-headermap-reserve.patch	2021-03-08 07:19:34.000000000 +0100
+++ rust-http-0.1.21/debian/patches/fix-capacity-overflows-in-headermap-reserve.patch	1970-01-01 01:00:00.000000000 +0100
@@ -1,53 +0,0 @@
-From 81ceb611cf96abe91d91693e813cd5ee36cdae02 Mon Sep 17 00:00:00 2001
-From: Sean McArthur <sean at seanmonstar.com>
-Date: Mon, 25 Nov 2019 15:54:04 -0800
-Subject: Fix capacity overflows in HeaderMap::reserve
- The patch required minimal adaption from upstream because the surrounding
- code had changed in upstream `master` branch over the 0.1.19 release.
- .
- Contrary to what one might assume with knowledge of `assert()` in C, the
- rust `assert!()` macro never gets removed for optimization, and is always
- checked resulting in a `panic!()` and thus a controlled shutdown of the
- process as described in
- https://doc.rust-lang.org/std/macro.assert.html#uses.
-Origin: upstream, https://github.com/hyperium/http/commit/81ceb611cf96abe91d91693e813cd5ee36cdae02
-Bug: https://github.com/hyperium/http/issues/352
-Bug-Debian: https://bugs.debian.org/969896
-
---- a/src/header/map.rs
-+++ b/src/header/map.rs
-@@ -628,6 +628,9 @@
- 
-         if cap > self.indices.len() {
-             let cap = cap.next_power_of_two();
-+            assert!(cap < MAX_SIZE, "header map reserve over max capacity");
-+            assert!(cap != 0, "header map reserve overflowed");
-+
- 
-             if self.entries.len() == 0 {
-                 self.mask = cap - 1;
---- a/tests/header_map.rs
-+++ b/tests/header_map.rs
-@@ -38,6 +38,22 @@
- }
- 
- #[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]
-+#[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();
- 
diff -Nru rust-http-0.1.19/debian/patches/series rust-http-0.1.21/debian/patches/series
--- rust-http-0.1.19/debian/patches/series	2021-03-08 07:19:34.000000000 +0100
+++ rust-http-0.1.21/debian/patches/series	2022-04-10 21:08:42.000000000 +0200
@@ -1 +1,4 @@
-fix-capacity-overflows-in-headermap-reserve.patch
+upgrade-to-bytes-0.5.patch
+upgrade-to-bytes-1.patch
+avoid_quickcheck.patch
+avoid_seahash.patch
diff -Nru rust-http-0.1.19/debian/patches/upgrade-to-bytes-0.5.patch rust-http-0.1.21/debian/patches/upgrade-to-bytes-0.5.patch
--- rust-http-0.1.19/debian/patches/upgrade-to-bytes-0.5.patch	1970-01-01 01:00:00.000000000 +0100
+++ rust-http-0.1.21/debian/patches/upgrade-to-bytes-0.5.patch	2022-04-10 19:40:20.000000000 +0200
@@ -0,0 +1,207 @@
+Description: Upgrade to bytes 0.5
+Origin: upstream, https://github.com/hyperium/http/commit/43dffa1
+Author: Sean McArthur <sean at seanmonstar.com>
+Last-Update: 2022-03-29
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+--- a/Cargo.toml
++++ b/Cargo.toml
+@@ -21,7 +21,7 @@
+ categories = ["web-programming"]
+ 
+ [dependencies]
+-bytes = "0.4"
++bytes = "0.5"
+ fnv = "1.0.5"
+ itoa = "0.4.1"
+ 
+--- a/src/byte_str.rs
++++ b/src/byte_str.rs
+@@ -50,7 +50,7 @@
+ impl<'a> From<&'a str> for ByteStr {
+     #[inline]
+     fn from(src: &'a str) -> ByteStr {
+-        ByteStr { bytes: Bytes::from(src) }
++        ByteStr { bytes: Bytes::copy_from_slice(src.as_bytes()) }
+     }
+ }
+ 
+--- a/src/header/name.rs
++++ b/src/header/name.rs
+@@ -1662,7 +1662,7 @@
+         match parse_hdr(src, &mut buf, &HEADER_CHARS)?.inner {
+             Repr::Standard(std) => Ok(std.into()),
+             Repr::Custom(MaybeLower { buf, lower: true }) => {
+-                let buf = Bytes::from(buf);
++                let buf = Bytes::copy_from_slice(buf);
+                 let val = unsafe { ByteStr::from_utf8_unchecked(buf) };
+                 Ok(Custom(val).into())
+             }
+@@ -1677,7 +1677,7 @@
+                         return Err(InvalidHeaderName::new());
+                     }
+ 
+-                    dst.put(b);
++                    dst.put_u8(b);
+                 }
+ 
+                 let val = unsafe { ByteStr::from_utf8_unchecked(dst.freeze()) };
+@@ -1711,7 +1711,7 @@
+         match parse_hdr(src, &mut buf, &HEADER_CHARS_H2)?.inner {
+             Repr::Standard(std) => Ok(std.into()),
+             Repr::Custom(MaybeLower { buf, lower: true }) => {
+-                let buf = Bytes::from(buf);
++                let buf = Bytes::copy_from_slice(buf);
+                 let val = unsafe { ByteStr::from_utf8_unchecked(buf) };
+                 Ok(Custom(val).into())
+             }
+@@ -1722,7 +1722,7 @@
+                     }
+                 }
+ 
+-                let buf = Bytes::from(buf);
++                let buf = Bytes::copy_from_slice(buf);
+                 let val = unsafe { ByteStr::from_utf8_unchecked(buf) };
+                 Ok(Custom(val).into())
+             }
+@@ -2089,7 +2089,7 @@
+             }
+             Repr::Custom(maybe_lower) => {
+                 if maybe_lower.lower {
+-                    let buf = Bytes::from(&maybe_lower.buf[..]);
++                    let buf = Bytes::copy_from_slice(&maybe_lower.buf[..]);
+                     let byte_str = unsafe { ByteStr::from_utf8_unchecked(buf) };
+ 
+                     HeaderName {
+@@ -2100,7 +2100,7 @@
+                     let mut dst = BytesMut::with_capacity(maybe_lower.buf.len());
+ 
+                     for b in maybe_lower.buf.iter() {
+-                        dst.put(HEADER_CHARS[*b as usize]);
++                        dst.put_u8(HEADER_CHARS[*b as usize]);
+                     }
+ 
+                     let buf = unsafe { ByteStr::from_utf8_unchecked(dst.freeze()) };
+--- a/src/header/value.rs
++++ b/src/header/value.rs
+@@ -104,7 +104,7 @@
+     /// ```
+     #[inline]
+     pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> {
+-        HeaderValue::try_from(src)
++        HeaderValue::try_from_generic(src, |s| Bytes::copy_from_slice(s.as_bytes()))
+     }
+ 
+     /// Converts a HeaderName into a HeaderValue
+@@ -150,7 +150,7 @@
+     /// ```
+     #[inline]
+     pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
+-        HeaderValue::try_from(src)
++        HeaderValue::try_from_generic(src, Bytes::copy_from_slice)
+     }
+ 
+     /// Attempt to convert a `Bytes` buffer to a `HeaderValue`.
+@@ -163,7 +163,7 @@
+     /// implementation once the trait is stabilized in std.
+     #[inline]
+     pub fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValueBytes> {
+-        HeaderValue::try_from(src).map_err(InvalidHeaderValueBytes)
++        HeaderValue::try_from_generic(src, std::convert::identity).map_err(InvalidHeaderValueBytes)
+     }
+ 
+     /// Convert a `Bytes` directly into a `HeaderValue` without validating.
+@@ -189,7 +189,7 @@
+         }
+     }
+ 
+-    fn try_from<T: AsRef<[u8]> + Into<Bytes>>(src: T) -> Result<HeaderValue, InvalidHeaderValue> {
++    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 {
+@@ -198,7 +198,7 @@
+             }
+         }
+         Ok(HeaderValue {
+-            inner: src.into(),
++            inner: into(src),
+             is_sensitive: false,
+         })
+     }
+@@ -546,6 +546,15 @@
+     }
+ }
+ 
++impl HttpTryFrom<Vec<u8>> for HeaderValue {
++    type Error = InvalidHeaderValueBytes;
++
++    #[inline]
++    fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
++        HeaderValue::from_shared(vec.into())
++    }
++}
++
+ impl HttpTryFrom<Bytes> for HeaderValue {
+     type Error = InvalidHeaderValueBytes;
+ 
+--- a/src/uri/authority.rs
++++ b/src/uri/authority.rs
+@@ -1,6 +1,3 @@
+-// Deprecated in 1.26, needed until our minimum version is >=1.23.
+-#[allow(unused, deprecated)]
+-use std::ascii::AsciiExt;
+ use std::{cmp, fmt, str};
+ use std::hash::{Hash, Hasher};
+ use std::str::FromStr;
+@@ -457,7 +454,9 @@
+         }
+ 
+         Ok(Authority {
+-            data: unsafe { ByteStr::from_utf8_unchecked(s.into()) },
++            data: unsafe {
++                ByteStr::from_utf8_unchecked(Bytes::copy_from_slice(s))
++            },
+         })
+     }
+ }
+--- a/src/uri/mod.rs
++++ b/src/uri/mod.rs
+@@ -888,7 +888,7 @@
+ 
+     #[inline]
+     fn from_str(s: &str) -> Result<Uri, InvalidUri> {
+-        Uri::from_shared(s.into()).map_err(|e| e.0)
++        Uri::from_shared(Bytes::copy_from_slice(s.as_bytes())).map_err(|e| e.0)
+     }
+ }
+ 
+--- a/src/uri/path.rs
++++ b/src/uri/path.rs
+@@ -296,7 +296,7 @@
+     type Error = InvalidUri;
+     #[inline]
+     fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
+-        PathAndQuery::from_shared(s.into()).map_err(|e| e.0)
++        PathAndQuery::from_shared(Bytes::copy_from_slice(s)).map_err(|e| e.0)
+     }
+ }
+ 
+--- a/src/uri/scheme.rs
++++ b/src/uri/scheme.rs
+@@ -1,6 +1,3 @@
+-// Deprecated in 1.26, needed until our minimum version is >=1.23.
+-#[allow(unused, deprecated)]
+-use std::ascii::AsciiExt;
+ use std::fmt;
+ use std::hash::{Hash, Hasher};
+ use std::str::FromStr;
+@@ -130,7 +127,7 @@
+             Other(_) => {
+                 // Unsafe: parse_exact already checks for a strict subset of UTF-8
+                 Ok(Other(Box::new(unsafe {
+-                    ByteStr::from_utf8_unchecked(s.into())
++                    ByteStr::from_utf8_unchecked(Bytes::copy_from_slice(s))
+                 })).into())
+             }
+         }
diff -Nru rust-http-0.1.19/debian/patches/upgrade-to-bytes-1.patch rust-http-0.1.21/debian/patches/upgrade-to-bytes-1.patch
--- rust-http-0.1.19/debian/patches/upgrade-to-bytes-1.patch	1970-01-01 01:00:00.000000000 +0100
+++ rust-http-0.1.21/debian/patches/upgrade-to-bytes-1.patch	2022-04-10 19:41:00.000000000 +0200
@@ -0,0 +1,17 @@
+Description: Upgrade to Bytes 1.0
+Origin: upstream, https://github.com/hyperium/http/commit/95c338e
+Author: Sean McArthur <sean at seanmonstar.com>
+Last-Update: 2022-03-29
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+--- a/Cargo.toml
++++ b/Cargo.toml
+@@ -21,7 +21,7 @@
+ categories = ["web-programming"]
+ 
+ [dependencies]
+-bytes = "0.5"
++bytes = "1"
+ fnv = "1.0.5"
+ itoa = "0.4.1"
+ 
diff -Nru rust-http-0.1.19/debian/tests/control rust-http-0.1.21/debian/tests/control
--- rust-http-0.1.19/debian/tests/control	2021-03-08 07:19:34.000000000 +0100
+++ rust-http-0.1.21/debian/tests/control	2022-04-10 21:08:24.000000000 +0200
@@ -1,14 +1,14 @@
-Test-Command: /usr/share/cargo/bin/cargo-auto-test http 0.1.19 --all-targets --all-features
+Test-Command: /usr/share/cargo/bin/cargo-auto-test http 0.1.21 --all-targets --all-features
 Features: test-name=rust-http:@
-Depends: dh-cargo (>= 18), librust-doc-comment-0.3+default-dev, librust-indexmap-1+default-dev, librust-quickcheck-0.6+default-dev, librust-rand-0.4+default-dev, librust-seahash-3+default-dev (>= 3.0.5-~~), librust-serde-1+default-dev, librust-serde-json-1+default-dev, @
+Depends: dh-cargo (>= 18), librust-doc-comment-0.3+default-dev, librust-indexmap-1+default-dev, librust-serde-1+default-dev, librust-serde-json-1+default-dev, @
 Restrictions: allow-stderr, skip-not-installable
 
-Test-Command: /usr/share/cargo/bin/cargo-auto-test http 0.1.19 --all-targets 
+Test-Command: /usr/share/cargo/bin/cargo-auto-test http 0.1.21 --all-targets 
 Features: test-name=librust-http-dev:default
-Depends: dh-cargo (>= 18), librust-doc-comment-0.3+default-dev, librust-indexmap-1+default-dev, librust-quickcheck-0.6+default-dev, librust-rand-0.4+default-dev, librust-seahash-3+default-dev (>= 3.0.5-~~), librust-serde-1+default-dev, librust-serde-json-1+default-dev, @
+Depends: dh-cargo (>= 18), librust-doc-comment-0.3+default-dev, librust-indexmap-1+default-dev, librust-serde-1+default-dev, librust-serde-json-1+default-dev, @
 Restrictions: allow-stderr, skip-not-installable
 
-Test-Command: /usr/share/cargo/bin/cargo-auto-test http 0.1.19 --all-targets --no-default-features
+Test-Command: /usr/share/cargo/bin/cargo-auto-test http 0.1.21 --all-targets --no-default-features
 Features: test-name=librust-http-dev:
-Depends: dh-cargo (>= 18), librust-doc-comment-0.3+default-dev, librust-indexmap-1+default-dev, librust-quickcheck-0.6+default-dev, librust-rand-0.4+default-dev, librust-seahash-3+default-dev (>= 3.0.5-~~), librust-serde-1+default-dev, librust-serde-json-1+default-dev, @
+Depends: dh-cargo (>= 18), librust-doc-comment-0.3+default-dev, librust-indexmap-1+default-dev, librust-serde-1+default-dev, librust-serde-json-1+default-dev, @
 Restrictions: allow-stderr, skip-not-installable
diff -Nru rust-http-0.1.19/src/header/map.rs rust-http-0.1.21/src/header/map.rs
--- rust-http-0.1.19/src/header/map.rs	2019-07-26 19:21:06.000000000 +0200
+++ rust-http-0.1.21/src/header/map.rs	2019-12-02 20:18:55.000000000 +0100
@@ -135,7 +135,9 @@
 #[derive(Debug)]
 pub struct Drain<'a, T: 'a> {
     idx: usize,
-    map: *mut HeaderMap<T>,
+    len: usize,
+    entries: *mut [Bucket<T>],
+    extra_values: *mut Vec<ExtraValue<T>>,
     lt: PhantomData<&'a mut HeaderMap<T>>,
 }
 
@@ -202,9 +204,8 @@
 /// An drain iterator of all values associated with a single header name.
 #[derive(Debug)]
 pub struct ValueDrain<'a, T: 'a> {
-    map: *mut HeaderMap<T>,
     first: Option<T>,
-    next: Option<usize>,
+    next: Option<::std::vec::IntoIter<T>>,
     lt: PhantomData<&'a mut HeaderMap<T>>,
 }
 
@@ -270,6 +271,13 @@
     tail: usize,
 }
 
+/// Access to the `links` value in a slice of buckets.
+///
+/// It's important that no other field is accessed, since it may have been
+/// freed in a `Drain` iterator.
+#[derive(Debug)]
+struct RawLinks<T>(*mut [Bucket<T>]);
+
 /// Node in doubly-linked list of header value entries
 #[derive(Debug, Clone)]
 struct ExtraValue<T> {
@@ -628,6 +636,8 @@
 
         if cap > self.indices.len() {
             let cap = cap.next_power_of_two();
+            assert!(cap < MAX_SIZE, "header map reserve over max capacity");
+            assert!(cap != 0, "header map reserve overflowed");
 
             if self.entries.len() == 0 {
                 self.mask = cap - 1;
@@ -930,9 +940,23 @@
             *i = Pos::none();
         }
 
+        // Memory safety
+        //
+        // When the Drain is first created, it shortens the length of
+        // the source vector to make sure no uninitialized or moved-from
+        // elements are accessible at all if the Drain's destructor never
+        // gets to run.
+
+        let entries = &mut self.entries[..] as *mut _;
+        let extra_values = &mut self.extra_values as *mut _;
+        let len = self.entries.len();
+        unsafe { self.entries.set_len(0); }
+
         Drain {
             idx: 0,
-            map: self as *mut _,
+            len,
+            entries,
+            extra_values,
             lt: PhantomData,
         }
     }
@@ -1136,10 +1160,17 @@
             links = entry.links.take();
         }
 
+        let raw_links = self.raw_links();
+        let extra_values = &mut self.extra_values;
+
+        let next = links.map(|l| {
+            drain_all_extra_values(raw_links, extra_values, l.next)
+                .into_iter()
+        });
+
         ValueDrain {
-            map: self as *mut _,
             first: Some(old),
-            next: links.map(|l| l.next),
+            next: next,
             lt: PhantomData,
         }
     }
@@ -1364,124 +1395,8 @@
     /// Removes the `ExtraValue` at the given index.
     #[inline]
     fn remove_extra_value(&mut self, idx: usize) -> ExtraValue<T> {
-        let prev;
-        let next;
-
-        {
-            debug_assert!(self.extra_values.len() > idx);
-            let extra = &self.extra_values[idx];
-            prev = extra.prev;
-            next = extra.next;
-        }
-
-        // First unlink the extra value
-        match (prev, next) {
-            (Link::Entry(prev), Link::Entry(next)) => {
-                debug_assert_eq!(prev, next);
-                debug_assert!(self.entries.len() > prev);
-
-                self.entries[prev].links = None;
-            }
-            (Link::Entry(prev), Link::Extra(next)) => {
-                debug_assert!(self.entries.len() > prev);
-                debug_assert!(self.entries[prev].links.is_some());
-
-                self.entries[prev].links.as_mut().unwrap()
-                    .next = next;
-
-                debug_assert!(self.extra_values.len() > next);
-                self.extra_values[next].prev = Link::Entry(prev);
-            }
-            (Link::Extra(prev), Link::Entry(next)) => {
-                debug_assert!(self.entries.len() > next);
-                debug_assert!(self.entries[next].links.is_some());
-
-                self.entries[next].links.as_mut().unwrap()
-                    .tail = prev;
-
-                debug_assert!(self.extra_values.len() > prev);
-                self.extra_values[prev].next = Link::Entry(next);
-            }
-            (Link::Extra(prev), Link::Extra(next)) => {
-                debug_assert!(self.extra_values.len() > next);
-                debug_assert!(self.extra_values.len() > prev);
-
-                self.extra_values[prev].next = Link::Extra(next);
-                self.extra_values[next].prev = Link::Extra(prev);
-            }
-        }
-
-        // Remove the extra value
-        let mut extra = self.extra_values.swap_remove(idx);
-
-        // This is the index of the value that was moved (possibly `extra`)
-        let old_idx = self.extra_values.len();
-
-        // Update the links
-        if extra.prev == Link::Extra(old_idx) {
-            extra.prev = Link::Extra(idx);
-        }
-
-        if extra.next == Link::Extra(old_idx) {
-            extra.next = Link::Extra(idx);
-        }
-
-        // Check if another entry was displaced. If it was, then the links
-        // need to be fixed.
-        if idx != old_idx {
-            let next;
-            let prev;
-
-            {
-                debug_assert!(self.extra_values.len() > idx);
-                let moved = &self.extra_values[idx];
-                next = moved.next;
-                prev = moved.prev;
-            }
-
-            // An entry was moved, we have to the links
-            match prev {
-                Link::Entry(entry_idx) => {
-                    // It is critical that we do not attempt to read the
-                    // header name or value as that memory may have been
-                    // "released" already.
-                    debug_assert!(self.entries.len() > entry_idx);
-                    debug_assert!(self.entries[entry_idx].links.is_some());
-
-                    let links = self.entries[entry_idx].links.as_mut().unwrap();
-                    links.next = idx;
-                }
-                Link::Extra(extra_idx) => {
-                    debug_assert!(self.extra_values.len() > extra_idx);
-                    self.extra_values[extra_idx].next = Link::Extra(idx);
-                }
-            }
-
-            match next {
-                Link::Entry(entry_idx) => {
-                    debug_assert!(self.entries.len() > entry_idx);
-                    debug_assert!(self.entries[entry_idx].links.is_some());
-
-                    let links = self.entries[entry_idx].links.as_mut().unwrap();
-                    links.tail = idx;
-                }
-                Link::Extra(extra_idx) => {
-                    debug_assert!(self.extra_values.len() > extra_idx);
-                    self.extra_values[extra_idx].prev = Link::Extra(idx);
-                }
-            }
-        }
-
-        debug_assert!({
-            for v in &self.extra_values {
-                assert!(v.next != Link::Extra(old_idx));
-                assert!(v.prev != Link::Extra(old_idx));
-            }
-
-            true
-        });
-
-        extra
+        let raw_links = self.raw_links();
+        remove_extra_value(raw_links, &mut self.extra_values, idx)
     }
 
     fn remove_all_extra_values(&mut self, mut head: usize) {
@@ -1631,6 +1546,145 @@
         let more = self.capacity() - self.entries.len();
         self.entries.reserve_exact(more);
     }
+
+    #[inline]
+    fn raw_links(&mut self) -> RawLinks<T> {
+        RawLinks(&mut self.entries[..] as *mut _)
+    }
+}
+
+/// Removes the `ExtraValue` at the given index.
+#[inline]
+fn remove_extra_value<T>(mut raw_links: RawLinks<T>, extra_values: &mut Vec<ExtraValue<T>>, idx: usize) -> ExtraValue<T> {
+    let prev;
+    let next;
+
+    {
+        debug_assert!(extra_values.len() > idx);
+        let extra = &extra_values[idx];
+        prev = extra.prev;
+        next = extra.next;
+    }
+
+    // First unlink the extra value
+    match (prev, next) {
+        (Link::Entry(prev), Link::Entry(next)) => {
+            debug_assert_eq!(prev, next);
+
+            raw_links[prev] = None;
+        }
+        (Link::Entry(prev), Link::Extra(next)) => {
+            debug_assert!(raw_links[prev].is_some());
+
+            raw_links[prev].as_mut().unwrap()
+                .next = next;
+
+            debug_assert!(extra_values.len() > next);
+            extra_values[next].prev = Link::Entry(prev);
+        }
+        (Link::Extra(prev), Link::Entry(next)) => {
+            debug_assert!(raw_links[next].is_some());
+
+            raw_links[next].as_mut().unwrap()
+                .tail = prev;
+
+            debug_assert!(extra_values.len() > prev);
+            extra_values[prev].next = Link::Entry(next);
+        }
+        (Link::Extra(prev), Link::Extra(next)) => {
+            debug_assert!(extra_values.len() > next);
+            debug_assert!(extra_values.len() > prev);
+
+            extra_values[prev].next = Link::Extra(next);
+            extra_values[next].prev = Link::Extra(prev);
+        }
+    }
+
+    // Remove the extra value
+    let mut extra = extra_values.swap_remove(idx);
+
+    // This is the index of the value that was moved (possibly `extra`)
+    let old_idx = extra_values.len();
+
+    // Update the links
+    if extra.prev == Link::Extra(old_idx) {
+        extra.prev = Link::Extra(idx);
+    }
+
+    if extra.next == Link::Extra(old_idx) {
+        extra.next = Link::Extra(idx);
+    }
+
+    // Check if another entry was displaced. If it was, then the links
+    // need to be fixed.
+    if idx != old_idx {
+        let next;
+        let prev;
+
+        {
+            debug_assert!(extra_values.len() > idx);
+            let moved = &extra_values[idx];
+            next = moved.next;
+            prev = moved.prev;
+        }
+
+        // An entry was moved, we have to the links
+        match prev {
+            Link::Entry(entry_idx) => {
+                // It is critical that we do not attempt to read the
+                // header name or value as that memory may have been
+                // "released" already.
+                debug_assert!(raw_links[entry_idx].is_some());
+
+                let links = raw_links[entry_idx].as_mut().unwrap();
+                links.next = idx;
+            }
+            Link::Extra(extra_idx) => {
+                debug_assert!(extra_values.len() > extra_idx);
+                extra_values[extra_idx].next = Link::Extra(idx);
+            }
+        }
+
+        match next {
+            Link::Entry(entry_idx) => {
+                debug_assert!(raw_links[entry_idx].is_some());
+
+                let links = raw_links[entry_idx].as_mut().unwrap();
+                links.tail = idx;
+            }
+            Link::Extra(extra_idx) => {
+                debug_assert!(extra_values.len() > extra_idx);
+                extra_values[extra_idx].prev = Link::Extra(idx);
+            }
+        }
+    }
+
+    debug_assert!({
+        for v in &*extra_values {
+            assert!(v.next != Link::Extra(old_idx));
+            assert!(v.prev != Link::Extra(old_idx));
+        }
+
+        true
+    });
+
+    extra
+}
+
+
+fn drain_all_extra_values<T>(raw_links: RawLinks<T>, extra_values: &mut Vec<ExtraValue<T>>, mut head: usize) -> Vec<T> {
+    let mut vec = Vec::new();
+    loop {
+        let extra = remove_extra_value(raw_links, extra_values, head);
+        vec.push(extra.value);
+
+        if let Link::Extra(idx) = extra.next {
+            head = idx;
+        } else {
+            break;
+        }
+    }
+    vec
 }
 
 impl<'a, T> IntoIterator for &'a HeaderMap<T> {
@@ -1821,7 +1875,6 @@
 
             // As long as `HeaderName` is none, keep inserting the value into
             // the current entry
-            'inner:
             loop {
                 match iter.next() {
                     Some((Some(k), v)) => {
@@ -2102,7 +2155,7 @@
     fn next(&mut self) -> Option<Self::Item> {
         let idx = self.idx;
 
-        if idx == unsafe { (*self.map).entries.len() } {
+        if idx == self.len {
             return None;
         }
 
@@ -2112,38 +2165,39 @@
         let value;
         let next;
 
-        unsafe {
-            let entry = &(*self.map).entries[idx];
+        let values = unsafe {
+            let entry = &(*self.entries)[idx];
 
             // Read the header name
             key = ptr::read(&entry.key as *const _);
             value = ptr::read(&entry.value as *const _);
-            next = entry.links.map(|l| l.next);
-        };
 
-        let values = ValueDrain {
-            map: self.map,
-            first: Some(value),
-            next: next,
-            lt: PhantomData,
+            let raw_links = RawLinks(self.entries);
+            let extra_values = &mut *self.extra_values;
+            next = entry.links.map(|l| {
+                drain_all_extra_values(raw_links, extra_values, l.next)
+                    .into_iter()
+            });
+
+            ValueDrain {
+                first: Some(value),
+                next,
+                lt: PhantomData,
+            }
         };
 
         Some((key, values))
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        let lower = unsafe { (*self.map).entries.len() } - self.idx;
+        let lower = self.len - self.idx;
         (lower, Some(lower))
     }
 }
 
 impl<'a, T> Drop for Drain<'a, T> {
     fn drop(&mut self) {
-        unsafe {
-            let map = &mut *self.map;
-            debug_assert!(map.extra_values.is_empty());
-            map.entries.set_len(0);
-        }
+        for _ in self {}
     }
 }
 
@@ -2860,10 +2914,16 @@
     /// returned.
     pub fn remove_entry_mult(self) -> (HeaderName, ValueDrain<'a, T>) {
         let entry = self.map.remove_found(self.probe, self.index);
+        let raw_links = self.map.raw_links();
+        let extra_values = &mut self.map.extra_values;
+
+        let next = entry.links.map(|l| {
+            drain_all_extra_values(raw_links, extra_values, l.next)
+                .into_iter()
+        });
         let drain = ValueDrain {
-            map: self.map as *mut _,
             first: Some(entry.value),
-            next: entry.links.map(|l| l.next),
+            next,
             lt: PhantomData,
         };
         (entry.key, drain)
@@ -2956,29 +3016,26 @@
     fn next(&mut self) -> Option<T> {
         if self.first.is_some() {
             self.first.take()
-        } else if let Some(next) = self.next {
-            // Remove the extra value
-            let extra = unsafe { &mut (*self.map) }.remove_extra_value(next);
-
-            match extra.next {
-                Link::Extra(idx) => self.next = Some(idx),
-                Link::Entry(_) => self.next = None,
-            }
-
-            Some(extra.value)
+        } else if let Some(ref mut extras) = self.next {
+            extras.next()
         } else {
             None
         }
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        match (&self.first, self.next) {
+        match (&self.first, &self.next) {
             // Exactly 1
-            (&Some(_), None) => (1, Some(1)),
-            // At least 1
-            (&_, Some(_)) => (1, None),
+            (&Some(_), &None) => (1, Some(1)),
+            // 1 + extras
+            (&Some(_), &Some(ref extras)) => {
+                let (l, u) = extras.size_hint();
+                (l + 1, u.map(|u| u + 1))
+            },
+            // Extras only
+            (&None, &Some(ref extras)) => extras.size_hint(),
             // No more
-            (&None, None) => (0, Some(0)),
+            (&None, &None) => (0, Some(0)),
         }
     }
 }
@@ -2993,6 +3050,34 @@
 unsafe impl<'a, T: Sync> Sync for ValueDrain<'a, T> {}
 unsafe impl<'a, T: Send> Send for ValueDrain<'a, T> {}
 
+// ===== impl RawLinks =====
+
+impl<T> Clone for RawLinks<T> {
+    fn clone(&self) -> RawLinks<T> {
+        *self
+    }
+}
+
+impl<T> Copy for RawLinks<T> {}
+
+impl<T> ops::Index<usize> for RawLinks<T> {
+    type Output = Option<Links>;
+
+    fn index(&self, idx: usize) -> &Self::Output {
+        unsafe {
+            &(*self.0)[idx].links
+        }
+    }
+}
+
+impl<T> ops::IndexMut<usize> for RawLinks<T> {
+    fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
+        unsafe {
+            &mut (*self.0)[idx].links
+        }
+    }
+}
+
 // ===== impl Pos =====
 
 impl Pos {
@@ -3198,7 +3283,7 @@
     use super::{Entry, HdrName, HeaderMap, HeaderName, InvalidHeaderName};
 
     /// A marker trait used to identify values that can be used as search keys
-                    /// to a `HeaderMap`.
+    /// to a `HeaderMap`.
     pub trait AsHeaderName: Sealed {}
 
     // All methods are on this pub(super) trait, instead of `AsHeaderName`,
diff -Nru rust-http-0.1.19/src/lib.rs rust-http-0.1.21/src/lib.rs
--- rust-http-0.1.19/src/lib.rs	2019-10-15 20:44:22.000000000 +0200
+++ rust-http-0.1.21/src/lib.rs	2019-12-02 20:18:55.000000000 +0100
@@ -1,4 +1,4 @@
-#![doc(html_root_url = "https://docs.rs/http/0.1.19")]
+#![doc(html_root_url = "https://docs.rs/http/0.1.21")]
 
 //! A general purpose library of common HTTP types
 //!
diff -Nru rust-http-0.1.19/src/method.rs rust-http-0.1.21/src/method.rs
--- rust-http-0.1.19/src/method.rs	2019-10-15 20:43:45.000000000 +0200
+++ rust-http-0.1.21/src/method.rs	2019-12-02 20:18:55.000000000 +0100
@@ -219,13 +219,9 @@
     /// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.2) for
     /// more words.
     pub fn is_idempotent(&self) -> bool {
-        if self.is_safe() {
-            true
-        } else {
-            match self.0 {
-                Put | Delete => true,
-                _ => false
-            }
+        match self.0 {
+            Put | Delete => true,
+            _ => self.is_safe(),
         }
     }
 
@@ -427,3 +423,17 @@
     assert!(Method::from_str("").is_err());
     assert!(Method::from_bytes(b"").is_err());
 }
+
+#[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());
+}
diff -Nru rust-http-0.1.19/src/uri/scheme.rs rust-http-0.1.21/src/uri/scheme.rs
--- rust-http-0.1.19/src/uri/scheme.rs	2019-07-26 19:05:29.000000000 +0200
+++ rust-http-0.1.21/src/uri/scheme.rs	2019-12-02 20:18:55.000000000 +0100
@@ -336,10 +336,6 @@
             for i in 0..s.len() {
                 let b = s[i];
 
-                if i == MAX_SCHEME_LEN {
-                    return Err(ErrorKind::SchemeTooLong.into());
-                }
-
                 match SCHEME_CHARS[b as usize] {
                     b':' => {
                         // Not enough data remaining
@@ -352,6 +348,10 @@
                             break;
                         }
 
+                        if i > MAX_SCHEME_LEN {
+                            return Err(ErrorKind::SchemeTooLong.into());
+                        }
+
                         // Return scheme
                         return Ok(Scheme2::Other(i));
                     }
diff -Nru rust-http-0.1.19/src/uri/tests.rs rust-http-0.1.21/src/uri/tests.rs
--- rust-http-0.1.19/src/uri/tests.rs	2019-07-26 19:05:29.000000000 +0200
+++ rust-http-0.1.21/src/uri/tests.rs	2019-12-02 20:18:55.000000000 +0100
@@ -232,6 +232,30 @@
 }
 
 test_parse! {
+    test_uri_parse_long_host_with_no_scheme,
+    "thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost",
+    [],
+
+    scheme_part = None,
+    authority_part = part!("thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost"),
+    path = "",
+    query = None,
+    port_part = None,
+}
+
+test_parse! {
+    test_uri_parse_long_host_with_port_and_no_scheme,
+    "thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost:1234",
+    [],
+
+    scheme_part = None,
+    authority_part = part!("thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost:1234"),
+    path = "",
+    query = None,
+    port_part = Port::from_str("1234").ok(),
+}
+
+test_parse! {
     test_userinfo1,
     "http://a:b@127.0.0.1:1234/",
     [],
@@ -430,7 +454,7 @@
 }
 
 #[test]
-fn test_long_scheme() {
+fn test_overflowing_scheme() {
     let mut uri = vec![];
     uri.extend(vec![b'a'; 256]);
     uri.extend(b"://localhost/");
@@ -442,6 +466,18 @@
 }
 
 #[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![
         ("/", "/"),
diff -Nru rust-http-0.1.19/tests/header_map.rs rust-http-0.1.21/tests/header_map.rs
--- rust-http-0.1.19/tests/header_map.rs	2019-07-26 19:05:29.000000000 +0200
+++ rust-http-0.1.21/tests/header_map.rs	2019-12-02 20:18:55.000000000 +0100
@@ -38,6 +38,22 @@
 }
 
 #[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]
+#[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();
 
@@ -87,6 +103,40 @@
 }
 
 #[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(2)));
+    // 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();
 
diff -Nru rust-http-0.1.19/util/Cargo.toml rust-http-0.1.21/util/Cargo.toml
--- rust-http-0.1.19/util/Cargo.toml	1970-01-01 01:00:00.000000000 +0100
+++ rust-http-0.1.21/util/Cargo.toml	2019-12-02 20:18:55.000000000 +0100
@@ -0,0 +1,4 @@
+[package]
+name = "gen"
+version = "0.1.0"
+authors = ["Carl Lerche <me at carllerche.com>"]
diff -Nru rust-http-0.1.19/util/README.md rust-http-0.1.21/util/README.md
--- rust-http-0.1.19/util/README.md	1970-01-01 01:00:00.000000000 +0100
+++ rust-http-0.1.21/util/README.md	2019-12-02 20:18:55.000000000 +0100
@@ -0,0 +1 @@
+Generates standard header code
diff -Nru rust-http-0.1.19/util/src/main.rs rust-http-0.1.21/util/src/main.rs
--- rust-http-0.1.19/util/src/main.rs	1970-01-01 01:00:00.000000000 +0100
+++ rust-http-0.1.21/util/src/main.rs	2019-12-02 20:18:55.000000000 +0100
@@ -0,0 +1,1040 @@
+macro_rules! standard_headers {
+    (
+        $(
+            $doc:expr,
+            $name:expr;
+        )+
+    ) => {
+        const HEADERS: &[(&'static str, &'static str)] = &[
+            $(
+                ($doc, $name),
+            )+
+        ];
+    }
+}
+
+standard_headers! {
+    r#"
+    /// Advertises which content types the client is able to understand.
+    ///
+    /// The Accept request HTTP header advertises which content types, expressed
+    /// as MIME types, the client is able to understand. Using content
+    /// negotiation, the server then selects one of the proposals, uses it and
+    /// informs the client of its choice with the Content-Type response header.
+    /// Browsers set adequate values for this header depending of the context
+    /// where the request is done: when fetching a CSS stylesheet a different
+    /// value is set for the request than when fetching an image, video or a
+    /// script.
+    "#,
+    "accept";
+
+    r#"
+    /// Advertises which character set the client is able to understand.
+    ///
+    /// The Accept-Charset request HTTP header advertises which character set
+    /// the client is able to understand. Using content negotiation, the server
+    /// then selects one of the proposals, uses it and informs the client of its
+    /// choice within the Content-Type response header. Browsers usually don't
+    /// set this header as the default value for each content type is usually
+    /// correct and transmitting it would allow easier fingerprinting.
+    ///
+    /// If the server cannot serve any matching character set, it can
+    /// theoretically send back a 406 (Not Acceptable) error code. But, for a
+    /// better user experience, this is rarely done and the more common way is
+    /// to ignore the Accept-Charset header in this case.
+    "#,
+    "accept-charset";
+
+    r#"
+    /// Advertises which content encoding the client is able to understand.
+    ///
+    /// The Accept-Encoding request HTTP header advertises which content
+    /// encoding, usually a compression algorithm, the client is able to
+    /// understand. Using content negotiation, the server selects one of the
+    /// proposals, uses it and informs the client of its choice with the
+    /// Content-Encoding response header.
+    ///
+    /// Even if both the client and the server supports the same compression
+    /// algorithms, the server may choose not to compress the body of a
+    /// response, if the identity value is also acceptable. Two common cases
+    /// lead to this:
+    ///
+    /// * The data to be sent is already compressed and a second compression
+    /// won't lead to smaller data to be transmitted. This may the case with
+    /// some image formats;
+    ///
+    /// * The server is overloaded and cannot afford the computational overhead
+    /// induced by the compression requirement. Typically, Microsoft recommends
+    /// not to compress if a server use more than 80 % of its computational
+    /// power.
+    ///
+    /// As long as the identity value, meaning no encryption, is not explicitly
+    /// forbidden, by an identity;q=0 or a *;q=0 without another explicitly set
+    /// value for identity, the server must never send back a 406 Not Acceptable
+    /// error.
+    "#,
+    "accept-encoding";
+
+    r#"
+    /// Advertises which languages the client is able to understand.
+    ///
+    /// The Accept-Language request HTTP header advertises which languages the
+    /// client is able to understand, and which locale variant is preferred.
+    /// Using content negotiation, the server then selects one of the proposals,
+    /// uses it and informs the client of its choice with the Content-Language
+    /// response header. Browsers set adequate values for this header according
+    /// their user interface language and even if a user can change it, this
+    /// happens rarely (and is frown upon as it leads to fingerprinting).
+    ///
+    /// This header is a hint to be used when the server has no way of
+    /// determining the language via another way, like a specific URL, that is
+    /// controlled by an explicit user decision. It is recommended that the
+    /// server never overrides an explicit decision. The content of the
+    /// Accept-Language is often out of the control of the user (like when
+    /// traveling and using an Internet Cafe in a different country); the user
+    /// may also want to visit a page in another language than the locale of
+    /// their user interface.
+    ///
+    /// If the server cannot serve any matching language, it can theoretically
+    /// send back a 406 (Not Acceptable) error code. But, for a better user
+    /// experience, this is rarely done and more common way is to ignore the
+    /// Accept-Language header in this case.
+    "#,
+    "accept-language";
+
+    r#"
+    /// Advertises which patch formats the server is able to understand.
+    ///
+    /// Accept-Patch should appear in the OPTIONS response for any resource that
+    /// supports the use of the PATCH method. The presence of the
+    /// Accept-Patch header in response to any method is an implicit indication
+    /// that PATCH is allowed on the resource identified by the URI. The
+    /// presence of a specific patch document format in this header indicates
+    /// that that specific format is allowed on the resource identified by the
+    /// URI.
+    "#,
+    "accept-patch";
+
+    r#"
+    /// Marker used by the server to advertise partial request support.
+    ///
+    /// The Accept-Ranges response HTTP header is a marker used by the server to
+    /// advertise its support of partial requests. The value of this field
+    /// indicates the unit that can be used to define a range.
+    ///
+    /// In presence of an Accept-Ranges header, the browser may try to resume an
+    /// interrupted download, rather than to start it from the start again.
+    "#,
+    "accept-ranges";
+
+    r#"
+    /// Preflight response indicating if the response to the request can be
+    /// exposed to the page.
+    ///
+    /// The Access-Control-Allow-Credentials response header indicates whether
+    /// or not the response to the request can be exposed to the page. It can be
+    /// exposed when the true value is returned; it can't in other cases.
+    ///
+    /// Credentials are cookies, authorization headers or TLS client
+    /// certificates.
+    ///
+    /// When used as part of a response to a preflight request, this indicates
+    /// whether or not the actual request can be made using credentials. Note
+    /// that simple GET requests are not preflighted, and so if a request is
+    /// made for a resource with credentials, if this header is not returned
+    /// with the resource, the response is ignored by the browser and not
+    /// returned to web content.
+    ///
+    /// The Access-Control-Allow-Credentials header works in conjunction with
+    /// the XMLHttpRequest.withCredentials property or with the credentials
+    /// option in the Request() constructor of the Fetch API. Credentials must
+    /// be set on both sides (the Access-Control-Allow-Credentials header and in
+    /// the XHR or Fetch request) in order for the CORS request with credentials
+    /// to succeed.
+    "#,
+    "access-control-allow-credentials";
+
+    r#"
+    /// Preflight response indicating permitted HTTP headers.
+    ///
+    /// The Access-Control-Allow-Headers response header is used in response to
+    /// a preflight request to indicate which HTTP headers will be available via
+    /// Access-Control-Expose-Headers when making the actual request.
+    ///
+    /// The simple headers, Accept, Accept-Language, Content-Language,
+    /// Content-Type (but only with a MIME type of its parsed value (ignoring
+    /// parameters) of either application/x-www-form-urlencoded,
+    /// multipart/form-data, or text/plain), are always available and don't need
+    /// to be listed by this header.
+    ///
+    /// This header is required if the request has an
+    /// Access-Control-Request-Headers header.
+    "#,
+    "access-control-allow-headers";
+
+    r#"
+    /// Preflight header response indicating permitted access methods.
+    ///
+    /// The Access-Control-Allow-Methods response header specifies the method or
+    /// methods allowed when accessing the resource in response to a preflight
+    /// request.
+    "#,
+    "access-control-allow-methods";
+
+
+    r#"
+    /// Indicates whether the response can be shared with resources with the
+    /// given origin.
+    "#,
+    "access-control-allow-origin";
+
+    r#"
+    /// Indicates which headers can be exposed as part of the response by
+    /// listing their names.
+    "#,
+    "access-control-expose-headers";
+
+    r#"
+    /// Indicates how long the results of a preflight request can be cached.
+    "#,
+    "access-control-max-age";
+
+    r#"
+    /// Informs the server which HTTP headers will be used when an actual
+    /// request is made.
+    "#,
+    "access-control-request-headers";
+
+    r#"
+    /// Informs the server know which HTTP method will be used when the actual
+    /// request is made.
+    "#,
+    "access-control-request-method";
+
+    r#"
+    /// Indicates the time in seconds the object has been in a proxy cache.
+    ///
+    /// The Age header is usually close to zero. If it is Age: 0, it was
+    /// probably just fetched from the origin server; otherwise It is usually
+    /// calculated as a difference between the proxy's current date and the Date
+    /// general header included in the HTTP response.
+    "#,
+    "age";
+
+    r#"
+    /// Lists the set of methods support by a resource.
+    ///
+    /// This header must be sent if the server responds with a 405 Method Not
+    /// Allowed status code to indicate which request methods can be used. An
+    /// empty Allow header indicates that the resource allows no request
+    /// methods, which might occur temporarily for a given resource, for
+    /// example.
+    "#,
+    "allow";
+
+    r#"
+    /// Advertises the availability of alternate services to clients.
+    "#,
+    "alt-svc";
+
+    r#"
+    /// Contains the credentials to authenticate a user agent with a server.
+    ///
+    /// Usually this header is included after the server has responded with a
+    /// 401 Unauthorized status and the WWW-Authenticate header.
+    "#,
+    "authorization";
+
+    r#"
+    /// Specifies directives for caching mechanisms in both requests and
+    /// responses.
+    ///
+    /// Caching directives are unidirectional, meaning that a given directive in
+    /// a request is not implying that the same directive is to be given in the
+    /// response.
+    "#,
+    "cache-control";
+
+    r#"
+    /// Controls whether or not the network connection stays open after the
+    /// current transaction finishes.
+    ///
+    /// If the value sent is keep-alive, the connection is persistent and not
+    /// closed, allowing for subsequent requests to the same server to be done.
+    ///
+    /// Except for the standard hop-by-hop headers (Keep-Alive,
+    /// Transfer-Encoding, TE, Connection, Trailer, Upgrade, Proxy-Authorization
+    /// and Proxy-Authenticate), any hop-by-hop headers used by the message must
+    /// be listed in the Connection header, so that the first proxy knows he has
+    /// to consume them and not to forward them further. Standard hop-by-hop
+    /// headers can be listed too (it is often the case of Keep-Alive, but this
+    /// is not mandatory.
+    "#,
+    "connection";
+
+    r#"
+    /// Indicates if the content is expected to be displayed inline.
+    ///
+    /// In a regular HTTP response, the Content-Disposition response header is a
+    /// header indicating if the content is expected to be displayed inline in
+    /// the browser, that is, as a Web page or as part of a Web page, or as an
+    /// attachment, that is downloaded and saved locally.
+    ///
+    /// In a multipart/form-data body, the HTTP Content-Disposition general
+    /// header is a header that can be used on the subpart of a multipart body
+    /// to give information about the field it applies to. The subpart is
+    /// delimited by the boundary defined in the Content-Type header. Used on
+    /// the body itself, Content-Disposition has no effect.
+    ///
+    /// The Content-Disposition header is defined in the larger context of MIME
+    /// messages for e-mail, but only a subset of the possible parameters apply
+    /// to HTTP forms and POST requests. Only the value form-data, as well as
+    /// the optional directive name and filename, can be used in the HTTP
+    /// context.
+    "#,
+    "content-disposition";
+
+    r#"
+    /// Used to compress the media-type.
+    ///
+    /// When present, its value indicates what additional content encoding has
+    /// been applied to the entity-body. It lets the client know, how to decode
+    /// in order to obtain the media-type referenced by the Content-Type header.
+    ///
+    /// It is recommended to compress data as much as possible and therefore to
+    /// use this field, but some types of resources, like jpeg images, are
+    /// already compressed.  Sometimes using additional compression doesn't
+    /// reduce payload size and can even make the payload longer.
+    "#,
+    "content-encoding";
+
+    r#"
+    /// Used to describe the languages intended for the audience.
+    ///
+    /// This header allows a user to differentiate according to the users' own
+    /// preferred language. For example, if "Content-Language: de-DE" is set, it
+    /// says that the document is intended for German language speakers
+    /// (however, it doesn't indicate the document is written in German. For
+    /// example, it might be written in English as part of a language course for
+    /// German speakers).
+    ///
+    /// If no Content-Language is specified, the default is that the content is
+    /// intended for all language audiences. Multiple language tags are also
+    /// possible, as well as applying the Content-Language header to various
+    /// media types and not only to textual documents.
+    "#,
+    "content-language";
+
+    r#"
+    /// Indicates the size fo the entity-body.
+    ///
+    /// The header value must be a decimal indicating the number of octets sent
+    /// to the recipient.
+    "#,
+    "content-length";
+
+    r#"
+    /// Indicates an alternate location for the returned data.
+    ///
+    /// The principal use case is to indicate the URL of the resource
+    /// transmitted as the result of content negotiation.
+    ///
+    /// Location and Content-Location are different: Location indicates the
+    /// target of a redirection (or the URL of a newly created document), while
+    /// Content-Location indicates the direct URL to use to access the resource,
+    /// without the need of further content negotiation. Location is a header
+    /// associated with the response, while Content-Location is associated with
+    /// the entity returned.
+    "#,
+    "content-location";
+
+    r#"
+    /// Contains the MD5 digest of the entity-body.
+    ///
+    /// The Content-MD5 entity-header field, as defined in RFC 1864 [23], is an
+    /// MD5 digest of the entity-body for the purpose of providing an end-to-end
+    /// message integrity check (MIC) of the entity-body. (Note: a MIC is good
+    /// for detecting accidental modification of the entity-body in transit, but
+    /// is not proof against malicious attacks.)
+    "#,
+    "content-md5";
+
+    r#"
+    /// Indicates where in a full body message a partial message belongs.
+    "#,
+    "content-range";
+
+    r#"
+    /// Allows controlling resources the user agent is allowed to load for a
+    /// given page.
+    ///
+    /// With a few exceptions, policies mostly involve specifying server origins
+    /// and script endpoints. This helps guard against cross-site scripting
+    /// attacks (XSS).
+    "#,
+    "content-security-policy";
+
+    r#"
+    /// Allows experimenting with policies by monitoring their effects.
+    ///
+    /// The HTTP Content-Security-Policy-Report-Only response header allows web
+    /// developers to experiment with policies by monitoring (but not enforcing)
+    /// their effects. These violation reports consist of JSON documents sent
+    /// via an HTTP POST request to the specified URI.
+    "#,
+    "content-security-policy-report-only";
+
+    r#"
+    /// Used to indicate the media type of the resource.
+    ///
+    /// In responses, a Content-Type header tells the client what the content
+    /// type of the returned content actually is. Browsers will do MIME sniffing
+    /// in some cases and will not necessarily follow the value of this header;
+    /// to prevent this behavior, the header X-Content-Type-Options can be set
+    /// to nosniff.
+    ///
+    /// In requests, (such as POST or PUT), the client tells the server what
+    /// type of data is actually sent.
+    "#,
+    "content-type";
+
+    r#"
+    /// Contains stored HTTP cookies previously sent by the server with the
+    /// Set-Cookie header.
+    ///
+    /// The Cookie header might be omitted entirely, if the privacy setting of
+    /// the browser are set to block them, for example.
+    "#,
+    "cookie";
+
+    r#"
+    /// Indicates the client's tracking preference.
+    ///
+    /// This header lets users indicate whether they would prefer privacy rather
+    /// than personalized content.
+    "#,
+    "dnt";
+
+    r#"
+    /// Contains the date and time at which the message was originated.
+    "#,
+    "date";
+
+    r#"
+    /// Identifier for a specific version of a resource.
+    ///
+    /// This header allows caches to be more efficient, and saves bandwidth, as
+    /// a web server does not need to send a full response if the content has
+    /// not changed. On the other side, if the content has changed, etags are
+    /// useful to help prevent simultaneous updates of a resource from
+    /// overwriting each other ("mid-air collisions").
+    ///
+    /// If the resource at a given URL changes, a new Etag value must be
+    /// generated. Etags are therefore similar to fingerprints and might also be
+    /// used for tracking purposes by some servers. A comparison of them allows
+    /// to quickly determine whether two representations of a resource are the
+    /// same, but they might also be set to persist indefinitely by a tracking
+    /// server.
+    "#,
+    "etag";
+
+    r#"
+    /// Indicates expectations that need to be fulfilled by the server in order
+    /// to properly handle the request.
+    ///
+    /// The only expectation defined in the specification is Expect:
+    /// 100-continue, to which the server shall respond with:
+    ///
+    /// * 100 if the information contained in the header is sufficient to cause
+    /// an immediate success,
+    ///
+    /// * 417 (Expectation Failed) if it cannot meet the expectation; or any
+    /// other 4xx status otherwise.
+    ///
+    /// For example, the server may reject a request if its Content-Length is
+    /// too large.
+    ///
+    /// No common browsers send the Expect header, but some other clients such
+    /// as cURL do so by default.
+    "#,
+    "expect";
+
+    r#"
+    /// Contains the date/time after which the response is considered stale.
+    ///
+    /// Invalid dates, like the value 0, represent a date in the past and mean
+    /// that the resource is already expired.
+    ///
+    /// If there is a Cache-Control header with the "max-age" or "s-max-age"
+    /// directive in the response, the Expires header is ignored.
+    "#,
+    "expires";
+
+    r#"
+    /// Contains information from the client-facing side of proxy servers that
+    /// is altered or lost when a proxy is involved in the path of the request.
+    ///
+    /// The alternative and de-facto standard versions of this header are the
+    /// X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Proto headers.
+    ///
+    /// This header is used for debugging, statistics, and generating
+    /// location-dependent content and by design it exposes privacy sensitive
+    /// information, such as the IP address of the client. Therefore the user's
+    /// privacy must be kept in mind when deploying this header.
+    "#,
+    "forwarded";
+
+    r#"
+    /// Contains an Internet email address for a human user who controls the
+    /// requesting user agent.
+    ///
+    /// If you are running a robotic user agent (e.g. a crawler), the From
+    /// header should be sent, so you can be contacted if problems occur on
+    /// servers, such as if the robot is sending excessive, unwanted, or invalid
+    /// requests.
+    "#,
+    "from";
+
+    r#"
+    /// Specifies the domain name of the server and (optionally) the TCP port
+    /// number on which the server is listening.
+    ///
+    /// If no port is given, the default port for the service requested (e.g.,
+    /// "80" for an HTTP URL) is implied.
+    ///
+    /// A Host header field must be sent in all HTTP/1.1 request messages. A 400
+    /// (Bad Request) status code will be sent to any HTTP/1.1 request message
+    /// that lacks a Host header field or contains more than one.
+    "#,
+    "host";
+
+    r#"
+    /// Makes a request conditional based on the E-Tag.
+    ///
+    /// For GET and HEAD methods, the server will send back the requested
+    /// resource only if it matches one of the listed ETags. For PUT and other
+    /// non-safe methods, it will only upload the resource in this case.
+    ///
+    /// The comparison with the stored ETag uses the strong comparison
+    /// algorithm, meaning two files are considered identical byte to byte only.
+    /// This is weakened when the  W/ prefix is used in front of the ETag.
+    ///
+    /// There are two common use cases:
+    ///
+    /// * For GET and HEAD methods, used in combination with an Range header, it
+    /// can guarantee that the new ranges requested comes from the same resource
+    /// than the previous one. If it doesn't match, then a 416 (Range Not
+    /// Satisfiable) response is returned.
+    ///
+    /// * For other methods, and in particular for PUT, If-Match can be used to
+    /// prevent the lost update problem. It can check if the modification of a
+    /// resource that the user wants to upload will not override another change
+    /// that has been done since the original resource was fetched. If the
+    /// request cannot be fulfilled, the 412 (Precondition Failed) response is
+    /// returned.
+    "#,
+    "if-match";
+
+    r#"
+    /// Makes a request conditional based on the modification date.
+    ///
+    /// The If-Modified-Since request HTTP header makes the request conditional:
+    /// the server will send back the requested resource, with a 200 status,
+    /// only if it has been last modified after the given date. If the request
+    /// has not been modified since, the response will be a 304 without any
+    /// body; the Last-Modified header will contain the date of last
+    /// modification. Unlike If-Unmodified-Since, If-Modified-Since can only be
+    /// used with a GET or HEAD.
+    ///
+    /// When used in combination with If-None-Match, it is ignored, unless the
+    /// server doesn't support If-None-Match.
+    ///
+    /// The most common use case is to update a cached entity that has no
+    /// associated ETag.
+    "#,
+    "if-modified-since";
+
+    r#"
+    /// Makes a request conditional based on the E-Tag.
+    ///
+    /// The If-None-Match HTTP request header makes the request conditional. For
+    /// GET and HEAD methods, the server will send back the requested resource,
+    /// with a 200 status, only if it doesn't have an ETag matching the given
+    /// ones. For other methods, the request will be processed only if the
+    /// eventually existing resource's ETag doesn't match any of the values
+    /// listed.
+    ///
+    /// When the condition fails for GET and HEAD methods, then the server must
+    /// return HTTP status code 304 (Not Modified). For methods that apply
+    /// server-side changes, the status code 412 (Precondition Failed) is used.
+    /// Note that the server generating a 304 response MUST generate any of the
+    /// following header fields that would have been sent in a 200 (OK) response
+    /// to the same request: Cache-Control, Content-Location, Date, ETag,
+    /// Expires, and Vary.
+    ///
+    /// The comparison with the stored ETag uses the weak comparison algorithm,
+    /// meaning two files are considered identical not only if they are
+    /// identical byte to byte, but if the content is equivalent. For example,
+    /// two pages that would differ only by the date of generation in the footer
+    /// would be considered as identical.
+    ///
+    /// When used in combination with If-Modified-Since, it has precedence (if
+    /// the server supports it).
+    ///
+    /// There are two common use cases:
+    ///
+    /// * For `GET` and `HEAD` methods, to update a cached entity that has an associated ETag.
+    /// * For other methods, and in particular for `PUT`, `If-None-Match` used with
+    /// the `*` value can be used to save a file not known to exist,
+    /// guaranteeing that another upload didn't happen before, losing the data
+    /// of the previous put; this problems is the variation of the lost update
+    /// problem.
+    "#,
+    "if-none-match";
+
+    r#"
+    /// Makes a request conditional based on range.
+    ///
+    /// The If-Range HTTP request header makes a range request conditional: if
+    /// the condition is fulfilled, the range request will be issued and the
+    /// server sends back a 206 Partial Content answer with the appropriate
+    /// body. If the condition is not fulfilled, the full resource is sent back,
+    /// with a 200 OK status.
+    ///
+    /// This header can be used either with a Last-Modified validator, or with
+    /// an ETag, but not with both.
+    ///
+    /// The most common use case is to resume a download, to guarantee that the
+    /// stored resource has not been modified since the last fragment has been
+    /// received.
+    "#,
+    "if-range";
+
+    r#"
+    /// Makes the request conditional based on the last modification date.
+    ///
+    /// The If-Unmodified-Since request HTTP header makes the request
+    /// conditional: the server will send back the requested resource, or accept
+    /// it in the case of a POST or another non-safe method, only if it has not
+    /// been last modified after the given date. If the request has been
+    /// modified after the given date, the response will be a 412 (Precondition
+    /// Failed) error.
+    ///
+    /// There are two common use cases:
+    ///
+    /// * In conjunction non-safe methods, like POST, it can be used to
+    /// implement an optimistic concurrency control, like done by some wikis:
+    /// editions are rejected if the stored document has been modified since the
+    /// original has been retrieved.
+    ///
+    /// * In conjunction with a range request with a If-Range header, it can be
+    /// used to ensure that the new fragment requested comes from an unmodified
+    /// document.
+    "#,
+    "if-unmodified-since";
+
+    r#"
+    /// Content-Types that are acceptable for the response.
+    "#,
+    "last-modified";
+
+    r#"
+    /// Hint about how the connection and may be used to set a timeout and a
+    /// maximum amount of requests.
+    "#,
+    "keep-alive";
+
+    r#"
+    /// Allows the server to point an interested client to another resource
+    /// containing metadata about the requested resource.
+    "#,
+    "link";
+
+    r#"
+    /// Indicates the URL to redirect a page to.
+    ///
+    /// The Location response header indicates the URL to redirect a page to. It
+    /// only provides a meaning when served with a 3xx status response.
+    ///
+    /// The HTTP method used to make the new request to fetch the page pointed
+    /// to by Location depends of the original method and of the kind of
+    /// redirection:
+    ///
+    /// * If 303 (See Also) responses always lead to the use of a GET method,
+    /// 307 (Temporary Redirect) and 308 (Permanent Redirect) don't change the
+    /// method used in the original request;
+    ///
+    /// * 301 (Permanent Redirect) and 302 (Found) doesn't change the method
+    /// most of the time, though older user-agents may (so you basically don't
+    /// know).
+    ///
+    /// All responses with one of these status codes send a Location header.
+    ///
+    /// Beside redirect response, messages with 201 (Created) status also
+    /// include the Location header. It indicates the URL to the newly created
+    /// resource.
+    ///
+    /// Location and Content-Location are different: Location indicates the
+    /// target of a redirection (or the URL of a newly created resource), while
+    /// Content-Location indicates the direct URL to use to access the resource
+    /// when content negotiation happened, without the need of further content
+    /// negotiation. Location is a header associated with the response, while
+    /// Content-Location is associated with the entity returned.
+    "#,
+    "location";
+
+    r#"
+    /// Indicates the max number of intermediaries the request should be sent
+    /// through.
+    "#,
+    "max-forwards";
+
+    r#"
+    /// Indicates where a fetch originates from.
+    ///
+    /// It doesn't include any path information, but only the server name. It is
+    /// sent with CORS requests, as well as with POST requests. It is similar to
+    /// the Referer header, but, unlike this header, it doesn't disclose the
+    /// whole path.
+    "#,
+    "origin";
+
+    r#"
+    /// HTTP/1.0 header usually used for backwards compatibility.
+    ///
+    /// The Pragma HTTP/1.0 general header is an implementation-specific header
+    /// that may have various effects along the request-response chain. It is
+    /// used for backwards compatibility with HTTP/1.0 caches where the
+    /// Cache-Control HTTP/1.1 header is not yet present.
+    "#,
+    "pragma";
+
+    r#"
+    /// Defines the authentication method that should be used to gain access to
+    /// a proxy.
+    ///
+    /// Unlike `www-authenticate`, the `proxy-authenticate` header field applies
+    /// only to the next outbound client on the response chain. This is because
+    /// only the client that chose a given proxy is likely to have the
+    /// credentials necessary for authentication. However, when multiple proxies
+    /// are used within the same administrative domain, such as office and
+    /// regional caching proxies within a large corporate network, it is common
+    /// for credentials to be generated by the user agent and passed through the
+    /// hierarchy until consumed. Hence, in such a configuration, it will appear
+    /// as if Proxy-Authenticate is being forwarded because each proxy will send
+    /// the same challenge set.
+    ///
+    /// The `proxy-authenticate` header is sent along with a `407 Proxy
+    /// Authentication Required`.
+    "#,
+    "proxy-authenticate";
+
+    r#"
+    /// Contains the credentials to authenticate a user agent to a proxy server.
+    ///
+    /// This header is usually included after the server has responded with a
+    /// 407 Proxy Authentication Required status and the Proxy-Authenticate
+    /// header.
+    "#,
+    "proxy-authorization";
+
+    r#"
+    /// Associates a specific cryptographic public key with a certain server.
+    ///
+    /// This decreases the risk of MITM attacks with forged certificates. If one
+    /// or several keys are pinned and none of them are used by the server, the
+    /// browser will not accept the response as legitimate, and will not display
+    /// it.
+    "#,
+    "public-key-pins";
+
+    r#"
+    /// Sends reports of pinning violation to the report-uri specified in the
+    /// header.
+    ///
+    /// Unlike `Public-Key-Pins`, this header still allows browsers to connect
+    /// to the server if the pinning is violated.
+    "#,
+    "public-key-pins-report-only";
+
+    r#"
+    /// Indicates the part of a document that the server should return.
+    ///
+    /// Several parts can be requested with one Range header at once, and the
+    /// server may send back these ranges in a multipart document. If the server
+    /// sends back ranges, it uses the 206 Partial Content for the response. If
+    /// the ranges are invalid, the server returns the 416 Range Not Satisfiable
+    /// error. The server can also ignore the Range header and return the whole
+    /// document with a 200 status code.
+    "#,
+    "range";
+
+    r#"
+    /// Contains the address of the previous web page from which a link to the
+    /// currently requested page was followed.
+    ///
+    /// The Referer header allows servers to identify where people are visiting
+    /// them from and may use that data for analytics, logging, or optimized
+    /// caching, for example.
+    "#,
+    "referer";
+
+    r#"
+    /// Governs which referrer information should be included with requests
+    /// made.
+    "#,
+    "referrer-policy";
+
+    r#"
+    /// Informs the web browser that the current page or frame should be
+    /// refreshed.
+    "#,
+    "refresh";
+
+    r#"
+    /// The Retry-After response HTTP header indicates how long the user agent
+    /// should wait before making a follow-up request. There are two main cases
+    /// this header is used:
+    ///
+    /// * When sent with a 503 (Service Unavailable) response, it indicates how
+    /// long the service is expected to be unavailable.
+    ///
+    /// * When sent with a redirect response, such as 301 (Moved Permanently),
+    /// it indicates the minimum time that the user agent is asked to wait
+    /// before issuing the redirected request.
+    "#,
+    "retry-after";
+
+    r#"
+    /// Contains information about the software used by the origin server to
+    /// handle the request.
+    ///
+    /// Overly long and detailed Server values should be avoided as they
+    /// potentially reveal internal implementation details that might make it
+    /// (slightly) easier for attackers to find and exploit known security
+    /// holes.
+    "#,
+    "server";
+
+    r#"
+    /// Used to send cookies from the server to the user agent.
+    "#,
+    "set-cookie";
+
+    r#"
+    /// Tells the client to communicate with HTTPS instead of using HTTP.
+    "#,
+    "strict-transport-security";
+
+    r#"
+    /// Informs the server of transfer encodings willing to be accepted as part
+    /// of the response.
+    ///
+    /// See also the Transfer-Encoding response header for more details on
+    /// transfer encodings. Note that chunked is always acceptable for HTTP/1.1
+    /// recipients and you that don't have to specify "chunked" using the TE
+    /// header. However, it is useful for setting if the client is accepting
+    /// trailer fields in a chunked transfer coding using the "trailers" value.
+    "#,
+    "te";
+
+    r#"
+    /// Indicates the tracking status that applied to the corresponding request.
+    "#,
+    "tk";
+
+    r#"
+    /// Allows the sender to include additional fields at the end of chunked
+    /// messages.
+    "#,
+    "trailer";
+
+    r#"
+    /// Specifies the form of encoding used to safely transfer the entity to the
+    /// client.
+    ///
+    /// `transfer-encoding` is a hop-by-hop header, that is applying to a
+    /// message between two nodes, not to a resource itself. Each segment of a
+    /// multi-node connection can use different `transfer-encoding` values. If
+    /// you want to compress data over the whole connection, use the end-to-end
+    /// header `content-encoding` header instead.
+    ///
+    /// When present on a response to a `HEAD` request that has no body, it
+    /// indicates the value that would have applied to the corresponding `GET`
+    /// message.
+    "#,
+    "transfer-encoding";
+
+    r#"
+    /// A response to the client's tracking preference.
+    ///
+    /// A tracking status value (TSV) is a single character response to the
+    /// user's tracking preference with regard to data collected via the
+    /// designated resource. For a site-wide tracking status resource, the
+    /// designated resource is any resource on the same origin server. For a Tk
+    /// response header field, the target resource of the corresponding request
+    /// is the designated resource, and remains so for any subsequent
+    /// request-specific tracking status resource referred to by the Tk field
+    /// value.
+    "#,
+    "tsv";
+
+    r#"
+    /// Contains a string that allows identifying the requesting client's
+    /// software.
+    "#,
+    "user-agent";
+
+    r#"
+    /// Used as part of the exchange to upgrade the protocol.
+    "#,
+    "upgrade";
+
+    r#"
+    /// Sends a signal to the server expressing the client’s preference for an
+    /// encrypted and authenticated response.
+    "#,
+    "upgrade-insecure-requests";
+
+    r#"
+    /// Determines how to match future requests with cached responses.
+    ///
+    /// The `vary` HTTP response header determines how to match future request
+    /// headers to decide whether a cached response can be used rather than
+    /// requesting a fresh one from the origin server. It is used by the server
+    /// to indicate which headers it used when selecting a representation of a
+    /// resource in a content negotiation algorithm.
+    ///
+    /// The `vary` header should be set on a 304 Not Modified response exactly
+    /// like it would have been set on an equivalent 200 OK response.
+    "#,
+    "vary";
+
+    r#"
+    /// Added by proxies to track routing.
+    ///
+    /// The `via` general header is added by proxies, both forward and reverse
+    /// proxies, and can appear in the request headers and the response headers.
+    /// It is used for tracking message forwards, avoiding request loops, and
+    /// identifying the protocol capabilities of senders along the
+    /// request/response chain.
+    "#,
+    "via";
+
+    r#"
+    /// General HTTP header contains information about possible problems with
+    /// the status of the message.
+    ///
+    /// More than one `warning` header may appear in a response. Warning header
+    /// fields can in general be applied to any message, however some warn-codes
+    /// are specific to caches and can only be applied to response messages.
+    "#,
+    "warning";
+
+    r#"
+    /// Defines the authentication method that should be used to gain access to
+    /// a resource.
+    "#,
+    "www-authenticate";
+
+    r#"
+    /// Marker used by the server to indicate that the MIME types advertised in
+    /// the `content-type` headers should not be changed and be followed.
+    ///
+    /// This allows to opt-out of MIME type sniffing, or, in other words, it is
+    /// a way to say that the webmasters knew what they were doing.
+    ///
+    /// This header was introduced by Microsoft in IE 8 as a way for webmasters
+    /// to block content sniffing that was happening and could transform
+    /// non-executable MIME types into executable MIME types. Since then, other
+    /// browsers have introduced it, even if their MIME sniffing algorithms were
+    /// less aggressive.
+    ///
+    /// Site security testers usually expect this header to be set.
+    "#,
+    "x-content-type-options";
+
+    r#"
+    /// Controls DNS prefetching.
+    ///
+    /// The `x-dns-prefetch-control` HTTP response header controls DNS
+    /// prefetching, a feature by which browsers proactively perform domain name
+    /// resolution on both links that the user may choose to follow as well as
+    /// URLs for items referenced by the document, including images, CSS,
+    /// JavaScript, and so forth.
+    ///
+    /// This prefetching is performed in the background, so that the DNS is
+    /// likely to have been resolved by the time the referenced items are
+    /// needed. This reduces latency when the user clicks a link.
+    "#,
+    "x-dns-prefetch-control";
+
+    r#"
+    /// Indicates whether or not a browser should be allowed to render a page in
+    /// a frame.
+    ///
+    /// Sites can use this to avoid clickjacking attacks, by ensuring that their
+    /// content is not embedded into other sites.
+    ///
+    /// The added security is only provided if the user accessing the document
+    /// is using a browser supporting `x-frame-options`.
+    "#,
+    "x-frame-options";
+
+    r#"
+    /// Stop pages from loading when an XSS attack is detected.
+    ///
+    /// The HTTP X-XSS-Protection response header is a feature of Internet
+    /// Explorer, Chrome and Safari that stops pages from loading when they
+    /// detect reflected cross-site scripting (XSS) attacks. Although these
+    /// protections are largely unnecessary in modern browsers when sites
+    /// implement a strong Content-Security-Policy that disables the use of
+    /// inline JavaScript ('unsafe-inline'), they can still provide protections
+    /// for users of older web browsers that don't yet support CSP.
+    "#,
+    "x-xss-protection";
+}
+
+fn constantize(s: &str) -> String {
+    let parts = s.split("-").map(|s| {
+        s.chars().enumerate().map(|(n, c)| {
+            if n == 0 {
+                c.to_uppercase().to_string()
+            } else {
+                c.to_string()
+            }
+        })
+    });
+
+    let mut res = String::new();
+
+    for part in parts {
+        res.extend(part);
+    }
+
+    res
+}
+
+fn upcase(s: &str) -> String {
+    let mut ret = String::new();
+
+    for ch in s.chars() {
+        if ch == '-' {
+            ret.push('_');
+        } else {
+            for ch in ch.to_uppercase() {
+                ret.push(ch);
+            }
+        }
+    }
+
+    ret
+}
+
+pub fn main() {
+    for &(doc, string) in HEADERS.iter() {
+        println!("{}", &doc[1..doc.len()-5]);
+        println!("    ({}, {}, {:?});", constantize(string), upcase(string), string);
+        println!("");
+    }
+}



More information about the Pkg-rust-maintainers mailing list