httpadapter 0.2.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ == 1.0.0
2
+
3
+ * rewrite to expose important implementation-specific configuration stuff
4
+
1
5
  == 0.2.1
2
6
 
3
7
  * added mock adapter for testing
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # HTTPAdapter
2
+
3
+ <dl>
4
+ <dt>Homepage</dt><dd><a href="http://httpadapter.rubyforge.org/">httpadapter.rubyforge.org</a></dd>
5
+ <dt>Author</dt><dd><a href="mailto:bobaman@google.com">Bob Aman</a></dd>
6
+ <dt>Copyright</dt><dd>Copyright © 2010 Google, Inc.</dd>
7
+ <dt>License</dt><dd>Apache 2.0</dd>
8
+ </dl>
9
+
10
+ # Description
11
+
12
+ A library for translating HTTP request and response objects for various clients
13
+ into a common representation.
14
+
15
+ # Reference
16
+
17
+ - {HTTPAdapter}
18
+
19
+ # Adapters
20
+
21
+ - {HTTPAdapter::NetHTTPAdapter}
22
+ - {HTTPAdapter::RackAdapter}
23
+ - {HTTPAdapter::TyphoeusAdapter}
24
+
25
+ # Example Usage
26
+
27
+ adapter = HTTPAdapter::NetHTTPAdapter.new
28
+ response = Net::HTTP.start('www.google.com', 80) { |http| http.get('/') }
29
+ # => #<Net::HTTPOK 200 OK readbody=true>
30
+ result = adapter.adapt_response(response)
31
+ # => [
32
+ # 200,
33
+ # [
34
+ # ["Expires", "-1"],
35
+ # ["Content-Type", "text/html; charset=ISO-8859-1"],
36
+ # ["X-Xss-Protection", "1; mode=block"],
37
+ # ["Server", "gws"],
38
+ # ["Date", "Thu, 26 Aug 2010 22:13:03 GMT"],
39
+ # ["Set-Cookie", "<snip>"],
40
+ # ["Cache-Control", "private, max-age=0"],
41
+ # ["Transfer-Encoding", "chunked"]
42
+ # ],
43
+ # ["<snip>"]
44
+ # ]
45
+
46
+ # Install
47
+
48
+ * sudo gem install httpadapter
data/lib/httpadapter.rb CHANGED
@@ -15,83 +15,100 @@
15
15
  require 'httpadapter/version'
16
16
  require 'httpadapter/connection'
17
17
 
18
- module HTTPAdapter #:nodoc:
18
+ ##
19
+ # A module which provides methods to aid in conversion of HTTP request and
20
+ # response objects. It uses tuples as a generic intermediary format.
21
+ #
22
+ # @example
23
+ # class StubAdapter
24
+ # include HTTPAdapter
25
+ #
26
+ # def convert_request_to_a(request_obj)
27
+ # return ['GET', '/', [], [""]] # Stubbed request tuple
28
+ # end
29
+ #
30
+ # def convert_request_from_a(request_ary)
31
+ # return Object.new # Stubbed request object
32
+ # end
33
+ #
34
+ # def convert_response_to_a(response_obj)
35
+ # return [200, [], ['']] # Stubbed response tuple
36
+ # end
37
+ #
38
+ # def convert_response_from_a(response_ary)
39
+ # return Object.new # Stubbed response object
40
+ # end
41
+ #
42
+ # def fetch_resource(request_ary, connection=nil)
43
+ # return [200, [], ['']] # Stubbed response tuple from server
44
+ # end
45
+ # end
46
+ module HTTPAdapter
19
47
  ##
20
48
  # Converts an HTTP request object to a simple tuple.
21
49
  #
22
- # @param [Object, #to_ary] request
23
- # The request object to be converted. The request may either implement
24
- # the <code>#to_ary</code> method directly or alternately, an optional
25
- # adapter class may be provided. The adapter must accept the request
26
- # object as a parameter and provide the <code>#to_ary</code> method.
50
+ # @param [Object] request
51
+ # The request object to be converted. The adapter must implement
52
+ # the <code>#convert_request_to_a</code> method, which takes the request
53
+ # object as a parameter.
27
54
  #
28
55
  # @return [Array] The tuple that the request was converted to.
29
- def self.adapt_request(request, adapter=nil)
30
- # Temporarily wrap the request if there's an adapter
31
- request = adapter.new(request) if adapter
32
- if request.respond_to?(:to_ary)
33
- converted_request = request.to_ary
56
+ def adapt_request(request_obj)
57
+ if self.respond_to?(:convert_request_to_a)
58
+ converted_request = self.convert_request_to_a(request_obj)
34
59
  else
35
- # Can't use #to_a because some versions of Ruby define #to_a on Object
36
60
  raise TypeError,
37
- "Expected adapter or request to implement #to_ary."
61
+ 'Expected adapter to implement #convert_request_to_a.'
38
62
  end
39
- return self.verified_request(converted_request)
40
- end
41
-
42
- ##
43
- # Converts an HTTP response object to a simple tuple.
44
- #
45
- # @param [Object, #to_ary] response
46
- # The response object to be converted. The response may either implement
47
- # the <code>#to_ary</code> method directly or alternately, an optional
48
- # adapter class may be provided. The adapter must accept the response
49
- # object as a parameter and provide the <code>#to_ary</code> method.
50
- #
51
- # @return [Array] The tuple that the reponse was converted to.
52
- def self.adapt_response(response, adapter=nil)
53
- # Temporarily wrap the response if there's an adapter
54
- response = adapter.new(response) if adapter
55
- if response.respond_to?(:to_ary)
56
- converted_response = response.to_ary
57
- else
58
- # Can't use #to_a because some versions of Ruby define #to_a on Object
59
- raise TypeError,
60
- "Expected adapter or response to implement #to_ary."
61
- end
62
- return self.verified_response(converted_response)
63
+ return HTTPAdapter.verified_request(converted_request)
63
64
  end
64
65
 
65
66
  ##
66
67
  # Converts a tuple to a specific HTTP implementation's request format.
67
68
  #
68
- # @param [Array] request
69
- # The request object to be converted. The request object must be a tuple
69
+ # @param [Array] request_ary
70
+ # The request array to be converted. The request array must be a tuple
70
71
  # with a length of 4. The first element must be the request method.
71
72
  # The second element must be the URI. The URI may be relative. The third
72
73
  # element contains the headers. It must respond to <code>#each</code> and
73
74
  # iterate over the header names and values. The fourth element must be
74
75
  # the body. It must respond to <code>#each</code> but may not be a
75
76
  # <code>String</code>. It should emit <code>String</code> objects.
76
- # @param [#from_ary] adapter
77
- # The adapter object that will convert to a tuple. It must respond to
78
- # <code>#from_ary</code>. Typically a reference to a class is used.
79
77
  #
80
78
  # @return [Array] The implementation-specific request object.
81
- def self.specialize_request(request, adapter)
82
- request = self.verified_request(request)
83
- if adapter.respond_to?(:from_ary)
84
- return adapter.from_ary(request)
79
+ def specialize_request(request_ary)
80
+ request = HTTPAdapter.verified_request(request_ary)
81
+ if self.respond_to?(:convert_request_from_a)
82
+ return self.convert_request_from_a(request)
83
+ else
84
+ raise TypeError,
85
+ 'Expected adapter to implement #convert_request_from_a.'
86
+ end
87
+ end
88
+
89
+ ##
90
+ # Converts an HTTP response object to a simple tuple.
91
+ #
92
+ # @param [Object] response
93
+ # The response object to be converted. The adapter must implement
94
+ # the <code>#convert_response_to_a</code> method, which takes the response
95
+ # object as a parameter.
96
+ #
97
+ # @return [Array] The tuple that the reponse was converted to.
98
+ def adapt_response(response_obj)
99
+ if self.respond_to?(:convert_response_to_a)
100
+ converted_response = self.convert_response_to_a(response_obj)
85
101
  else
86
102
  raise TypeError,
87
- "Expected adapter to implement .from_ary."
103
+ 'Expected adapter to implement #convert_response_to_a.'
88
104
  end
105
+ return HTTPAdapter.verified_response(converted_response)
89
106
  end
90
107
 
91
108
  ##
92
109
  # Converts a tuple to a specific HTTP implementation's response format.
93
110
  #
94
- # @param [Array] response
111
+ # @param [Array] response_ary
95
112
  # The response object to be converted. The response object must be a
96
113
  # tuple with a length of 3. The first element must be the HTTP status
97
114
  # code. The second element contains the headers. It must respond to
@@ -100,47 +117,41 @@ module HTTPAdapter #:nodoc:
100
117
  # but may not be a <code>String</code>. It should emit
101
118
  # <code>String</code> objects. This is essentially the same format that
102
119
  # Rack uses.
103
- # @param [#from_ary] adapter
104
- # The adapter object that will convert to a tuple. It must respond to
105
- # <code>#from_ary</code>. Typically a reference to a class is used.
106
120
  #
107
121
  # @return [Array] The implementation-specific response object.
108
- def self.specialize_response(response, adapter)
109
- response = self.verified_response(response)
110
- if adapter.respond_to?(:from_ary)
111
- return adapter.from_ary(response)
122
+ def specialize_response(response_ary)
123
+ response_ary = HTTPAdapter.verified_response(response_ary)
124
+ if self.respond_to?(:convert_response_from_a)
125
+ return self.convert_response_from_a(response_ary)
112
126
  else
113
- raise TypeError, 'Expected adapter to implement .from_ary.'
127
+ raise TypeError,
128
+ 'Expected adapter to implement #convert_response_from_a.'
114
129
  end
115
130
  end
116
131
 
117
132
  ##
118
133
  # Transmits a request.
119
134
  #
120
- # @param [Array] request
121
- # The request that will be sent.
122
- # @param [#transmit] adapter
123
- # The adapter object that will perform the transmission of the HTTP
124
- # request. It must respond to <code>#transmit</code>. Typically a
125
- # reference to a class is used.
135
+ # @param [Array] request_ary
136
+ # The request tuple that will be sent.
126
137
  # @param [HTTPAdapter::Connection] connection
127
138
  # An object representing a connection. This object represents an open
128
139
  # HTTP connection that is used to make multiple HTTP requests.
129
140
  # @return [Array]
130
141
  # The response given by the server.
131
142
  #
132
- # @return [Array] The implementation-specific response object.
133
- def self.transmit(request, adapter, connection=nil)
134
- request = self.verified_request(request)
143
+ # @return [Array] A tuple representing the response from the server.
144
+ def transmit(request_ary, connection=nil)
145
+ request_ary = HTTPAdapter.verified_request(request_ary)
135
146
  if connection && !connection.kind_of?(HTTPAdapter::Connection)
136
147
  raise TypeError,
137
148
  "Expected HTTPAdapter::Connection, got #{connection.class}."
138
149
  end
139
- if adapter.respond_to?(:transmit)
140
- response = adapter.transmit(request, connection)
141
- return self.verified_response(response)
150
+ if self.respond_to?(:fetch_resource)
151
+ response_ary = self.fetch_resource(request_ary, connection)
152
+ return HTTPAdapter.verified_response(response_ary)
142
153
  else
143
- raise TypeError, 'Expected adapter to implement .transmit.'
154
+ raise TypeError, 'Expected adapter to implement .fetch_resource.'
144
155
  end
145
156
  end
146
157
 
@@ -187,7 +198,7 @@ module HTTPAdapter #:nodoc:
187
198
  headers << [header, value]
188
199
  end
189
200
  else
190
- raise TypeError, "Expected headers to respond to #each."
201
+ raise TypeError, 'Expected headers to respond to #each.'
191
202
  end
192
203
  if body.kind_of?(String)
193
204
  raise TypeError,
@@ -197,11 +208,12 @@ module HTTPAdapter #:nodoc:
197
208
  # Can't verify that all chunks are Strings because #each may be
198
209
  # effectively destructive.
199
210
  if !body.respond_to?(:each)
200
- raise TypeError, "Expected body to respond to #each."
211
+ raise TypeError, 'Expected body to respond to #each.'
201
212
  end
202
213
  else
203
214
  raise TypeError,
204
- "Expected tuple of [method, uri, headers, body]."
215
+ "Expected tuple of [method, uri, headers, body], " +
216
+ "got #{request.inspect}."
205
217
  end
206
218
  return [method, uri, headers, body]
207
219
  end
@@ -240,7 +252,7 @@ module HTTPAdapter #:nodoc:
240
252
  headers << [header, value]
241
253
  end
242
254
  else
243
- raise TypeError, "Expected headers to respond to #each."
255
+ raise TypeError, 'Expected headers to respond to #each.'
244
256
  end
245
257
  if body.kind_of?(String)
246
258
  raise TypeError,
@@ -250,11 +262,11 @@ module HTTPAdapter #:nodoc:
250
262
  # Can't verify that all chunks are Strings because #each may be
251
263
  # effectively destructive.
252
264
  if !body.respond_to?(:each)
253
- raise TypeError, "Expected body to respond to #each."
265
+ raise TypeError, 'Expected body to respond to #each.'
254
266
  end
255
267
  else
256
268
  raise TypeError,
257
- "Expected tuple of [status, headers, body]."
269
+ "Expected tuple of [status, headers, body], got #{response.inspect}."
258
270
  end
259
271
  return [status, headers, body]
260
272
  end
@@ -14,22 +14,24 @@
14
14
 
15
15
  require 'httpadapter'
16
16
 
17
- module HTTPAdapter #:nodoc:
17
+ module HTTPAdapter
18
18
  ##
19
19
  # A simple module for mocking the transmit method on an adapter.
20
20
  #
21
21
  # @example
22
22
  # # Using RSpec, verify that the request being sent includes a user agent.
23
- # adapter = HTTPAdapter::MockAdapter.request_adapter do |req, conn|
24
- # method, uri, headers, body = req
23
+ # adapter = HTTPAdapter::MockAdapter.create do |request_ary, connection|
24
+ # method, uri, headers, body = request_ary
25
25
  # headers.should be_any { |k, v| k.downcase == 'user-agent' }
26
26
  # end
27
27
  module MockAdapter
28
- def self.request_adapter(&block)
29
- return Class.new do
28
+ def self.create(&block)
29
+ adapter = Class.new do
30
+ include HTTPAdapter
31
+
30
32
  @@block = block
31
33
 
32
- def self.transmit(*params)
34
+ def fetch_resource(*params)
33
35
  response = @@block.call(*params)
34
36
  if response.respond_to?(:each)
35
37
  return response
@@ -38,6 +40,7 @@ module HTTPAdapter #:nodoc:
38
40
  end
39
41
  end
40
42
  end
43
+ return adapter.new
41
44
  end
42
45
  end
43
46
  end
@@ -18,7 +18,9 @@ require 'net/http'
18
18
  require 'addressable/uri'
19
19
 
20
20
  module HTTPAdapter #:nodoc:
21
- class NetHTTPRequestAdapter
21
+ class NetHTTPAdapter
22
+ include HTTPAdapter
23
+
22
24
  METHOD_MAPPING = {
23
25
  # RFC 2616
24
26
  'OPTIONS' => Net::HTTP::Options,
@@ -38,116 +40,6 @@ module HTTPAdapter #:nodoc:
38
40
  'UNLOCK' => Net::HTTP::Unlock
39
41
  }
40
42
 
41
- def initialize(request, options={})
42
- unless request.kind_of?(Net::HTTPRequest)
43
- raise TypeError, "Expected Net::HTTPRequest, got #{request.class}."
44
- end
45
- @request = request
46
- @uri = Addressable::URI.parse(options[:uri] || request.path || "")
47
- if !@uri.host && options[:host]
48
- @uri.host = options[:host]
49
- if !@uri.scheme && options[:scheme]
50
- @uri.scheme = options[:scheme]
51
- elsif !@uri.scheme
52
- @uri.scheme = 'http'
53
- end
54
- if !@uri.port && options[:port]
55
- @uri.port = options[:port]
56
- end
57
- @uri.scheme = @uri.normalized_scheme
58
- @uri.authority = @uri.normalized_authority
59
- end
60
- end
61
-
62
- def to_ary
63
- method = @request.method.to_s.upcase
64
- uri = @uri.to_str
65
- headers = []
66
- @request.canonical_each do |header, value|
67
- headers << [header, value]
68
- end
69
- body = @request.body || ""
70
- return [method, uri, headers, [body]]
71
- end
72
-
73
- def self.from_ary(array)
74
- method, uri, headers, body = array
75
- method = method.to_s.upcase
76
- uri = Addressable::URI.parse(uri)
77
- request_class = METHOD_MAPPING[method]
78
- unless request_class
79
- raise ArgumentError, "Unknown HTTP method: #{method}"
80
- end
81
- request = request_class.new(uri.request_uri)
82
- headers.each do |header, value|
83
- request[header] = value
84
- if header.downcase == 'Content-Type'.downcase
85
- request.content_type = value
86
- end
87
- end
88
- merged_body = ""
89
- body.each do |chunk|
90
- merged_body += chunk
91
- end
92
- if merged_body.length > 0
93
- request.body = merged_body
94
- elsif ['POST', 'PUT'].include?(method)
95
- request.content_length = 0
96
- end
97
- return request
98
- end
99
-
100
- def self.transmit(request, connection=nil)
101
- method, uri, headers, body = request
102
- uri = Addressable::URI.parse(uri)
103
- net_http_request = self.from_ary([method, uri, headers, body])
104
- net_http_response = nil
105
- unless connection
106
- http = Net::HTTP.new(uri.host, uri.inferred_port)
107
- if uri.normalized_scheme == 'https'
108
- require 'net/https'
109
- http.use_ssl = true
110
- if http.respond_to?(:enable_post_connection_check=)
111
- http.enable_post_connection_check = true
112
- end
113
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
114
- store = OpenSSL::X509::Store.new
115
- store.set_default_paths
116
- http.cert_store = store
117
- context = http.instance_variable_get('@ssl_context')
118
- if context && context.respond_to?(:tmp_dh_callback) &&
119
- context.tmp_dh_callback == nil
120
- context.tmp_dh_callback = lambda do |*args|
121
- tmp_dh_key_file = File.expand_path(
122
- ENV['TMP_DH_KEY_FILE'] || "~/.dhparams.pem"
123
- )
124
- if File.exists?(tmp_dh_key_file)
125
- OpenSSL::PKey::DH.new(File.read(tmp_dh_key_file))
126
- else
127
- # Slow, fix with `openssl dhparam -out ~/.dhparams.pem 2048`
128
- OpenSSL::PKey::DH.new(512)
129
- end
130
- end
131
- end
132
- end
133
- http.start
134
- connection = HTTPAdapter::Connection.new(
135
- uri.host, uri.inferred_port, http,
136
- :open => [:start, [], nil],
137
- :close => [:finish, [], nil]
138
- )
139
- else
140
- http = nil
141
- end
142
- net_http_response = connection.connection.request(net_http_request)
143
- if http
144
- connection.close
145
- end
146
- return NetHTTPResponseAdapter.new(net_http_response).to_ary
147
- end
148
- end
149
-
150
- class NetHTTPResponseAdapter
151
43
  STATUS_MESSAGES = {
152
44
  100 => "Continue",
153
45
  101 => "Switching Protocols",
@@ -205,25 +97,87 @@ module HTTPAdapter #:nodoc:
205
97
  }
206
98
  STATUS_MAPPING = Net::HTTPResponse::CODE_TO_OBJ
207
99
 
208
- def initialize(response)
209
- unless response.kind_of?(Net::HTTPResponse)
210
- raise TypeError, "Expected Net::HTTPResponse, got #{response.class}."
100
+ def initialize(&block)
101
+ @connection_config = block
102
+ end
103
+
104
+ def convert_request_to_a(request_obj)
105
+ unless request_obj.kind_of?(Net::HTTPRequest)
106
+ raise TypeError, "Expected Net::HTTPRequest, got #{request_obj.class}."
211
107
  end
212
- @response = response
108
+ method = request_obj.method.to_s.upcase
109
+ host_from_header = nil
110
+ scheme_from_header = nil
111
+ headers = []
112
+ request_obj.canonical_each do |header, value|
113
+ if header.downcase == 'X-Forwarded-Proto'.downcase
114
+ scheme_from_header = value
115
+ elsif header.downcase == 'Host'.downcase
116
+ host_from_header = value
117
+ end
118
+ headers << [header, value]
119
+ end
120
+ uri = Addressable::URI.parse(request_obj.path || "")
121
+ uri.host ||= host_from_header
122
+ if uri.host
123
+ uri.scheme ||= scheme_from_header || 'http'
124
+ uri.scheme = uri.normalized_scheme
125
+ uri.authority = uri.normalized_authority
126
+ end
127
+ uri = uri.to_str
128
+ body = request_obj.body || ""
129
+ return [method, uri, headers, [body]]
213
130
  end
