Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client request stalls if streaming body request is not drained #2356

Closed
klaas opened this issue May 13, 2020 · 1 comment
Closed

Client request stalls if streaming body request is not drained #2356

klaas opened this issue May 13, 2020 · 1 comment
Labels
bug Something isn't working
Projects

Comments

@klaas
Copy link
Sponsor Contributor

klaas commented May 13, 2020

I'm not sure if this is a bug or meant to be like this. I ran into this and it took me some time to figure out what I was doing wrong.

I'm using

base.on(.POST, "myupload", body: .stream) { req -> EventLoopFuture<HTTPResponseStatus> in
    let requestPromise = req.eventLoop.makePromise(of: HTTPResponseStatus.self)

    // [ ... handle body stream and complete requestPromise at the end ... ]

    return requestPromise.futureResult
}

to handle a streaming request with a reasonably large image file (e.g. 1 MB). This works fine.

BUT: When I change my code to validate some headers beforehand, it will stall and the client request will not get a response when the header is missing.

base.on(.POST, "myupload", body: .stream) { req -> EventLoopFuture<HTTPResponseStatus> in
    guard nil != req.headers["MyHeader"].first else {
        return req.eventLoop.makeSucceededFuture(.badRequest)
    }

    let requestPromise = req.eventLoop.makePromise(of: HTTPResponseStatus.self)

    // [ ... handle body stream and complete requestPromise at the end ... ]

    return requestPromise.futureResult
}

When I add some simple code to collect the body stream, it works again:

base.on(.POST, "myupload", body: .stream) { req -> EventLoopFuture<HTTPResponseStatus> in
    guard nil != req.headers["MyHeader"].first else {
        _ = req.body.collect(max: 10)
        return req.eventLoop.makeSucceededFuture(.badRequest)
    }

    let requestPromise = req.eventLoop.makePromise(of: HTTPResponseStatus.self)

    // [ ... handle body stream and complete requestPromise at the end ... ]

    return requestPromise.futureResult
}

Steps to reproduce

Setup a POST route with a streaming body and invoke it with httpie (http://httpie.org) from the command line to upload an image to this route:

http POST "http://localhost:8080/myupload" MyHeader:123 <yourImage.jpeg

This works.

http POST "http://localhost:8080/myupload" NotMyHeader:123 <yourImage.jpeg

This stalls in 4 out of 5 times and will eventually time out.

Expected behavior

Will not time event when the body stream is not collected / drained.

Actual behavior

It stalls in 4 out of 5 times.

Environment

  • Vapor Framework version: 4.5.0
  • Vapor Toolbox version: 3.1.0
  • OS version: macOS 10.15.4
@tanner0101 tanner0101 added the bug Something isn't working label May 27, 2020
@tanner0101 tanner0101 added this to To Do in Vapor 4 via automation May 27, 2020
@tanner0101
Copy link
Member

This has been fixed in https://github.com/vapor/vapor/releases/tag/4.7.0, thanks for reporting!

Vapor 4 automation moved this from To Do to Done May 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Vapor 4
  
Done
Development

No branches or pull requests

2 participants