Open
Description
Expected Behavior
Obviously server should run smoothly, no sockets should be left in ESTABLISHED or CLOSE_WAIT and client should not get stuck.
Current Behavior
Sockets are left in ESTABLISHED or CLOSE_WAIT and clients get stuck.
Possible Solution
No clue
Steps to Reproduce
Server:
Cargo.toml
:
[dependencies]
anyhow = "1"
actix-rt = "2.8"
actix-web = "4.3"
main.rs
:
use actix_web::{error::ErrorConflict, web, App, HttpResponse, HttpServer};
use anyhow;
async fn upload() -> Result<HttpResponse, actix_web::Error> {
Err(ErrorConflict("conflict"))
}
#[actix_rt::main]
async fn main() -> anyhow::Result<()> {
HttpServer::new(move || {
App::new().service(web::resource("/upload/{name}").route(web::put().to(upload)))
})
.bind("127.0.0.1:8000")?
.run()
.await?;
Ok(())
}
Client
client.py
:
import requests
def chunks():
yield bytes(1024*1024*b'a')
yield bytes(1024*1024*b'b')
yield bytes(1024*1024*b'c')
yield bytes(1024*1024*b'd')
resp = requests.put(f"http://localhost:8000/upload/test.txt", data=chunks())
print(repr(resp))
Steps:
- Start the server
- Run
client.py
few times.
Aftermath:
After running client.py
few times lsof shows for example
> lsof -i -a -p 17671 -n -P
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
rs 17671 etam 9u IPv4 2823931 0t0 TCP 127.0.0.1:8000 (LISTEN)
rs 17671 etam 21u IPv4 2823936 0t0 TCP 127.0.0.1:8000->127.0.0.1:34484 (CLOSE_WAIT)
rs 17671 etam 23u IPv4 2827508 0t0 TCP 127.0.0.1:8000->127.0.0.1:36270 (CLOSE_WAIT)
rs 17671 etam 24u IPv4 2827545 0t0 TCP 127.0.0.1:8000->127.0.0.1:39514 (CLOSE_WAIT)
rs 17671 etam 25u IPv4 2827585 0t0 TCP 127.0.0.1:8000->127.0.0.1:39516 (CLOSE_WAIT)
rs 17671 etam 26u IPv4 2825173 0t0 TCP 127.0.0.1:8000->127.0.0.1:48344 (CLOSE_WAIT)
rs 17671 etam 27u IPv4 2825215 0t0 TCP 127.0.0.1:8000->127.0.0.1:48358 (ESTABLISHED)
rs 17671 etam 28u IPv4 2829316 0t0 TCP 127.0.0.1:8000->127.0.0.1:43466 (ESTABLISHED)
rs 17671 etam 29u IPv4 2826652 0t0 TCP 127.0.0.1:8000->127.0.0.1:43474 (ESTABLISHED)
rs 17671 etam 30u IPv4 2826663 0t0 TCP 127.0.0.1:8000->127.0.0.1:43482 (ESTABLISHED)
and client.py
instead of printing <Response [409]>
might get stuck, where it has to be killed with Ctrl+C:
Traceback (most recent call last):
File "/home/etam/tmp/./upload.py", line 11, in <module>
resp = requests.put(f"http://localhost:8000/upload/test.txt", data=chunks())
File "/usr/lib/python3.10/site-packages/requests/api.py", line 130, in put
return request("put", url, data=data, **kwargs)
File "/usr/lib/python3.10/site-packages/requests/api.py", line 59, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/lib/python3.10/site-packages/requests/sessions.py", line 587, in request
resp = self.send(prep, **send_kwargs)
File "/usr/lib/python3.10/site-packages/requests/sessions.py", line 701, in send
r = adapter.send(request, **kwargs)
File "/usr/lib/python3.10/site-packages/requests/adapters.py", line 526, in send
low_conn.send(i)
File "/usr/lib64/python3.10/http/client.py", line 998, in send
self.sock.sendall(data)
KeyboardInterrupt
Context
It's a simple service for uploading files. But sometimes we want to return ErrorConflict
.
Your Environment
- Rust Version: 1.67.0
- Actix Web Version: 4.3.0
- python3-requests: 2.28.2