httpadapter 0.2.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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