214
131
 
215
- def to_ary
216
- status = @response.code.to_i
132
+ def convert_request_from_a(request_ary)
133
+ method, uri, headers, body = request_ary
134
+ method = method.to_s.upcase
135
+ host_from_header = nil
136
+ uri = Addressable::URI.parse(uri)
137
+ request_class = METHOD_MAPPING[method]
138
+ unless request_class
139
+ raise ArgumentError, "Unknown HTTP method: #{method}"
140
+ end
141
+ request = request_class.new(uri.request_uri)
142
+ headers.each do |header, value|
143
+ request[header] = value
144
+ if header.downcase == 'Content-Type'.downcase
145
+ request.content_type = value
146
+ elsif header.downcase == 'Host'.downcase
147
+ host_from_header = value
148
+ end
149
+ end
150
+ if host_from_header == nil && uri.host
151
+ request['Host'] = uri.host
152
+ end
153
+ merged_body = ""
154
+ body.each do |chunk|
155
+ merged_body += chunk
156
+ end
157
+ if merged_body.length > 0
158
+ request.body = merged_body
159
+ elsif ['POST', 'PUT'].include?(method)
160
+ request.content_length = 0
161
+ end
162
+ return request
163
+ end
164
+
165
+ def convert_response_to_a(response_obj)
166
+ unless response_obj.kind_of?(Net::HTTPResponse)
167
+ raise TypeError,
168
+ "Expected Net::HTTPResponse, got #{response_obj.class}."
169
+ end
170
+ status = response_obj.code.to_i
217
171
  headers = []
218
- @response.canonical_each do |header, value|
172
+ response_obj.canonical_each do |header, value|
219
173
  headers << [header, value]
220
174
  end
221
- body = @response.body || ""
175
+ body = response_obj.body || ""
222
176
  return [status, headers, [body]]
223
177
  end
224
178
 
225
- def self.from_ary(array)
226
- status, headers, body = array
179
+ def convert_response_from_a(response_ary)
180
+ status, headers, body = response_ary
227
181
  message = STATUS_MESSAGES[status.to_i]
228
182
  response_class = STATUS_MAPPING[status.to_s]
229
183
  unless message && response_class
@@ -245,5 +199,55 @@ module HTTPAdapter #:nodoc:
245
199
 
246
200
  return response
247
201
  end
202
+
203
+ def fetch_resource(request_ary, connection=nil)
204
+ method, uri, headers, body = request_ary
205
+ uri = Addressable::URI.parse(uri)
206
+ net_http_request = self.convert_request_from_a(
207
+ [method, uri, headers, body]
208
+ )
209
+ net_http_response = nil
210
+ unless connection
211
+ http = Net::HTTP.new(uri.host, uri.inferred_port)
212
+ if uri.normalized_scheme == 'https'
213
+ require 'net/https'
214
+ http.use_ssl = true
215
+ if http.respond_to?(:enable_post_connection_check=)
216
+ http.enable_post_connection_check = true
217
+ end
218
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
219
+ ca_file = File.expand_path(ENV['CA_FILE'] || '~/.cacert.pem')
220
+ if File.exists?(ca_file)
221
+ http.ca_file = ca_file
222
+ end
223
+ store = OpenSSL::X509::Store.new
224
+ store.set_default_paths
225
+ http.cert_store = store
226
+ context = http.instance_variable_get('@ssl_context')
227
+ if context && context.respond_to?(:tmp_dh_callback)
228
+ # Fix for annoying warning
229
+ context.tmp_dh_callback ||= lambda {}
230
+ end
231
+ end
232
+ connection = HTTPAdapter::Connection.new(
233
+ uri.host, uri.inferred_port, http,
234
+ :open => [:start, [], nil],
235
+ :close => [:finish, [], nil]
236
+ )
237
+ else
238
+ http = nil
239
+ end
240
+ if @connection_config
241
+ @connection_config.call(connection)
242
+ end
243
+ if connection.connection && !connection.connection.active?
244
+ connection.connection.start
245
+ end
246
+ net_http_response = connection.connection.request(net_http_request)
247
+ if http
248
+ connection.close
249
+ end
250
+ return self.convert_response_to_a(net_http_response)
251
+ end
248
252
  end
249
253
  end