Skip to content

Sockets left open and client get stuck, when PUT returns error #2972

Open
@etam

Description

@etam

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-httpproject: actix-httpC-bugCategory: bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions