mirror of https://github.com/fafhrd91/actix-web
Compare commits
3 Commits
fde7934243
...
25963dbdf1
| Author | SHA1 | Date |
|---|---|---|
|
|
25963dbdf1 | |
|
|
4df9953c86 | |
|
|
016841137e |
|
|
@ -71,7 +71,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "actix-http"
|
name = "actix-http"
|
||||||
version = "3.11.1"
|
version = "3.11.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-codec",
|
"actix-codec",
|
||||||
"actix-http-test",
|
"actix-http-test",
|
||||||
|
|
@ -620,7 +620,7 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "awc"
|
name = "awc"
|
||||||
version = "3.8.0"
|
version = "3.8.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-codec",
|
"actix-codec",
|
||||||
"actix-http",
|
"actix-http",
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,12 @@
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
## 3.11.2
|
||||||
|
|
||||||
- Properly wake Payload receivers when feeding errors or EOF.
|
- Properly wake Payload receivers when feeding errors or EOF.
|
||||||
- Add `ServiceConfigBuilder` type to facilitate future configuration extensions.
|
- Add `ServiceConfigBuilder` type to facilitate future configuration extensions.
|
||||||
- Add a configuration option to allow/disallow half closed connections in HTTP/1. This defaults to allow, reverting the change made in 3.11.1.
|
- Add a configuration option to allow/disallow half closed connections in HTTP/1. This defaults to allow, reverting the change made in 3.11.1.
|
||||||
|
- Shutdown connections when HTTP Responses are written without reading full Requests.
|
||||||
|
|
||||||
## 3.11.1
|
## 3.11.1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "actix-http"
|
name = "actix-http"
|
||||||
version = "3.11.1"
|
version = "3.11.2"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>", "Rob Ede <robjtede@icloud.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>", "Rob Ede <robjtede@icloud.com>"]
|
||||||
description = "HTTP types and services for the Actix ecosystem"
|
description = "HTTP types and services for the Actix ecosystem"
|
||||||
keywords = ["actix", "http", "framework", "async", "futures"]
|
keywords = ["actix", "http", "framework", "async", "futures"]
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@
|
||||||
<!-- prettier-ignore-start -->
|
<!-- prettier-ignore-start -->
|
||||||
|
|
||||||
[](https://crates.io/crates/actix-http)
|
[](https://crates.io/crates/actix-http)
|
||||||
[](https://docs.rs/actix-http/3.11.1)
|
[](https://docs.rs/actix-http/3.11.2)
|
||||||

|

|
||||||

|

|
||||||
<br />
|
<br />
|
||||||
[](https://deps.rs/crate/actix-http/3.11.1)
|
[](https://deps.rs/crate/actix-http/3.11.2)
|
||||||
[](https://crates.io/crates/actix-http)
|
[](https://crates.io/crates/actix-http)
|
||||||
[](https://discord.gg/NWpN5mmg3x)
|
[](https://discord.gg/NWpN5mmg3x)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -386,7 +386,14 @@ where
|
||||||
let mut this = self.project();
|
let mut this = self.project();
|
||||||
this.state.set(match size {
|
this.state.set(match size {
|
||||||
BodySize::None | BodySize::Sized(0) => {
|
BodySize::None | BodySize::Sized(0) => {
|
||||||
this.flags.insert(Flags::FINISHED);
|
let payload_unfinished = this.payload.is_some();
|
||||||
|
|
||||||
|
if payload_unfinished {
|
||||||
|
this.flags.insert(Flags::SHUTDOWN | Flags::FINISHED);
|
||||||
|
} else {
|
||||||
|
this.flags.insert(Flags::FINISHED);
|
||||||
|
}
|
||||||
|
|
||||||
State::None
|
State::None
|
||||||
}
|
}
|
||||||
_ => State::SendPayload { body },
|
_ => State::SendPayload { body },
|
||||||
|
|
@ -404,7 +411,14 @@ where
|
||||||
let mut this = self.project();
|
let mut this = self.project();
|
||||||
this.state.set(match size {
|
this.state.set(match size {
|
||||||
BodySize::None | BodySize::Sized(0) => {
|
BodySize::None | BodySize::Sized(0) => {
|
||||||
this.flags.insert(Flags::FINISHED);
|
let payload_unfinished = this.payload.is_some();
|
||||||
|
|
||||||
|
if payload_unfinished {
|
||||||
|
this.flags.insert(Flags::SHUTDOWN | Flags::FINISHED);
|
||||||
|
} else {
|
||||||
|
this.flags.insert(Flags::FINISHED);
|
||||||
|
}
|
||||||
|
|
||||||
State::None
|
State::None
|
||||||
}
|
}
|
||||||
_ => State::SendErrorPayload { body },
|
_ => State::SendErrorPayload { body },
|
||||||
|
|
@ -503,10 +517,22 @@ where
|
||||||
Poll::Ready(None) => {
|
Poll::Ready(None) => {
|
||||||
this.codec.encode(Message::Chunk(None), this.write_buf)?;
|
this.codec.encode(Message::Chunk(None), this.write_buf)?;
|
||||||
|
|
||||||
|
// if we have not yet pipelined to the next request, then
|
||||||
|
// this.payload was the payload for the request we just finished
|
||||||
|
// responding to. We can check to see if we finished reading it
|
||||||
|
// yet, and if not, shutdown the connection.
|
||||||
|
let payload_unfinished = this.payload.is_some();
|
||||||
|
let not_pipelined = this.messages.is_empty();
|
||||||
|
|
||||||
// payload stream finished.
|
// payload stream finished.
|
||||||
// set state to None and handle next message
|
// set state to None and handle next message
|
||||||
this.state.set(State::None);
|
this.state.set(State::None);
|
||||||
this.flags.insert(Flags::FINISHED);
|
|
||||||
|
if not_pipelined && payload_unfinished {
|
||||||
|
this.flags.insert(Flags::SHUTDOWN | Flags::FINISHED);
|
||||||
|
} else {
|
||||||
|
this.flags.insert(Flags::FINISHED);
|
||||||
|
}
|
||||||
|
|
||||||
continue 'res;
|
continue 'res;
|
||||||
}
|
}
|
||||||
|
|
@ -542,10 +568,22 @@ where
|
||||||
Poll::Ready(None) => {
|
Poll::Ready(None) => {
|
||||||
this.codec.encode(Message::Chunk(None), this.write_buf)?;
|
this.codec.encode(Message::Chunk(None), this.write_buf)?;
|
||||||
|
|
||||||
// payload stream finished
|
// if we have not yet pipelined to the next request, then
|
||||||
|
// this.payload was the payload for the request we just finished
|
||||||
|
// responding to. We can check to see if we finished reading it
|
||||||
|
// yet, and if not, shutdown the connection.
|
||||||
|
let payload_unfinished = this.payload.is_some();
|
||||||
|
let not_pipelined = this.messages.is_empty();
|
||||||
|
|
||||||
|
// payload stream finished.
|
||||||
// set state to None and handle next message
|
// set state to None and handle next message
|
||||||
this.state.set(State::None);
|
this.state.set(State::None);
|
||||||
this.flags.insert(Flags::FINISHED);
|
|
||||||
|
if not_pipelined && payload_unfinished {
|
||||||
|
this.flags.insert(Flags::SHUTDOWN | Flags::FINISHED);
|
||||||
|
} else {
|
||||||
|
this.flags.insert(Flags::FINISHED);
|
||||||
|
}
|
||||||
|
|
||||||
continue 'res;
|
continue 'res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -535,6 +535,73 @@ async fn pipelining_ok_then_ok() {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn early_response_with_payload_closes_connection() {
|
||||||
|
lazy(|cx| {
|
||||||
|
let buf = TestBuffer::new(
|
||||||
|
"\
|
||||||
|
GET /unfinished HTTP/1.1\r\n\
|
||||||
|
Content-Length: 2\r\n\
|
||||||
|
\r\n\
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
let cfg = ServiceConfig::new(
|
||||||
|
KeepAlive::Os,
|
||||||
|
Duration::from_millis(1),
|
||||||
|
Duration::from_millis(1),
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
let services = HttpFlow::new(echo_path_service(), ExpectHandler, None);
|
||||||
|
|
||||||
|
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler>::new(
|
||||||
|
buf.clone(),
|
||||||
|
services,
|
||||||
|
cfg,
|
||||||
|
None,
|
||||||
|
OnConnectData::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
pin!(h1);
|
||||||
|
|
||||||
|
assert!(matches!(&h1.inner, DispatcherState::Normal { .. }));
|
||||||
|
|
||||||
|
match h1.as_mut().poll(cx) {
|
||||||
|
Poll::Pending => panic!("Should have shut down"),
|
||||||
|
Poll::Ready(res) => assert!(res.is_ok()),
|
||||||
|
}
|
||||||
|
|
||||||
|
// polls: initial => shutdown
|
||||||
|
assert_eq!(h1.poll_count, 2);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut res = buf.write_buf_slice_mut();
|
||||||
|
stabilize_date_header(&mut res);
|
||||||
|
let res = &res[..];
|
||||||
|
|
||||||
|
let exp = b"\
|
||||||
|
HTTP/1.1 200 OK\r\n\
|
||||||
|
content-length: 11\r\n\
|
||||||
|
date: Thu, 01 Jan 1970 12:34:56 UTC\r\n\r\n\
|
||||||
|
/unfinished\
|
||||||
|
";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
exp,
|
||||||
|
"\nexpected response not in write buffer:\n\
|
||||||
|
response: {:?}\n\
|
||||||
|
expected: {:?}",
|
||||||
|
String::from_utf8_lossy(res),
|
||||||
|
String::from_utf8_lossy(exp)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn pipelining_ok_then_bad() {
|
async fn pipelining_ok_then_bad() {
|
||||||
lazy(|cx| {
|
lazy(|cx| {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
## 3.8.1
|
||||||
|
|
||||||
|
- Fix a bug where `GO_AWAY` errors did not stop connections from returning to the pool.
|
||||||
|
|
||||||
## 3.8.0
|
## 3.8.0
|
||||||
|
|
||||||
- Add `hickory-dns` crate feature (off-by-default).
|
- Add `hickory-dns` crate feature (off-by-default).
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "awc"
|
name = "awc"
|
||||||
version = "3.8.0"
|
version = "3.8.1"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Async HTTP and WebSocket client library"
|
description = "Async HTTP and WebSocket client library"
|
||||||
keywords = ["actix", "http", "framework", "async", "web"]
|
keywords = ["actix", "http", "framework", "async", "web"]
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
<!-- prettier-ignore-start -->
|
<!-- prettier-ignore-start -->
|
||||||
|
|
||||||
[](https://crates.io/crates/awc)
|
[](https://crates.io/crates/awc)
|
||||||
[](https://docs.rs/awc/3.8.0)
|
[](https://docs.rs/awc/3.8.1)
|
||||||

|

|
||||||
[](https://deps.rs/crate/awc/3.8.0)
|
[](https://deps.rs/crate/awc/3.8.1)
|
||||||
[](https://discord.gg/NWpN5mmg3x)
|
[](https://discord.gg/NWpN5mmg3x)
|
||||||
|
|
||||||
<!-- prettier-ignore-end -->
|
<!-- prettier-ignore-end -->
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ where
|
||||||
|
|
||||||
let res = poll_fn(|cx| io.poll_ready(cx)).await;
|
let res = poll_fn(|cx| io.poll_ready(cx)).await;
|
||||||
if let Err(err) = res {
|
if let Err(err) = res {
|
||||||
io.on_release(err.is_io());
|
io.on_release(err.is_io() || err.is_go_away());
|
||||||
return Err(SendRequestError::from(err));
|
return Err(SendRequestError::from(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,7 +121,7 @@ where
|
||||||
fut.await.map_err(SendRequestError::from)?
|
fut.await.map_err(SendRequestError::from)?
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
io.on_release(err.is_io());
|
io.on_release(err.is_io() || err.is_go_away());
|
||||||
return Err(err.into());
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue