Class: Rack::StreamingProxy::Proxy

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/streaming_proxy/proxy.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, &block) ⇒ Proxy

The block provided to the initializer is given a Rack::Request and should return:

* nil/false to skip the proxy and continue down the stack
* a complete uri (with query string if applicable) to proxy to

Example:

use Rack::StreamingProxy::Proxy do |req|
  if req.path.start_with?('/search')
    "http://some_other_service/search?#{req.query}"
  end
end

Most headers, request body, and HTTP method are preserved.



58
59
60
61
# File 'lib/rack/streaming_proxy/proxy.rb', line 58

def initialize(app, &block)
  @app   = app
  @block = block
end

Class Method Details

.log(level, message) ⇒ Object



35
36
37
38
39
# File 'lib/rack/streaming_proxy/proxy.rb', line 35

def log(level, message)
  unless log_verbosity == :low && level == :debug
    logger.send level, "[Rack::StreamingProxy] #{message}"
  end
end

.log_verbosityObject

At :low verbosity by default – will not output :debug level messages. :high verbosity outputs :debug level messages. This is independent of the Logger’s log_level, as set in Rails, for example, although the Logger’s level can override this setting.



18
19
20
# File 'lib/rack/streaming_proxy/proxy.rb', line 18

def log_verbosity
  :low
end

.loggerObject

Logs to stdout by default unless configured with another logger via Railtie.



10
11
12
# File 'lib/rack/streaming_proxy/proxy.rb', line 10

def logger
  Logger.new(STDOUT)
end

.num_retries_on_5xxObject

No retries are performed by default.



23
24
25
# File 'lib/rack/streaming_proxy/proxy.rb', line 23

def num_retries_on_5xx
  0
end

.raise_on_5xxObject

If the proxy cannot recover from 5xx’s through retries (see num_retries_on_5xx), then it by default passes through the content from the destination e.g. the Apache error page. If you want an exception to be raised instead so you can handle it yourself (i.e. display your own error page), set raise_on_5xx to true.



31
32
33
# File 'lib/rack/streaming_proxy/proxy.rb', line 31

def raise_on_5xx
  false
end

Instance Method Details

#call(env) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/rack/streaming_proxy/proxy.rb', line 63

def call(env)
  current_request = Rack::Request.new(env)
  destination_uri = destination_uri(current_request)

  # Decide whether this request should be proxied.
  if destination_uri
    self.class.log :info, "Starting proxy request to: #{destination_uri}"

    request  = Rack::StreamingProxy::Request.new(destination_uri, current_request)
    begin
      response = Rack::StreamingProxy::Session.new(request).start
    rescue Exception => e # Rescuing only for the purpose of logging to rack.errors
      log_rack_error(env, e)
      raise e
    end

    # Notify client http version to the instance of Response class.
    response.client_http_version = env['HTTP_VERSION'].sub(/HTTP\//, '') if env.has_key?('HTTP_VERSION')
    # Ideally, both a Content-Length header field and a Transfer-Encoding 
    # header field are not expected to be present from servers which 
    # are compliant with RFC2616. However, irresponsible servers may send 
    # both to rack-streaming-proxy.
    # RFC2616 says if a message is received with both a Transfer-Encoding 
    # header field and a Content-Length header field, the latter MUST be 
    # ignored. So I deleted a Content-Length header here.
    #
    # Though there is a case that rack-streaming-proxy deletes both a 
    # Content-Length and a Transfer-Encoding, a client can acknowledge the 
    # end of body by closing the connection when the entire response has 
    # been sent without a Content-Length header. So a Content-Length header 
    # does not have to be required here in our understaing.
    response.headers.delete('Content-Length') if response.headers.has_key?('Transfer-Encoding')
    if env.has_key?('HTTP_VERSION') && env['HTTP_VERSION'] < 'HTTP/1.1'
      # Be compliant with RFC2146
      response.headers.delete('Transfer-Encoding')
    end

    self.class.log :info, "Finishing proxy request to: #{destination_uri}"
    [response.status, response.headers, response]

  # Continue down the middleware stack if the request is not to be proxied.
  else
    @app.call(env)
  end
end