Skip to content

Sending response before all request data was received #348

@janko

Description

@janko

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions