Class: Ronin::Web::Server::ReverseProxy

Inherits:
Object
  • Object
show all
Defined in:
lib/ronin/web/server/reverse_proxy.rb,
lib/ronin/web/server/reverse_proxy/request.rb,
lib/ronin/web/server/reverse_proxy/response.rb

Overview

Reverse proxies Rack requests to other HTTP web servers.

Examples

Standalone Server

reverse_proxy = Ronin::Web::Server::ReverseProxy.new do |proxy|
  proxy.on_request do |request|
    # ...
  end

  proxy.on_response do |response|
    # ...
  end
end
reverse_proxy.run!(host: '0.0.0.0', port: 8080)

App

class App < Ronin::Web::Server::Base

  mount '/signin', Ronin::Web::Server::ReverseProxy.new

end

Defined Under Namespace

Classes: Request, Response

Standalone Server Methods collapse

DEFAULT_HOST =

Default host the Proxy will bind to

'0.0.0.0'
DEFAULT_PORT =

Default port the Proxy will listen on

8080
DEFAULT_SERVER =

Default server the Proxy will run on

'webrick'

Constant Summary collapse

IGNORED_HEADERS =

Blacklisted HTTP response Headers.

Standalone Server Methods collapse

Instance Method Summary collapse

Constructor Details

#initialize {|reverse_proxy| ... } ⇒ ReverseProxy

Creates a new reverse proxy application.

Yields:

  • (reverse_proxy)

    If a block is given, it will be passed the new proxy.

Yield Parameters:



69
70
71
72
73
# File 'lib/ronin/web/server/reverse_proxy.rb', line 69

def initialize
  @connections = {}

  yield self if block_given?
end

Instance Method Details

#call(env) ⇒ (Integer, Hash{String => String}, Array<String>)

Reverse proxies every request using the Host header.

Parameters:

  • env (Hash{String => Object})

    The rack request env Hash.

Returns:

  • ((Integer, Hash{String => String}, Array<String>))

    The rack response tuple (status, headers, body).



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/ronin/web/server/reverse_proxy.rb', line 116

def call(env)
  request = Request.new(env)
  @on_request_callback.call(request) if @on_request_callback

  response = reverse_proxy(request)

  if @on_response_callback
    if @on_response_callback.arity == 1
      @on_response_callback.call(response)
    else
      @on_response_callback.call(request,response)
    end
  end

  return [response.status, response.headers, response.body]
end

#connection_for(host, port, ssl: nil) ⇒ Ronin::Support::Network::HTTP

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Creates a new connection or fetches an existing connection.

Parameters:

  • host (String)

    The host to connect to.

  • port (Integer)

    The port to connect to.

  • ssl (Boolean) (defaults to: nil)

    Indicates whether to use SSL.

Returns:

  • (Ronin::Support::Network::HTTP)

    The HTTP connection.



150
151
152
153
154
155
156
# File 'lib/ronin/web/server/reverse_proxy.rb', line 150

def connection_for(host,port, ssl: nil)
  key = [host,port,ssl]

  @connections.fetch(key) do
    @connections[key] = Support::Network::HTTP.new(host,port, ssl: ssl)
  end
end

#on_request {|request| ... } ⇒ Object

Registers a callback to run on each request.

Yields:

  • (request)

    The given block will be passed each received request before it has been reverse proxied.



82
83
84
# File 'lib/ronin/web/server/reverse_proxy.rb', line 82

def on_request(&block)
  @on_request_callback = block
end

#on_response {|response| ... } ⇒ Object

Registers a callback to run on each response.

Yields:

  • (response)

    The given block will be passed each response before it has been returned.

  • (request, response)

    If the block accepts two arguments then both the request and the response objects will be yielded.

Yield Parameters:



103
104
105
# File 'lib/ronin/web/server/reverse_proxy.rb', line 103

def on_response(&block)
  @on_response_callback = block
end

#quit!(server, handler) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Stops the reverse proxy server.

Parameters:

  • server (Rack::Server)

    The Rack Handler server.

  • handler (#stop!, #stop)

    The Rack Handler.



258
259
260
261
# File 'lib/ronin/web/server/reverse_proxy.rb', line 258

def quit!(server,handler)
  # Use thins' hard #stop! if available, otherwise just #stop
  handler.respond_to?(:stop!) ? handler.stop! : handler.stop
end

#reverse_proxy(request) ⇒ ReverseProxy::Response

Reverse proxies the given request.

Parameters:

Returns:



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/ronin/web/server/reverse_proxy.rb', line 172

def reverse_proxy(request)
  host    = request.host
  port    = request.port
  ssl     = request.scheme == 'https'
  method  = request.request_method.downcase.to_sym
  path    = request.path
  query   = request.query_string
  headers = request.headers
  body    = request.body.read

  http          = connection_for(host,port, ssl: ssl)
  http_response = http.request(method,path, query:   query,
                                            headers: headers,
                                            body:    body)

  response_headers = {}

  http_response.each_capitalized do |name,value|
    unless IGNORED_HEADERS.include?(name)
      response_headers[name] = value
    end
  end

  response_body   = http_response.body || ''
  response_status = http_response.code.to_i

  return Response.new(response_body,response_status,response_headers)
end

#run!(host: DEFAULT_HOST, port: DEFAULT_PORT, server: DEFAULT_SERVER, **rack_options) ⇒ Object

Runs the reverse proxy as a standalone HTTP server.

Parameters:

  • host (String) (defaults to: DEFAULT_HOST)

    The host to bind to.

  • port (Integer) (defaults to: DEFAULT_PORT)

    The port to listen on.

  • server (String) (defaults to: DEFAULT_SERVER)

    The Rack server to run the reverse proxy under.

  • rack_options (Hash{Symbol => Object})

    Additional options to pass to Rack::Server.new.



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/ronin/web/server/reverse_proxy.rb', line 229

def run!(host: DEFAULT_HOST, port: DEFAULT_PORT, server: DEFAULT_SERVER,
         **rack_options)
  server = Rack::Server.new(
             app:    self,
             server: server,
             Host:   host,
             Port:   port,
             **rack_options
           )

  server.start do |handler|
    trap(:INT)  { quit!(server,handler) }
    trap(:TERM) { quit!(server,handler) }
  end

  return self
end