mirror of
https://github.com/actix/actix-web.git
synced 2024-12-21 07:36:43 +00:00
use iota for more content-length insertions (#2050)
This commit is contained in:
parent
880b863f95
commit
ca69b6577e
8 changed files with 49 additions and 45 deletions
|
@ -1,4 +1,3 @@
|
||||||
use std::convert::TryFrom;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
|
@ -61,10 +60,14 @@ where
|
||||||
BodySize::Empty => req
|
BodySize::Empty => req
|
||||||
.headers_mut()
|
.headers_mut()
|
||||||
.insert(CONTENT_LENGTH, HeaderValue::from_static("0")),
|
.insert(CONTENT_LENGTH, HeaderValue::from_static("0")),
|
||||||
BodySize::Sized(len) => req.headers_mut().insert(
|
BodySize::Sized(len) => {
|
||||||
CONTENT_LENGTH,
|
let mut buf = itoa::Buffer::new();
|
||||||
HeaderValue::try_from(format!("{}", len)).unwrap(),
|
|
||||||
),
|
req.headers_mut().insert(
|
||||||
|
CONTENT_LENGTH,
|
||||||
|
HeaderValue::from_str(buf.format(len)).unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extracting extra headers from RequestHeadType. HeaderMap::new() does not allocate.
|
// Extracting extra headers from RequestHeadType. HeaderMap::new() does not allocate.
|
||||||
|
@ -87,7 +90,10 @@ where
|
||||||
// copy headers
|
// copy headers
|
||||||
for (key, value) in headers {
|
for (key, value) in headers {
|
||||||
match *key {
|
match *key {
|
||||||
CONNECTION | TRANSFER_ENCODING => continue, // http2 specific
|
// TODO: consider skipping other headers according to:
|
||||||
|
// https://tools.ietf.org/html/rfc7540#section-8.1.2.2
|
||||||
|
// omit HTTP/1.x only headers
|
||||||
|
CONNECTION | TRANSFER_ENCODING => continue,
|
||||||
CONTENT_LENGTH if skip_len => continue,
|
CONTENT_LENGTH if skip_len => continue,
|
||||||
// DATE => has_date = true,
|
// DATE => has_date = true,
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -632,10 +632,9 @@ mod tests {
|
||||||
|
|
||||||
let mut res: Response<()> =
|
let mut res: Response<()> =
|
||||||
Response::new(StatusCode::SWITCHING_PROTOCOLS).into_body::<()>();
|
Response::new(StatusCode::SWITCHING_PROTOCOLS).into_body::<()>();
|
||||||
|
res.headers_mut().insert(DATE, HeaderValue::from_static(""));
|
||||||
res.headers_mut()
|
res.headers_mut()
|
||||||
.insert(DATE, HeaderValue::from_static(&""));
|
.insert(CONTENT_LENGTH, HeaderValue::from_static("0"));
|
||||||
res.headers_mut()
|
|
||||||
.insert(CONTENT_LENGTH, HeaderValue::from_static(&"0"));
|
|
||||||
|
|
||||||
let _ = res.encode_headers(
|
let _ = res.encode_headers(
|
||||||
&mut bytes,
|
&mut bytes,
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
use std::future::Future;
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::net;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use std::{cmp, convert::TryFrom};
|
use std::{cmp, future::Future, marker::PhantomData, net, pin::Pin, rc::Rc};
|
||||||
|
|
||||||
use actix_codec::{AsyncRead, AsyncWrite};
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
use actix_rt::time::{Instant, Sleep};
|
use actix_rt::time::{Instant, Sleep};
|
||||||
|
@ -125,7 +120,7 @@ where
|
||||||
let pl = Payload::<crate::payload::PayloadStream>::H2(pl);
|
let pl = Payload::<crate::payload::PayloadStream>::H2(pl);
|
||||||
let mut req = Request::with_payload(pl);
|
let mut req = Request::with_payload(pl);
|
||||||
|
|
||||||
let head = &mut req.head_mut();
|
let head = req.head_mut();
|
||||||
head.uri = parts.uri;
|
head.uri = parts.uri;
|
||||||
head.method = parts.method;
|
head.method = parts.method;
|
||||||
head.version = parts.version;
|
head.version = parts.version;
|
||||||
|
@ -203,16 +198,22 @@ where
|
||||||
BodySize::Empty => res
|
BodySize::Empty => res
|
||||||
.headers_mut()
|
.headers_mut()
|
||||||
.insert(CONTENT_LENGTH, HeaderValue::from_static("0")),
|
.insert(CONTENT_LENGTH, HeaderValue::from_static("0")),
|
||||||
BodySize::Sized(len) => res.headers_mut().insert(
|
BodySize::Sized(len) => {
|
||||||
CONTENT_LENGTH,
|
let mut buf = itoa::Buffer::new();
|
||||||
HeaderValue::try_from(format!("{}", len)).unwrap(),
|
|
||||||
),
|
res.headers_mut().insert(
|
||||||
|
CONTENT_LENGTH,
|
||||||
|
HeaderValue::from_str(buf.format(*len)).unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// copy headers
|
// copy headers
|
||||||
for (key, value) in head.headers.iter() {
|
for (key, value) in head.headers.iter() {
|
||||||
match *key {
|
match *key {
|
||||||
// omit HTTP/1 only headers
|
// TODO: consider skipping other headers according to:
|
||||||
|
// https://tools.ietf.org/html/rfc7540#section-8.1.2.2
|
||||||
|
// omit HTTP/1.x only headers
|
||||||
CONNECTION | TRANSFER_ENCODING => continue,
|
CONNECTION | TRANSFER_ENCODING => continue,
|
||||||
CONTENT_LENGTH if skip_len => continue,
|
CONTENT_LENGTH if skip_len => continue,
|
||||||
DATE => has_date = true,
|
DATE => has_date = true,
|
||||||
|
|
|
@ -498,7 +498,8 @@ impl ResponseBuilder {
|
||||||
/// Disable chunked transfer encoding for HTTP/1.1 streaming responses.
|
/// Disable chunked transfer encoding for HTTP/1.1 streaming responses.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn no_chunking(&mut self, len: u64) -> &mut Self {
|
pub fn no_chunking(&mut self, len: u64) -> &mut Self {
|
||||||
self.insert_header((header::CONTENT_LENGTH, len));
|
let mut buf = itoa::Buffer::new();
|
||||||
|
self.insert_header((header::CONTENT_LENGTH, buf.format(len)));
|
||||||
|
|
||||||
if let Some(parts) = parts(&mut self.head, &self.err) {
|
if let Some(parts) = parts(&mut self.head, &self.err) {
|
||||||
parts.no_chunking(true);
|
parts.no_chunking(true);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
### Changed
|
### Changed
|
||||||
* Feature `cookies` is now optional and enabled by default. [#1981]
|
* Feature `cookies` is now optional and enabled by default. [#1981]
|
||||||
* `ClientBuilder::connector` method would take `actix_http::client::Connector<T, U>` type. [#2008]
|
* `ClientBuilder::connector` method would take `actix_http::client::Connector<T, U>` type. [#2008]
|
||||||
|
* Basic auth password now takes blank passwords as an empty string instead of Option. [#2050]
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
* `ClientBuilder::default` function [#2008]
|
* `ClientBuilder::default` function [#2008]
|
||||||
|
@ -17,6 +18,8 @@
|
||||||
[#1981]: https://github.com/actix/actix-web/pull/1981
|
[#1981]: https://github.com/actix/actix-web/pull/1981
|
||||||
[#2008]: https://github.com/actix/actix-web/pull/2008
|
[#2008]: https://github.com/actix/actix-web/pull/2008
|
||||||
[#2024]: https://github.com/actix/actix-web/pull/2024
|
[#2024]: https://github.com/actix/actix-web/pull/2024
|
||||||
|
[#2050]: https://github.com/actix/actix-web/pull/2050
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.2 - 2021-02-10
|
## 3.0.0-beta.2 - 2021-02-10
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -54,6 +54,7 @@ bytes = "1"
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
derive_more = "0.99.5"
|
derive_more = "0.99.5"
|
||||||
futures-core = { version = "0.3.7", default-features = false }
|
futures-core = { version = "0.3.7", default-features = false }
|
||||||
|
itoa = "0.4"
|
||||||
log =" 0.4"
|
log =" 0.4"
|
||||||
mime = "0.3"
|
mime = "0.3"
|
||||||
percent-encoding = "2.1"
|
percent-encoding = "2.1"
|
||||||
|
@ -80,8 +81,8 @@ actix-server = "2.0.0-beta.3"
|
||||||
actix-tls = { version = "3.0.0-beta.4", features = ["openssl", "rustls"] }
|
actix-tls = { version = "3.0.0-beta.4", features = ["openssl", "rustls"] }
|
||||||
|
|
||||||
brotli2 = "0.3.2"
|
brotli2 = "0.3.2"
|
||||||
|
env_logger = "0.8"
|
||||||
flate2 = "1.0.13"
|
flate2 = "1.0.13"
|
||||||
futures-util = { version = "0.3.7", default-features = false }
|
futures-util = { version = "0.3.7", default-features = false }
|
||||||
env_logger = "0.8"
|
|
||||||
rcgen = "0.8"
|
rcgen = "0.8"
|
||||||
webpki = "0.21"
|
webpki = "0.21"
|
||||||
|
|
|
@ -248,30 +248,25 @@ impl ClientRequest {
|
||||||
/// Set content length
|
/// Set content length
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn content_length(self, len: u64) -> Self {
|
pub fn content_length(self, len: u64) -> Self {
|
||||||
self.append_header((header::CONTENT_LENGTH, len))
|
let mut buf = itoa::Buffer::new();
|
||||||
|
self.insert_header((header::CONTENT_LENGTH, buf.format(len)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set HTTP basic authorization header
|
/// Set HTTP basic authorization header.
|
||||||
pub fn basic_auth<U>(self, username: U, password: Option<&str>) -> Self
|
///
|
||||||
where
|
/// If no password is needed, just provide an empty string.
|
||||||
U: fmt::Display,
|
pub fn basic_auth(self, username: impl fmt::Display, password: impl fmt::Display) -> Self {
|
||||||
{
|
let auth = format!("{}:{}", username, password);
|
||||||
let auth = match password {
|
|
||||||
Some(password) => format!("{}:{}", username, password),
|
self.insert_header((
|
||||||
None => format!("{}:", username),
|
|
||||||
};
|
|
||||||
self.append_header((
|
|
||||||
header::AUTHORIZATION,
|
header::AUTHORIZATION,
|
||||||
format!("Basic {}", base64::encode(&auth)),
|
format!("Basic {}", base64::encode(&auth)),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set HTTP bearer authentication header
|
/// Set HTTP bearer authentication header
|
||||||
pub fn bearer_auth<T>(self, token: T) -> Self
|
pub fn bearer_auth(self, token: impl fmt::Display) -> Self {
|
||||||
where
|
self.insert_header((header::AUTHORIZATION, format!("Bearer {}", token)))
|
||||||
T: fmt::Display,
|
|
||||||
{
|
|
||||||
self.append_header((header::AUTHORIZATION, format!("Bearer {}", token)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a cookie
|
/// Set a cookie
|
||||||
|
@ -643,9 +638,7 @@ mod tests {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn client_basic_auth() {
|
async fn client_basic_auth() {
|
||||||
let req = Client::new()
|
let req = Client::new().get("/").basic_auth("username", "password");
|
||||||
.get("/")
|
|
||||||
.basic_auth("username", Some("password"));
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
req.head
|
req.head
|
||||||
.headers
|
.headers
|
||||||
|
@ -656,7 +649,7 @@ mod tests {
|
||||||
"Basic dXNlcm5hbWU6cGFzc3dvcmQ="
|
"Basic dXNlcm5hbWU6cGFzc3dvcmQ="
|
||||||
);
|
);
|
||||||
|
|
||||||
let req = Client::new().get("/").basic_auth("username", None);
|
let req = Client::new().get("/").basic_auth("username", "");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
req.head
|
req.head
|
||||||
.headers
|
.headers
|
||||||
|
|
|
@ -829,7 +829,7 @@ async fn client_basic_auth() {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_str()
|
.to_str()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
== "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
|
== format!("Basic {}", base64::encode("username:password"))
|
||||||
{
|
{
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
} else {
|
} else {
|
||||||
|
@ -840,7 +840,7 @@ async fn client_basic_auth() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// set authorization header to Basic <base64 encoded username:password>
|
// set authorization header to Basic <base64 encoded username:password>
|
||||||
let request = srv.get("/").basic_auth("username", Some("password"));
|
let request = srv.get("/").basic_auth("username", "password");
|
||||||
let response = request.send().await.unwrap();
|
let response = request.send().await.unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue