1
0
Fork 0
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:
Rob Ede 2021-03-07 19:29:02 +00:00 committed by GitHub
parent 880b863f95
commit ca69b6577e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 49 additions and 45 deletions

View file

@ -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) => {
let mut buf = itoa::Buffer::new();
req.headers_mut().insert(
CONTENT_LENGTH, CONTENT_LENGTH,
HeaderValue::try_from(format!("{}", len)).unwrap(), 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,
_ => {} _ => {}

View file

@ -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,

View file

@ -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) => {
let mut buf = itoa::Buffer::new();
res.headers_mut().insert(
CONTENT_LENGTH, CONTENT_LENGTH,
HeaderValue::try_from(format!("{}", len)).unwrap(), 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,

View file

@ -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);

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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());
} }