File: http_library_adapters.rb

package info (click to toggle)
ruby-vcr 6.0.0%2Breally5.0.0-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,320 kB
  • sloc: ruby: 8,456; sh: 177; makefile: 7
file content (299 lines) | stat: -rw-r--r-- 8,359 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
module HeaderDowncaser
  def downcase_headers(headers)
    {}.tap do |downcased|
      headers.each do |k, v|
        downcased[k.downcase] = v
      end
    end
  end
end

HTTP_LIBRARY_ADAPTERS = {}

HTTP_LIBRARY_ADAPTERS['net/http'] = Module.new do
  include HeaderDowncaser

  def self.http_library_name; 'Net::HTTP'; end

  def get_body_string(response); response.body; end
  alias get_body_object get_body_string

  def get_header(header_key, response)
    response.get_fields(header_key)
  end

  def make_http_request(method, url, body = nil, headers = {})
    uri = URI.parse(url)
    http = Net::HTTP.new(uri.host, uri.port)

    if uri.scheme == "https"
      http.use_ssl = true
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    end

    http.send_request(method.to_s.upcase, uri.request_uri, body, headers)
  end

  DEFAULT_REQUEST_HEADERS = { "Accept"=>["*/*"] }
  DEFAULT_REQUEST_HEADERS['User-Agent'] = ["Ruby"]
  DEFAULT_REQUEST_HEADERS['Accept-Encoding'] = ["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"] if RUBY_VERSION.to_f > 1.9

  def normalize_request_headers(headers)
    defined?(super) ? super :
    downcase_headers(headers.merge(DEFAULT_REQUEST_HEADERS))
  end
end

HTTP_LIBRARY_ADAPTERS['patron'] = Module.new do
  def self.http_library_name; 'Patron'; end

  def get_body_string(response); response.body; end
  alias get_body_object get_body_string

  def get_header(header_key, response)
    response.headers[header_key]
  end

  def make_http_request(method, url, body = nil, headers = {})
    Patron::Session.new.request(method, url, headers, :data => body || '')
  end

  def normalize_request_headers(headers)
    headers.merge('Expect' => [''])
  end
end

HTTP_LIBRARY_ADAPTERS['httpclient'] = Module.new do
  def self.http_library_name; 'HTTP Client'; end

  def get_body_string(response)
    body = response.body
    string = body.is_a?(String) ? body : body.content
    string.respond_to?(:read) ? string.read : string
  end

  def get_body_object(response)
    response.body
  end

  def get_header(header_key, response)
    response.header[header_key]
  end

  def make_http_request(method, url, body = nil, headers = {})
    HTTPClient.new.request(method, url, nil, body, headers)
  end

  def normalize_request_headers(headers)
    headers.merge({
      'Accept'     => ["*/*"],
      'User-Agent' => ["HTTPClient/1.0 (#{HTTPClient::VERSION}, ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}))"],
      'Date'       => [Time.now.httpdate]
    })
  end
end

HTTP_LIBRARY_ADAPTERS['em-http-request'] = Module.new do
  def self.http_library_name; 'EM HTTP Request'; end

  def get_body_string(response)
    response.response
  end
  alias get_body_object get_body_string

  def get_header(header_key, response)
    values = response.response_header[header_key.upcase.gsub('-', '_')]
    values.is_a?(Array) ? values : values.split(', ')
  end

  def make_http_request(method, url, body = nil, headers = {})
    http = nil
    EventMachine.run do
      # Several request options are required to prevent em-http-request from inserting headers
      request_options = {
        body: body,
        head: headers.merge({"user-agent" => nil}),
        compressed: false,
        keepalive: true
      }
      http = EventMachine::HttpRequest.new(url).send(method, **request_options)
      http.callback { EventMachine.stop }
    end
    http
  end

  def normalize_request_headers(headers)
    headers
  end
end

HTTP_LIBRARY_ADAPTERS['curb'] = Module.new do
  def self.http_library_name; "Curb"; end

  def get_body_string(response)
    response.body_str
  end
  alias get_body_object get_body_string

  def get_header(header_key, response)
    headers = response.header_str.split("\r\n")[1..-1]
    value = nil
    headers.each do |h|
      next unless h =~ /^#{Regexp.escape(header_key)}: (.*)$/
      new_value = $1.split(', ')
      value = value ? Array(value) + Array(new_value) : new_value
    end
    value
  end

  def make_http_request(method, url, body = nil, headers = {})
    Curl::Easy.new(url) do |c|
      c.headers = headers

      if [:post, :put].include?(method)
        c.send("http_#{method}", body)
      else
        c.send("http_#{method}")
      end
    end
  end

  def normalize_request_headers(headers)
    headers
  end
