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

Sending response before all request data was received #348

Open
janko opened this issue May 22, 2018 · 1 comment
Open

Sending response before all request data was received #348

janko opened this issue May 22, 2018 · 1 comment

Comments

@janko
Copy link
Contributor

janko commented May 22, 2018

In tus-ruby-server I'm handling large file uploads. When the user makes a PATCH request with a chunk of the file, the app first validates request headers, and if they're invalid it returns, it returns an error response without even reading the request body.

I'm using goliath-rack_proxy as a glue between Goliath and the tus-ruby-server Rack app, and I'm trying to figure out how to return the response early with Goliath. The reason I want that is because I would like to avoid happily accepting multiple gigabytes of request body from a client, only to return an error response because the request headers were invalid. I would like to utilize Goliath's ability to act as soon as request headers are received.

The problem is that .succeed is called on the Goliath::Request only after all request body has been receved, and all of the env[ASYNC_*] procs use callback { }, which means they will send the response only after all request data has been received (e.g. I tried using env[ASYNC_CALLBACK]). I wrote the following proof-of-concept, which uses hacks to access the Goliath::Request object (already discussed in #341) and use Goliath::Connection#send_data directly:

require "goliath"

class App < Goliath::API
  def on_headers(env, headers)
    request    = env[ASYNC_CALLBACK].receiver
    connection = request.conn
    response   = request.response

    response.status = 200
    response.headers = { "Foo" => "Bar" }
    response.body = "This is a response"

    response.each { |data| connection.send_data(data) }
    connection.terminate_request(false)
  end

  def response(env)
  end
end

I'm pretty sure that returning a response early is valid HTTP interaction, because curl-ing this app returns the response without any errors.

Are you open to support this in Goliath? If yes, I could come up with a PR.

@igrigorik
Copy link
Member

igrigorik commented May 26, 2018

I'm pretty sure that returning a response early is valid HTTP interaction...

Yes, I think so. What would you propose as an API to address this? The main complication I can anticipate here is not breaking all the other Goliath clients.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants