Skip to content

Commit

Permalink
Merge branch 'master' into cookie_store_14
Browse files Browse the repository at this point in the history
* master:
  add option to disable http2 upgrade (seanmonstar#1292)
  Fix documentation of http1_title_case_headers() (seanmonstar#1294)
  CI: make a single final job that depends on all others (seanmonstar#1291)
  Fix bare url warnings in `multipart` docs (seanmonstar#1289)
  v0.11.4
  Allow overriding of DNS resolution to specified IP addresses(seanmonstar#561) (seanmonstar#1277)
  WASM: Add `try_clone` implementations to `Request` and `RequestBuilder` (seanmonstar#1286)
  Add native-tls-alpn feature (seanmonstar#1283)
  • Loading branch information
pfernie committed Jun 25, 2021
2 parents 197dbb8 + bccefe7 commit f674e6d
Show file tree
Hide file tree
Showing 11 changed files with 407 additions and 40 deletions.
16 changes: 15 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ env:
RUST_BACKTRACE: 1

jobs:
ci-pass:
name: CI is green
runs-on: ubuntu-latest
needs:
- style
- test
- nightly
- minversion
- android
- wasm
- docs
steps:
- run: exit 0

style:
name: Check Style

Expand Down Expand Up @@ -38,7 +52,7 @@ jobs:
# Workaround for rust-lang/cargo#7732
run: cargo fmt -- --check $(find . -name '*.rs' -print)

build:
test:
name: ${{ matrix.name }}
needs: [style]

Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## v0.11.4

- Add `ClientBuilder::resolve()` option to override DNS resolution for specific domains.
- Add `native-tls-alpn` Cargo feature to use ALPN with the native-tls backend.
- Add `ClientBuilder::deflate()` option and `deflate` Cargo feature to support decoding response bodies using deflate.
- Add `RequestBuilder::version()` to allow setting the HTTP version of a request.
- Fix allowing "invalid" certificates with the `rustls-tls` backend, when the server uses TLS v1.2 or v1.3.
- (wasm) Add `try_clone` to `Request` and `RequestBuilder`

## v0.11.3

- Add `impl From<hyper::Body> for reqwest::Body`.
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "reqwest"
version = "0.11.3" # remember to update html_root_url
version = "0.11.4" # remember to update html_root_url
description = "higher level HTTP client library"
keywords = ["http", "request", "client"]
categories = ["web-programming::http-client", "wasm"]
Expand Down Expand Up @@ -34,6 +34,7 @@ default-tls = ["hyper-tls", "native-tls-crate", "__tls", "tokio-native-tls"]

# Enables native-tls specific functionality not available by default.
native-tls = ["default-tls"]
native-tls-alpn = ["native-tls", "native-tls-crate/alpn"]
native-tls-vendored = ["native-tls", "native-tls-crate/vendored"]

rustls-tls = ["rustls-tls-webpki-roots"]
Expand Down Expand Up @@ -197,7 +198,6 @@ path = "examples/form.rs"
[[example]]
name = "simple"
path = "examples/simple.rs"
required-features = ["deflate"]

[[test]]
name = "blocking"
Expand Down
94 changes: 81 additions & 13 deletions src/async_impl/client.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#[cfg(any(feature = "native-tls", feature = "__rustls",))]
use std::any::Any;
use std::convert::TryInto;
use std::net::IpAddr;
use std::sync::Arc;
use std::time::Duration;
use std::{collections::HashMap, convert::TryInto, net::SocketAddr};
use std::{fmt, str};

use bytes::Bytes;
Expand Down Expand Up @@ -68,6 +68,12 @@ pub struct ClientBuilder {
config: Config,
}

enum HttpVersionPref {
Http1,
Http2,
All,
}

struct Config {
// NOTE: When adding a new field, update `fmt::Debug for ClientBuilder`
accepts: Accepts,
Expand All @@ -94,7 +100,7 @@ struct Config {
tls_built_in_root_certs: bool,
#[cfg(feature = "__tls")]
tls: TlsBackend,
http2_only: bool,
http_version_pref: HttpVersionPref,
http1_title_case_headers: bool,
http2_initial_stream_window_size: Option<u32>,
http2_initial_connection_window_size: Option<u32>,
Expand All @@ -107,6 +113,7 @@ struct Config {
trust_dns: bool,
error: Option<crate::Error>,
https_only: bool,
dns_overrides: HashMap<String, SocketAddr>,
}

impl Default for ClientBuilder {
Expand Down Expand Up @@ -152,7 +159,7 @@ impl ClientBuilder {
identity: None,
#[cfg(feature = "__tls")]
tls: TlsBackend::default(),
http2_only: false,
http_version_pref: HttpVersionPref::All,
http1_title_case_headers: false,
http2_initial_stream_window_size: None,
http2_initial_connection_window_size: None,
Expand All @@ -164,6 +171,7 @@ impl ClientBuilder {
#[cfg(feature = "cookies")]
cookie_store: None,
https_only: false,
dns_overrides: HashMap::new(),
},
}
}
Expand Down Expand Up @@ -194,9 +202,21 @@ impl ClientBuilder {
}

let http = match config.trust_dns {
false => HttpConnector::new_gai(),
false => {
if config.dns_overrides.is_empty() {
HttpConnector::new_gai()
} else {
HttpConnector::new_gai_with_overrides(config.dns_overrides)
}
}
#[cfg(feature = "trust-dns")]
true => HttpConnector::new_trust_dns()?,
true => {
if config.dns_overrides.is_empty() {
HttpConnector::new_trust_dns()?
} else {
HttpConnector::new_trust_dns_with_overrides(config.dns_overrides)?
}
}
#[cfg(not(feature = "trust-dns"))]
true => unreachable!("trust-dns shouldn't be enabled unless the feature is"),
};
Expand All @@ -207,6 +227,21 @@ impl ClientBuilder {
TlsBackend::Default => {
let mut tls = TlsConnector::builder();

#[cfg(feature = "native-tls-alpn")]
{
match config.http_version_pref {
HttpVersionPref::Http1 => {
tls.request_alpns(&["http/1.1"]);
}
HttpVersionPref::Http2 => {
tls.request_alpns(&["h2"]);
}
HttpVersionPref::All => {
tls.request_alpns(&["h2", "http/1.1"]);
}
}
}

#[cfg(feature = "native-tls")]
{
tls.danger_accept_invalid_hostnames(!config.hostname_verification);
Expand Down Expand Up @@ -259,10 +294,16 @@ impl ClientBuilder {
use crate::tls::NoVerifier;

let mut tls = rustls::ClientConfig::new();
if config.http2_only {
tls.set_protocols(&["h2".into()]);
} else {
tls.set_protocols(&["h2".into(), "http/1.1".into()]);
match config.http_version_pref {
HttpVersionPref::Http1 => {
tls.set_protocols(&["http/1.1".into()]);
}
HttpVersionPref::Http2 => {
tls.set_protocols(&["h2".into()]);
}
HttpVersionPref::All => {
tls.set_protocols(&["h2".into(), "http/1.1".into()]);
}
}
#[cfg(feature = "rustls-tls-webpki-roots")]
if config.tls_built_in_root_certs {
Expand Down Expand Up @@ -313,7 +354,7 @@ impl ClientBuilder {
connector.set_verbose(config.connection_verbose);

let mut builder = hyper::Client::builder();
if config.http2_only {
if matches!(config.http_version_pref, HttpVersionPref::Http2) {
builder.http2_only(true);
}

Expand Down Expand Up @@ -708,15 +749,21 @@ impl ClientBuilder {
self
}

/// Enable case sensitive headers.
/// Send headers as title case instead of lowercase.
pub fn http1_title_case_headers(mut self) -> ClientBuilder {
self.config.http1_title_case_headers = true;
self
}

/// Only use HTTP/1.
pub fn http1_only(mut self) -> ClientBuilder {
self.config.http_version_pref = HttpVersionPref::Http1;
self
}

/// Only use HTTP/2.
pub fn http2_prior_knowledge(mut self) -> ClientBuilder {
self.config.http2_only = true;
self.config.http_version_pref = HttpVersionPref::Http2;
self
}

Expand Down Expand Up @@ -1028,6 +1075,19 @@ impl ClientBuilder {
self.config.https_only = enabled;
self
}

/// Override DNS resolution for specific domains to particular IP addresses.
///
/// Warning
///
/// Since the DNS protocol has no notion of ports, if you wish to send
/// traffic to a particular port you must include this port in the URL
/// itself, any port in the overridden addr will be ignored and traffic sent
/// to the conventional port for the given scheme (e.g. 80 for http).
pub fn resolve(mut self, domain: &str, addr: SocketAddr) -> ClientBuilder {
self.config.dns_overrides.insert(domain.to_string(), addr);
self
}
}

type HyperClient = hyper::Client<Connector, super::body::ImplStream>;
Expand Down Expand Up @@ -1303,7 +1363,11 @@ impl Config {
f.field("http1_title_case_headers", &true);
}

if self.http2_only {
if matches!(self.http_version_pref, HttpVersionPref::Http1) {
f.field("http1_only", &true);
}

if matches!(self.http_version_pref, HttpVersionPref::Http2) {
f.field("http2_prior_knowledge", &true);
}

Expand Down Expand Up @@ -1341,6 +1405,10 @@ impl Config {
{
f.field("tls_backend", &self.tls);
}

if !self.dns_overrides.is_empty() {
f.field("dns_overrides", &self.dns_overrides);
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/async_impl/multipart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,20 +408,20 @@ impl PartMetadata {
}
}

/// https://url.spec.whatwg.org/#fragment-percent-encode-set
// https://url.spec.whatwg.org/#fragment-percent-encode-set
const FRAGMENT_ENCODE_SET: &AsciiSet = &percent_encoding::CONTROLS
.add(b' ')
.add(b'"')
.add(b'<')
.add(b'>')
.add(b'`');

/// https://url.spec.whatwg.org/#path-percent-encode-set
// https://url.spec.whatwg.org/#path-percent-encode-set
const PATH_ENCODE_SET: &AsciiSet = &FRAGMENT_ENCODE_SET.add(b'#').add(b'?').add(b'{').add(b'}');

const PATH_SEGMENT_ENCODE_SET: &AsciiSet = &PATH_ENCODE_SET.add(b'/').add(b'%');

/// https://tools.ietf.org/html/rfc8187#section-3.2.1
// https://tools.ietf.org/html/rfc8187#section-3.2.1
const ATTR_CHAR_ENCODE_SET: &AsciiSet = &NON_ALPHANUMERIC
.remove(b'!')
.remove(b'#')
Expand Down
7 changes: 6 additions & 1 deletion src/blocking/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,11 +399,16 @@ impl ClientBuilder {
self.with_inner(move |inner| inner.pool_max_idle_per_host(max))
}

/// Enable case sensitive headers.
/// Send headers as title case instead of lowercase.
pub fn http1_title_case_headers(self) -> ClientBuilder {
self.with_inner(|inner| inner.http1_title_case_headers())
}

/// Only use HTTP/1.
pub fn http1_only(self) -> ClientBuilder {
self.with_inner(|inner| inner.http1_only())
}

/// Only use HTTP/2.
pub fn http2_prior_knowledge(self) -> ClientBuilder {
self.with_inner(|inner| inner.http2_prior_knowledge())
Expand Down

0 comments on commit f674e6d

Please sign in to comment.