end

HTTP_LIBRARY_ADAPTERS['typhoeus'] = Module.new do
  def self.http_library_name; "Typhoeus"; end

  def get_body_string(response)
    response.body
  end
  alias get_body_object get_body_string

  def get_header(header_key, response)
    # Due to https://github.com/typhoeus/typhoeus/commit/256c95473d5d40d7ec2f5db603687323ddd73689
    # headers are now downcased.
    # ...except when they're not.  I'm not 100% why (I haven't had time to dig into it yet)
    # but in some situations the headers aren't downcased.  I think it has to do with playback; VCR
    # isn't sending the headers in downcased to typhoeus. It gets complicated with the interaction
    # w/ WebMock, and the fact that webmock normalizes headers in a different fashion.
    #
    # For now this hack works.
    response.headers.fetch(header_key.downcase) { response.headers[header_key] }
  end

  def make_http_request(method, url, body = nil, headers = {})
    request = Typhoeus::Request.new(url, :method => method, :body => body, :headers => headers)
    request.run
    request.response
  end

  def normalize_request_headers(headers)
    headers.merge("User-Agent"=>["Typhoeus - https://github.com/typhoeus/typhoeus"], 'Expect' => [''])
  end
end

HTTP_LIBRARY_ADAPTERS['typhoeus 0.4'] = Module.new do
  def self.http_library_name; "Typhoeus"; end

  def get_body_string(response)
    response.body
  end
  alias get_body_object get_body_string

  def get_header(header_key, response)
    response.headers_hash[header_key]
  end

  def make_http_request(method, url, body = nil, headers = {})
    Typhoeus::Request.send(method, url, :body => body, :headers => headers)
  end

  def normalize_request_headers(headers)
    headers
  end
end

HTTP_LIBRARY_ADAPTERS['excon'] = Module.new do
  def self.http_library_name; "Excon"; end

  def get_body_string(response)
    response.body
  end
  alias get_body_object get_body_string

  def get_header(header_key, response)
    response.headers[header_key]
  end

  def make_http_request(method, url, body = nil, headers = {})
    # There are multiple ways to use Excon but this is how fog (the main user of excon) uses it:
    # https://github.com/fog/fog/blob/v1.1.1/lib/fog/aws/rds.rb#L139-147
    Excon.new(url).request(:method => method.to_s.upcase, :body => body, :headers => headers)
  end

  def normalize_request_headers(headers)
    if Gem::Version.new(Excon::VERSION) < Gem::Version.new("0.63")
      headers.merge('User-Agent' => [Excon::USER_AGENT])
    else
      headers.merge('User-Agent' => [Excon::USER_AGENT], 'Accept' => ['*/*'])
    end
  end
end

%w[ net_http typhoeus patron ].each do |_faraday_adapter|
  if _faraday_adapter == 'typhoeus' &&
     defined?(::Typhoeus::VERSION) &&
     ::Typhoeus::VERSION.to_f >= 0.5
    require 'typhoeus/adapters/faraday'
  end

  HTTP_LIBRARY_ADAPTERS["faraday (w/ #{_faraday_adapter})"] = Module.new do
    class << self; self; end.class_eval do
      define_method(:http_library_name) do
        "Faraday (#{_faraday_adapter})"
      end
    end

    define_method(:faraday_adapter) { _faraday_adapter.to_sym }

    def get_body_string(response)
      response.body
    end
    alias get_body_object get_body_string

    def get_header(header_key, response)
      value = response.headers[header_key]
      value.split(', ') if value
    end

    def make_http_request(method, url, body = nil, headers = {})
      url_root, url_rest = split_url(url)

      faraday_connection(url_root).send(method) do |req|
        req.url url_rest
        headers.each { |k, v| req[k] = v }
        req.body = body if body
      end
    end

    def split_url(url)
      uri = URI.parse(url)
      url_root = "#{uri.scheme}://#{uri.host}:#{uri.port}"
      rest = url.sub(url_root, '')

      [url_root, rest]
    end

    def faraday_connection(url_root)
      Faraday::Connection.new(:url => url_root) do |builder|
        builder.adapter faraday_adapter
      end
    end

    def normalize_request_headers(headers)
      headers.merge("User-Agent" => ["Faraday v#{Faraday::VERSION}"])
    end
  end
end