Class: ReverseProxy::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/reverse_proxy/client.rb

Constant Summary collapse

@@callback_methods =
[
  :on_response,
  :on_set_cookies,
  :on_success,
  :on_redirect,
  :on_missing,
  :on_error,
  :on_complete
]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url) {|_self| ... } ⇒ Client

Returns a new instance of Client.

Yields:

  • (_self)

Yield Parameters:



26
27
28
29
30
31
32
33
34
35
36
# File 'lib/reverse_proxy/client.rb', line 26

def initialize(url)
  self.url = url
  self.callbacks = {}

  # Initialize default callbacks with empty Proc
  @@callback_methods.each do |method|
    self.callbacks[method] = Proc.new {}
  end

  yield(self) if block_given?
end

Instance Attribute Details

#callbacksObject

Returns the value of attribute callbacks.



24
25
26
# File 'lib/reverse_proxy/client.rb', line 24

def callbacks
  @callbacks
end

#urlObject

Returns the value of attribute url.



24
25
26
# File 'lib/reverse_proxy/client.rb', line 24

def url
  @url
end

Instance Method Details

#request(env, options = {}, &block) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/reverse_proxy/client.rb', line 38

def request(env, options = {}, &block)
  options.reverse_merge!(
    headers: {},
    path: nil,
    username: nil,
    password: nil
  )

  source_request = Rack::Request.new(env)

  # We can pass in a custom path
  uri = URI.parse("#{url}#{options[:path] || env['ORIGINAL_FULLPATH']}")

  # Initialize request
  target_request = Net::HTTP.const_get(source_request.request_method.capitalize).new(uri.request_uri)

  # Setup headers
  target_request_headers = extract_http_request_headers(source_request.env).merge(options[:headers])

  target_request.initialize_http_header(target_request_headers)

  # Basic auth
  target_request.basic_auth(options[:username], options[:password]) if options[:username] and options[:password]

  # Setup body
  if target_request.request_body_permitted? \
     && source_request.body
    source_request.body.rewind
    target_request.body_stream = source_request.body
  end

  target_request.content_length = source_request.content_length || 0
  target_request.content_type   = source_request.content_type if source_request.content_type

  # Hold the response here
  target_response = nil

  # Don't encode response/support compression which was
  # causing content length not match the actual content
  # length of the response which ended up causing issues
  # within Varnish (503)
  target_request['Accept-Encoding'] = nil

  # Make the request
  Net::HTTP.start(uri.host, uri.port, use_ssl: (uri.scheme == "https")) do |http|
    target_response = http.request(target_request)
  end

  status_code = target_response.code.to_i
  payload = [status_code, target_response]

  callbacks[:on_response].call(payload)

  if set_cookie_headers = target_response.to_hash['set-cookie']
    set_cookies_hash = {}

    set_cookie_headers.each do |set_cookie_header|
      set_cookie_hash = CookieJar::CookieValidation.parse_set_cookie(set_cookie_header)
      set_cookie_hash[:value] = CGI.unescape(set_cookie_hash[:value])

      name = set_cookie_hash.delete(:name)

      set_cookies_hash[name] = set_cookie_hash
    end

    callbacks[:on_set_cookies].call(payload | [set_cookies_hash])
  end

  case status_code
  when 200..299
    callbacks[:on_success].call(payload)
  when 300..399
    if redirect_url = target_response['Location']
      callbacks[:on_redirect].call(payload | [redirect_url])
    end
  when 400..499
    callbacks[:on_missing].call(payload)
  when 500..599
    callbacks[:on_error].call(payload)
  end

  callbacks[:on_complete].call(payload)

  payload
end