actix-web: file upload timeout

I have a POST request that does some complex processing. However, for debug purposes I have commented out the meat of the handler body. This is what’s left:


// For details on the available formatting options for `LOG_FMT`, see
// https://docs.rs/actix-web/3.0.2/actix_web/middleware/struct.Logger.html
const LOG_FMT: &str = r#"{
    remote_ip: %a,
    serve_time: %D ms,
    status: %s,
    request: "%r",
    response_size: %b bytes,
    user_agent: "%{User-Agent}i",
}"#;

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    // some code here
    let mut settings = Settings::parse_toml("Server.toml")?;
    // more code here 
    let settings = Arc::new(settings); // Leverage `Arc` to not waste memory
    let insettings = Arc::clone(&settings);
    HttpServer::new(move || {
        let route = |path| if insettings.actix.enable_log { "N/A" } else { path };
        App::new()
            .wrap(Compress::new(if insettings.actix.enable_compression {
                ContentEncoding::Deflate
            } else {
                ContentEncoding::Identity
            }))
            .wrap(
                Logger::new(LOG_FMT)
                    .exclude(route("/"))
                    .exclude(route("/favicon.ico"))
            )
            .data(insettings.clone())
        // Define routes:
            .service(index)
            .service(upload)
    })
        .apply_settings(&settings) // This comes from the actix-settings crate; all it does is apply the settings in a file using APIs defined by `actix-web`.
        .run()
        .await
}

#[get("/")]
async fn index() -> impl Responder {
    let html = r#"
        <html>
            <head><title>Upload Test</title></head>
            <body style="background: #3c3c3c;">
                <form target="/" method="post" enctype="multipart/form-data">
                    <input type="file" multiple name="file"/>
                    <button type="submit">Submit</button>
                </form>
            </body>
        </html>
    "#;
    HttpResponse::Ok().body(html)
}

#[post("/")]
async fn upload(
    mut payload: Multipart,
    settings: web::Data<Arc<Settings>>,
) -> ActixResult<impl Responder> {
    // NOTE: The original body has been replaced by returning a simple string
    Ok("[upload] foo bar".to_string())
}

Expected Behavior

I expect the POST request to complete, and quickly too.

Current Behavior

The POST request hangs indefinitely until the connection with the client is broken. Altering the keep-alive setting merely keeps the connection hanging for longer.

Possible Solution

No clue, as I’m not familiar with actix-web internals.

Steps to Reproduce (for bugs)

  1. Run the server
  2. Send the POST request to / to engage the upload route using the HTML form located at get("/")
  3. A new tab/page appears…
  4. …and it never completes, instead just timing out.

Context

This is a show-stopper bug. The entire server is unusable like this during development, never mind production.

Your Environment

The environment doesn’t really matter as the issue is reproducible on a regular OS install as well as in a Kubernetes cluster. In all cases the OS is linux-based.

  • Ubuntu Linux 19.10

  • rustc 1.48.0 (7eac88abb 2020-11-16)

  • Actix-web 3.3.0

  • actix-settings 0.5

  • Rust Version (I.e, output of rustc -V):

  • Actix Web Version:

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Comments: 19 (8 by maintainers)

Most upvoted comments

Like I said please make a minimal example. For example you don’t need three endpoints to produce a leak. You don’t need logger. You don’t need middleware.

There is not enough man power to look into your big block of code and analyze it.

That’s a lot of code. Please try to make a minimal reproduce able one so the problem can be more clear.