From 18dfac4fe2590f2e3a27e808c72fb26e6d9af98b Mon Sep 17 00:00:00 2001
From: bensadiku <43443348+bensadiku@users.noreply.github.com>
Date: Thu, 15 Apr 2021 04:03:22 +0200
Subject: [PATCH] Add `RequestBuilder::version()` method to set HTTP version
(#1243)
Closes #1240
---
src/async_impl/client.rs | 3 +-
src/async_impl/request.rs | 69 ++++++++++++++++++++++++++++++++++++---
src/blocking/request.rs | 45 +++++++++++++++++++++++--
3 files changed, 110 insertions(+), 7 deletions(-)
diff --git a/src/async_impl/client.rs b/src/async_impl/client.rs
index bbefbd0..4bdad5d 100644
--- a/src/async_impl/client.rs
+++ b/src/async_impl/client.rs
@@ -1106,7 +1106,7 @@ impl Client {
}
pub(super) fn execute_request(&self, req: Request) -> Pending {
- let (method, url, mut headers, body, timeout) = req.pieces();
+ let (method, url, mut headers, body, timeout, version) = req.pieces();
if url.scheme() != "http" && url.scheme() != "https" {
return Pending::new_err(error::url_bad_scheme(url));
}
@@ -1157,6 +1157,7 @@ impl Client {
let mut req = hyper::Request::builder()
.method(method.clone())
.uri(uri)
+ .version(version)
.body(body.into_stream())
.expect("valid request parts");
diff --git a/src/async_impl/request.rs b/src/async_impl/request.rs
index 3e089e9..504fd56 100644
--- a/src/async_impl/request.rs
+++ b/src/async_impl/request.rs
@@ -18,7 +18,7 @@ use super::response::Response;
use crate::header::CONTENT_LENGTH;
use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE};
use crate::{Method, Url};
-use http::{request::Parts, Request as HttpRequest};
+use http::{request::Parts, Request as HttpRequest, Version};
/// A request which can be executed with `Client::execute()`.
pub struct Request {
@@ -27,6 +27,7 @@ pub struct Request {
headers: HeaderMap,
body: Option
,
timeout: Option,
+ version: Version,
}
/// A builder to construct the properties of a `Request`.
@@ -48,6 +49,7 @@ impl Request {
headers: HeaderMap::new(),
body: None,
timeout: None,
+ version: Version::default(),
}
}
@@ -111,6 +113,18 @@ impl Request {
&mut self.timeout
}
+ /// Get the http version.
+ #[inline]
+ pub fn version(&self) -> Version {
+ self.version
+ }
+
+ /// Get a mutable reference to the http version.
+ #[inline]
+ pub fn version_mut(&mut self) -> &mut Version {
+ &mut self.version
+ }
+
/// Attempt to clone the request.
///
/// `None` is returned if the request can not be cloned, i.e. if the body is a stream.
@@ -122,12 +136,29 @@ impl Request {
let mut req = Request::new(self.method().clone(), self.url().clone());
*req.timeout_mut() = self.timeout().cloned();
*req.headers_mut() = self.headers().clone();
+ *req.version_mut() = self.version().clone();
req.body = body;
Some(req)
}
- pub(super) fn pieces(self) -> (Method, Url, HeaderMap, Option, Option) {
- (self.method, self.url, self.headers, self.body, self.timeout)
+ pub(super) fn pieces(
+ self,
+ ) -> (
+ Method,
+ Url,
+ HeaderMap,
+ Option,
+ Option,
+ Version,
+ ) {
+ (
+ self.method,
+ self.url,
+ self.headers,
+ self.body,
+ self.timeout,
+ self.version,
+ )
}
}
@@ -322,6 +353,14 @@ impl RequestBuilder {
self
}
+ /// Set HTTP version
+ pub fn version(mut self, version: Version) -> RequestBuilder {
+ if let Ok(ref mut req) = self.request {
+ req.version = version;
+ }
+ self
+ }
+
/// Send a form body.
pub fn form(mut self, form: &T) -> RequestBuilder {
let mut error = None;
@@ -516,6 +555,7 @@ where
method,
uri,
headers,
+ version,
..
} = parts;
let url = Url::parse(&uri.to_string()).map_err(crate::error::builder)?;
@@ -525,13 +565,14 @@ where
headers,
body: Some(body.into()),
timeout: None,
+ version: version,
})
}
}
#[cfg(test)]
mod tests {
- use super::{Client, HttpRequest, Request};
+ use super::{Client, HttpRequest, Request, Version};
use crate::Method;
use serde::Serialize;
use std::collections::BTreeMap;
@@ -753,6 +794,26 @@ mod tests {
assert_eq!(req.url().as_str(), "http://localhost/");
}
+ #[test]
+ fn set_http_request_version() {
+ let http_request = HttpRequest::builder()
+ .method("GET")
+ .uri("http://localhost/")
+ .header("User-Agent", "my-awesome-agent/1.0")
+ .version(Version::HTTP_11)
+ .body("test test test")
+ .unwrap();
+ let req: Request = Request::try_from(http_request).unwrap();
+ assert_eq!(req.body().is_none(), false);
+ let test_data = b"test test test";
+ assert_eq!(req.body().unwrap().as_bytes(), Some(&test_data[..]));
+ let headers = req.headers();
+ assert_eq!(headers.get("User-Agent").unwrap(), "my-awesome-agent/1.0");
+ assert_eq!(req.method(), Method::GET);
+ assert_eq!(req.url().as_str(), "http://localhost/");
+ assert_eq!(req.version(), Version::HTTP_11);
+ }
+
/*
use {body, Method};
use super::Client;
diff --git a/src/blocking/request.rs b/src/blocking/request.rs
index 7b36d3f..f0517ca 100644
--- a/src/blocking/request.rs
+++ b/src/blocking/request.rs
@@ -3,7 +3,7 @@ use std::fmt;
use std::time::Duration;
use base64::encode;
-use http::{request::Parts, Request as HttpRequest};
+use http::{request::Parts, Request as HttpRequest, Version};
use serde::Serialize;
#[cfg(feature = "json")]
use serde_json;
@@ -78,6 +78,18 @@ impl Request {
self.inner.headers_mut()
}
+ /// Get the http version.
+ #[inline]
+ pub fn version(&self) -> Version {
+ self.inner.version()
+ }
+
+ /// Get a mutable reference to the http version.
+ #[inline]
+ pub fn version_mut(&mut self) -> &mut Version {
+ self.inner.version_mut()
+ }
+
/// Get the body.
#[inline]
pub fn body(&self) -> Option<&Body> {
@@ -118,6 +130,7 @@ impl Request {
};
let mut req = Request::new(self.method().clone(), self.url().clone());
*req.headers_mut() = self.headers().clone();
+ *req.version_mut() = self.version().clone();
req.body = body;
Some(req)
}
@@ -394,6 +407,14 @@ impl RequestBuilder {
self
}
+ /// Set HTTP version
+ pub fn version(mut self, version: Version) -> RequestBuilder {
+ if let Ok(ref mut req) = self.request {
+ *req.version_mut() = version;
+ }
+ self
+ }
+
/// Send a form body.
///
/// Sets the body to the url encoded serialization of the passed value,
@@ -640,7 +661,7 @@ fn fmt_request_fields<'a, 'b>(
#[cfg(test)]
mod tests {
use super::super::{body, Client};
- use super::{HttpRequest, Request};
+ use super::{HttpRequest, Request, Version};
use crate::header::{HeaderMap, HeaderValue, ACCEPT, CONTENT_TYPE, HOST};
use crate::Method;
use serde::Serialize;
@@ -988,6 +1009,26 @@ mod tests {
assert_eq!(req.url().as_str(), "http://localhost/");
}
+ #[test]
+ fn set_http_request_version() {
+ let http_request = HttpRequest::builder()
+ .method("GET")
+ .uri("http://localhost/")
+ .header("User-Agent", "my-awesome-agent/1.0")
+ .version(Version::HTTP_11)
+ .body("test test test")
+ .unwrap();
+ let req: Request = Request::try_from(http_request).unwrap();
+ assert_eq!(req.body().is_none(), false);
+ let test_data = b"test test test";
+ assert_eq!(req.body().unwrap().as_bytes(), Some(&test_data[..]));
+ let headers = req.headers();
+ assert_eq!(headers.get("User-Agent").unwrap(), "my-awesome-agent/1.0");
+ assert_eq!(req.method(), Method::GET);
+ assert_eq!(req.url().as_str(), "http://localhost/");
+ assert_eq!(req.version(), Version::HTTP_11);
+ }
+
#[test]
fn test_basic_auth_sensitive_header() {
let client = Client::new();