class Goliath::RackProxy

Public Class Methods

rack_app(app) click to toggle source

Rack app to proxy the incoming requests to.

# File lib/goliath/rack_proxy.rb, line 10
def self.rack_app(app)
  rack_proxy_options[:rack_app] = app
end
rack_proxy_options() click to toggle source

Custom user-defined options.

# File lib/goliath/rack_proxy.rb, line 20
def self.rack_proxy_options
  @rack_proxy_options ||= {}
end
rewindable_input(value) click to toggle source

Whether the request body should be rewindable.

# File lib/goliath/rack_proxy.rb, line 15
def self.rewindable_input(value)
  rack_proxy_options[:rewindable_input] = value
end

Public Instance Methods

on_body(env, data) click to toggle source

Resumes the Rack request with the received request body data.

# File lib/goliath/rack_proxy.rb, line 34
def on_body(env, data)
  env["rack_proxy.call"].resume(data, on_response: -> (response) { send_response(response, env) })
end
on_close(env) click to toggle source

Resumes the Rack request with no more data.

# File lib/goliath/rack_proxy.rb, line 39
def on_close(env)
  env["rack_proxy.call"].resume
end
on_headers(env, headers) click to toggle source

Starts the request to the given Rack application.

# File lib/goliath/rack_proxy.rb, line 25
def on_headers(env, headers)
  rack_app         = self.class.rack_proxy_options.fetch(:rack_app)
  rewindable_input = self.class.rack_proxy_options.fetch(:rewindable_input, true)

  env["rack_proxy.call"] = RackCall.new(rack_app, env, rewindable_input: rewindable_input)
  env["rack_proxy.call"].resume(on_response: -> (response) { send_response(response, env) })
end
response(env) click to toggle source

Resumes the Rack request with no more data.

# File lib/goliath/rack_proxy.rb, line 44
def response(env)
  env["rack_proxy.call"].resume(on_response: -> (response) { send_response(response, env) })
  nil
end

Private Instance Methods

send_response(response, env) click to toggle source

The env proc wraps sending response data in a Goliath::Request#callback, which gets executed after the whole request body has been received.

This is not ideal for apps that receive large uploads, as when they validate request headers, they likely want to return error responses immediately. It's not good user experience to require the user to upload a large file, only to have the request fail with a validation error.

To work around that, we mark the request as succeeded before sending the response, so that the response is sent immediately.

# File lib/goliath/rack_proxy.rb, line 62
def send_response(response, env)
  request = env[STREAM_SEND].binding.receiver # hack to get the Goliath::Request object
  request.succeed # makes it so that response is sent immediately

  env[ASYNC_CALLBACK].call(response)
end