http-client 0.1.1 → 0.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8833622cfb8dd5390e0daae8a669265432903ba5
4
- data.tar.gz: 76efa57c394ef3b0ea0073426161c8cb9e7f04db
3
+ metadata.gz: d9e9eae81102b0be33c27dc85929a220ab8bfee5
4
+ data.tar.gz: 4a2f85ca306800e17f5ee29a459ff2747a70eacf
5
5
  SHA512:
6
- metadata.gz: 28020a9dd60ca5f2415e4dcb3b44005550147afea1cf39232c962c22c06210b924ba3366b32b2f88137696499817b7abda4c5f1adff55ebaad07f6178df0687c
7
- data.tar.gz: 6c2cc5c1e1e9e92e994e4e7164b98771d1eed5f3ceb019a01fc6ece374e7e26c8c759e3e7d72214550ea7985e07528dfd57a99a8b7940aacebd453db6adf112a
6
+ metadata.gz: 770fd61b83f170d613ca39ee167fd652adbb88654e01b13f34fda61e68f93a038d44f8cd719e6327bbe6ba0ecd5cd4c6af94df90c65b5899ba332d3779ba548c
7
+ data.tar.gz: 2d96e1124de41b12e14ce29f6de8d9e78029a5b6ed70fb19d25781cc196f040e23a5c477363f01da49f448d624ae120a3825ff104f85b54bf7faa722952119bf
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ == 0.1.2 (2016-06-09)
2
+
3
+ * Fix YARD documentation.
4
+ * Preserve headers in 301, 302 & 303 redirects.
5
+ * Handle 303, 307 & 308.
6
+
1
7
  == 0.1.1 (2016-06-08)
2
8
 
3
9
  * Less restrictive dependency versions.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # HTTP Client
2
2
 
3
- A simple Net::HTTP wrapper with multi-part and cookie-jar support.
3
+ A simple Net::HTTP wrapper with multi-part request, file upload and cookie-jar support.
4
4
 
5
5
  ## Install
6
6
 
@@ -12,26 +12,33 @@ gem install http-client
12
12
 
13
13
  ```ruby
14
14
  require 'http-client'
15
- res = HTTP::Client::Request.new(:get, "http://www.example.org", max_redirects: 2).execute
15
+ res = HTTP::Client::Request.new(:get, "http://a.b/", max_redirects: 2).execute
16
16
 
17
17
  # save a few keystrokes.
18
- res = HTTP::Client.get("http://www.example.org/", max_redirects: 2)
19
- res = HTTP::Client.post(
20
- "http://www.example.org/",
21
- files: {pic: "kittens.jpg"},
22
- query: {title: "the usual suspects"}
23
- )
18
+ res = HTTP::Client.get("http://a.b/", max_redirects: 2)
19
+ res = HTTP::Client.put("http://a.b/", files: {pic: "kittens.jpg"}, query: {title: "the usual suspects"})
20
+ res = HTTP::Client.post("http://a.b/", auth: {username: "test", password: "test"}, headers: {'x-a' => 'b'})
21
+ res = HTTP::Client.delete("http://a.b/", auth: {username: "test", password: "test"});
24
22
  ```
25
23
 
26
24
  ## API
27
25
 
28
26
  ```
27
+ HTTP::Client
28
+ .get(uri, arguments = {})
29
+ .put(uri, arguments = {})
30
+ .post(uri, arguments = {})
31
+ .head(uri, arguments = {})
32
+ .trace(uri, arguments = {})
33
+ .delete(uri, arguments = {})
34
+ .options(uri, arguments = {})
35
+
29
36
  HTTP::Client::Request
30
37
  .new(verb, uri, arguments = {})
31
38
  #execute
32
39
 
33
40
  HTTP::Client::Response
34
- .new net_http_response, last_effective_uri
41
+ .new(net_http_response, last_effective_uri)
35
42
  #code
36
43
  #body
37
44
  #headers
@@ -49,24 +56,32 @@ HTTP::Client::Response
49
56
 
50
57
  #### Optional arguments hash
51
58
 
52
- | Name | Type | Description |
53
- |------|------|-------------|
54
- | headers | Hash | Net::HTTP headers, in key-value pairs. |
55
- | query | Hash | Net::HTTP query-string in key-value pairs. |
56
- | files | Hash | Multi-part file uploads, in key-value pairs of {name => path_to_file} or {name => [File]} |
57
- | body | String | Request body. |
58
- | auth | Hash | Basic-Auth hash. {username: "...", password: "..."} |
59
- | timeout | Integer | Fixed timeout for connection, read and ssl handshake in seconds. |
60
- | open_timeout | Integer | Connection timeout in seconds. |
61
- | read_timeout | Integer | Read timeout in seconds. |
62
- | ssl_timeout | Integer | SSL handshake timeout in seconds. |
63
- | max_redirects | Integer | Max redirect follow, default: 0 |
64
- | ssl_verify | Integer | OpenSSL verification, HTTP::Client::SSL_VERIFY_PEER or HTTP::Client::SSL_VERIFY_NONE, defaults to SSL_VERIFY_PEER. |
65
- | jar | HTTP::CookieJar | Optional cookie jar to use. Relies on HTTP::CookieJar from http-cookie gem. |
66
-
67
- ## TODO
68
-
69
- Extensive testing :/
59
+ | Name | Type | Description | Default |
60
+ |------|------|-------------|---------|
61
+ | headers | Hash | Net::HTTP headers, in key-value pairs. | nil |
62
+ | query | Hash | Net::HTTP query-string in key-value pairs. | nil |
63
+ | files | Hash | Multi-part file uploads, in key-value pairs of {name => path_to_file} or {name => File} | nil |
64
+ | body | String | Request body. | nil |
65
+ | auth | Hash | Basic-Auth hash. {username: "...", password: "..."} | nil |
66
+ | timeout | Integer | Fixed timeout for connection, read and ssl handshake in seconds. | Net::HTTP default |
67
+ | open_timeout | Integer | Connection timeout in seconds. | Net::HTTP default |
68
+ | read_timeout | Integer | Read timeout in seconds. | Net::HTTP default |
69
+ | ssl_timeout | Integer | SSL handshake timeout in seconds. | Net::HTTP default |
70
+ | max_redirects | Integer | Maximum redirects follow. | 0 |
71
+ | ssl_verify | Integer | OpenSSL verification. HTTP::Client::SSL_VERIFY_PEER or HTTP::Client::SSL_VERIFY_NONE | SSL_VERIFY_PEER |
72
+ | jar | HTTP::CookieJar | Optional cookie jar to use. Relies on HTTP::CookieJar from http-cookie gem. | HTTP::CookieJar.new |
73
+
74
+ ## Default behaviour
75
+
76
+ ### SSL
77
+
78
+ * By default peer verification is done. You can turn this off by passing `ssl_verfy: HTTP::Client::SSL_VERIFY_NONE` option.
79
+
80
+ ### Redirects
81
+
82
+ * By default the client does not follow redirects. You can enable this with a non-zero `max_redirects` option.
83
+ * 301, 302 and 303 redirects are always followed with a GET method.
84
+ * 307 and 308 redirects preserve original request method & body.
70
85
 
71
86
  ## License
72
87
 
data/lib/http/client.rb CHANGED
@@ -7,7 +7,7 @@ require 'http-cookie'
7
7
 
8
8
  module HTTP
9
9
  module Client
10
- VERSION = '0.1.1'
10
+ VERSION = '0.1.2'
11
11
 
12
12
  GET = Net::HTTP::Get
13
13
  HEAD = Net::HTTP::Head
@@ -16,45 +16,68 @@ module HTTP
16
16
  DELETE = Net::HTTP::Delete
17
17
  OPTIONS = Net::HTTP::Options
18
18
  TRACE = Net::HTTP::Trace
19
- VALID_VERBS = [GET, HEAD, PUT, POST, DELETE, OPTIONS, TRACE]
20
19
 
21
20
  SSL_VERIFY_NONE = OpenSSL::SSL::VERIFY_NONE
22
21
  SSL_VERIFY_PEER = OpenSSL::SSL::VERIFY_PEER
23
- VALID_SSL_VERIFICATIONS = [SSL_VERIFY_NONE, SSL_VERIFY_PEER]
24
-
25
- DEFAULT_HEADERS = {'User-Agent' => 'HTTP Client API/1.0'}
26
22
 
27
23
  class Request
28
- attr_reader :uri
24
+ VALID_PARAMETERS = %w(headers files query body auth timeout open_timeout ssl_timeout read_timeout max_redirects ssl_verify jar)
25
+ DEFAULT_HEADERS = {'User-Agent' => 'HTTP Client API/1.0'}
26
+
27
+ REDIRECT_WITH_GET = [301, 302, 303]
28
+ REDIRECT_WITH_ORIGINAL = [307, 308]
29
29
 
30
- VALID_PARAMETERS = %w(headers files query body auth timeout open_timeout ssl_timeout read_timeout max_redirects ssl_verify jar)
30
+ VALID_VERBS = [GET, HEAD, PUT, POST, DELETE, OPTIONS, TRACE]
31
+ VALID_SSL_VERIFICATIONS = [SSL_VERIFY_NONE, SSL_VERIFY_PEER]
32
+ VALID_REDIRECT_CODES = REDIRECT_WITH_GET + REDIRECT_WITH_ORIGINAL
31
33
 
32
34
  # Create a new HTTP Client Request.
33
35
  #
34
- # @param verb [Symbol] HTTP verb, one of :get, :head, :put, :post, :delete, :options, :trace.
35
- # @param uri [String] or [URI] Remote URI.
36
- # @param headers [Hash] Net::HTTP headers, in key-value pairs.
37
- # @param query [Hash] Net::HTTP query-string in key-value pairs.
38
- # @param files [Hash] Multi-part file uploads, in key-value pairs of {name => path_to_file} or {name => File}
39
- # @param body [String] Request body.
40
- # @param auth [Hash] Basic-Auth hash. {username: "...", password: "..."}
41
- # @param timeout [Integer] Fixed timeout for connection, read and ssl handshake in seconds.
42
- # @param open_timeout [Integer] Connection timeout in seconds.
43
- # @param read_timeout [Integer] Read timeout in seconds.
44
- # @param ssl_timeout [Integer] SSL handshake timeout in seconds.
45
- # @param max_redirects [Integer] Max redirect follow, default: 0
46
- # @param ssl_verify [Integer] OpenSSL verification, HTTP::Client::SSL_VERIFY_PEER or HTTP::Client::SSL_VERIFY_NONE, defaults to SSL_VERIFY_PEER.
47
- # @param jar [HTTP::CookieJar] Optional cookie jar to use. Relies on HTTP::CookieJar from http-cookie gem.
36
+ # @param [Symbol] verb HTTP verb, one of :get, :head, :put, :post, :delete, :options, :trace.
37
+ # @param [String or URI] uri Remote URI.
38
+ # @param [Hash] args Options, see below.
39
+ # @option args [Hash] headers Net::HTTP headers, in key-value pairs.
40
+ # @option args [Hash] query Net::HTTP query-string in key-value pairs.
41
+ # @option args [Hash] files Multi-part file uploads, in key-value pairs of name & path or name & File object.
42
+ # @option args [String] body Request body.
43
+ # @option args [Hash] auth Basic-Auth hash. Requires :username and :password.
44
+ # @option args [Integer] timeout Fixed timeout for connection, read and ssl handshake in seconds.
45
+ # @option args [Integer] open_timeout Connection timeout in seconds.
46
+ # @option args [Integer] read_timeout Read timeout in seconds.
47
+ # @option args [Integer] ssl_timeout SSL handshake timeout in seconds.
48
+ # @option args [Integer] max_redirects Max redirect follow, default: 0
49
+ # @option args [Integer] ssl_verify OpenSSL verification, SSL_VERIFY_PEER or SSL_VERIFY_NONE, defaults to SSL_VERIFY_PEER.
50
+ # @option args [HTTP::CookieJar] jar Optional cookie jar to use. Relies on HTTP::CookieJar from http-cookie gem.
48
51
  #
49
52
  # @return [HTTP::Client::Request]
50
53
  #
54
+ # @example Retrieve a page using GET.
55
+ # request = HTTP::Client::Request.new(:get, "http://www.example.org/", query: {q: "search something"})
56
+ # response = request.execute
57
+ #
58
+ # @example Handle redirects.
59
+ # request = HTTP::Client::Request.new(:get, "http://www.example.org/", max_redirects: 3)
60
+ # response = request.execute
61
+ #
62
+ # @example Perform request and return result in one go.
63
+ # response = HTTP::Client.get("http://www.example.org/", max_redirects: 3)
64
+ #
65
+ # @example Upload a few files in a POST request.
66
+ # request = HTTP::Client::Request.new(:post, "http://www.example.org/", files: {"cats" => "cats.jpg", "dogs" => "dogs.jpg"}, query: {title: "cute pics"})
67
+ # response = request.execute
68
+ #
69
+ # @example Pass in an external cookie jar.
70
+ # jar = HTTP::CookieJar.new
71
+ # jar.load("mycookies.cky")
72
+ # response = HTTP::Client.get("http://www.example.org/", jar: jar)
73
+ #
51
74
  def initialize verb, uri, args = {}
52
75
  args.each do |k, v|
53
76
  raise ArgumentError, "unknown argument #{k}" unless VALID_PARAMETERS.include?(k.to_s)
54
77
  end
55
78
 
56
- parse_uri! uri
57
- setup_request_delegate! verb, args
79
+ uri = parse_uri!(uri)
80
+ @delegate = create_request_delegate(verb, uri, args)
58
81
 
59
82
  if body = args[:body]
60
83
  raise ArgumentError, "#{verb} cannot have body" unless @delegate.class.const_get(:REQUEST_HAS_BODY)
@@ -77,9 +100,9 @@ module HTTP
77
100
  @ssl_timeout = args[:ssl_timeout] if args[:ssl_timeout]
78
101
  @read_timeout = args[:read_timeout] if args[:read_timeout]
79
102
 
80
- @redirects = args.fetch(:max_redirects, 0)
81
- @ssl_verify = args.fetch(:ssl_verify, SSL_VERIFY_PEER)
82
- @jar = args.fetch(:jar, HTTP::CookieJar.new)
103
+ @max_redirects = args.fetch(:max_redirects, 0)
104
+ @ssl_verify = args.fetch(:ssl_verify, SSL_VERIFY_PEER)
105
+ @jar = args.fetch(:jar, HTTP::CookieJar.new)
83
106
  end
84
107
 
85
108
  # Executes a request.
@@ -87,7 +110,7 @@ module HTTP
87
110
  # @return [HTTP::Client::Response]
88
111
  #
89
112
  def execute
90
- @last_effective_uri = uri
113
+ last_effective_uri = uri
91
114
 
92
115
  cookie = HTTP::Cookie.cookie_value(@jar.cookies(uri))
93
116
  if cookie && !cookie.empty?
@@ -97,57 +120,73 @@ module HTTP
97
120
  response = request!(uri, @delegate)
98
121
  @jar.parse(response['set-cookie'].to_s, uri)
99
122
 
100
- while @redirects > 0 && [301, 302, 307].include?(response.code.to_i)
101
- @redirects -= 1
102
- redirect = redirect_to(response['location'])
123
+ redirects = 0
124
+ while redirects < @max_redirects && VALID_REDIRECT_CODES.include?(response.code.to_i)
125
+ redirects += 1
126
+ last_effective_uri = parse_uri! response['location']
127
+ redirect_delegate = redirect_to(last_effective_uri, response.code.to_i)
103
128
 
104
- cookie = HTTP::Cookie.cookie_value(@jar.cookies(@last_effective_uri))
129
+ cookie = HTTP::Cookie.cookie_value(@jar.cookies(last_effective_uri))
105
130
  if cookie && !cookie.empty?
106
- redirect.add_field('Cookie', cookie)
131
+ redirect_delegate.add_field('Cookie', cookie)
107
132
  end
108
133
 
109
- response = request!(@last_effective_uri, redirect)
110
- @jar.parse(response['set-cookie'].to_s, @last_effective_uri)
134
+ response = request!(last_effective_uri, redirect_delegate)
135
+ @jar.parse(response['set-cookie'].to_s, last_effective_uri)
111
136
  end
112
137
 
113
- Response.new(response, @last_effective_uri)
138
+ Response.new(response, last_effective_uri)
114
139
  end
115
140
 
116
141
  private
142
+ def uri
143
+ @delegate.uri
144
+ end
145
+
117
146
  def parse_uri! uri
118
- @uri = uri.kind_of?(URI) ? uri : URI.parse(uri)
119
- case @uri
147
+ uri = uri.kind_of?(URI) ? uri : URI.parse(uri)
148
+ case uri
120
149
  when URI::HTTP, URI::HTTPS
121
- # ok
150
+ uri
151
+ when URI::Generic
152
+ if @delegate.uri
153
+ @delegate.uri.dup.tap {|s| s += uri }
154
+ else
155
+ raise ArgumentError, "Invalid URI #{uri}"
156
+ end
122
157
  else
123
158
  raise ArgumentError, "Invalid URI #{uri}"
124
159
  end
125
160
  end
126
161
 
127
- def setup_request_delegate! verb, args
128
- klass = find_delegate_class(verb)
129
- @headers = DEFAULT_HEADERS.merge(args.fetch(:headers, {}))
162
+ def create_request_delegate verb, uri, args
163
+ klass = find_delegate_class(verb)
164
+ headers = DEFAULT_HEADERS.merge(args.fetch(:headers, {}))
130
165
 
131
166
  files = args[:files]
132
167
  qs = args[:query]
168
+ uri = uri.dup
169
+ delegate = nil
133
170
 
134
171
  if files
135
172
  raise ArgumentError, "#{verb} cannot have body" unless klass.const_get(:REQUEST_HAS_BODY)
136
- multipart = Multipart.new(files, qs)
137
- @delegate = klass.new(@uri.request_uri, headers_for(@uri))
138
- @delegate.content_type = multipart.content_type
139
- @delegate.body = multipart.body
173
+ multipart = Multipart.new(files, qs)
174
+ delegate = klass.new(uri, headers)
175
+ delegate.content_type = multipart.content_type
176
+ delegate.body = multipart.body
140
177
  elsif qs
141
178
  if klass.const_get(:REQUEST_HAS_BODY)
142
- @delegate = klass.new(@uri.request_uri, headers_for(@uri))
143
- @delegate.set_form_data(qs)
179
+ delegate = klass.new(uri, headers)
180
+ delegate.set_form_data(qs)
144
181
  else
145
- @uri.query = URI.encode_www_form(qs)
146
- @delegate = klass.new(@uri.request_uri, headers_for(@uri))
182
+ uri.query = URI.encode_www_form(qs)
183
+ delegate = klass.new(uri, headers)
147
184
  end
148
185
  else
149
- @delegate = klass.new(@uri.request_uri, headers_for(@uri))
186
+ delegate = klass.new(uri, headers)
150
187
  end
188
+
189
+ delegate
151
190
  end
152
191
 
153
192
  def request! uri, delegate
@@ -166,13 +205,28 @@ module HTTP
166
205
  response
167
206
  end
168
207
 
169
- def redirect_to uri
170
- @last_effective_uri = URI.parse(uri)
171
- GET.new(@last_effective_uri.request_uri, headers_for(@last_effective_uri))
172
- end
173
-
174
- def headers_for uri
175
- @headers
208
+ def redirect_to uri, code
209
+ # NOTE request-uri with query string is not preserved.
210
+ case code
211
+ when *REDIRECT_WITH_GET
212
+ GET.new(uri, {}).tap do |r|
213
+ @delegate.each_header do |field, value|
214
+ next if field.downcase == 'host'
215
+ r[field] = value
216
+ end
217
+ end
218
+ when *REDIRECT_WITH_ORIGINAL
219
+ @delegate.class.new(uri, {}).tap do |r|
220
+ @delegate.each_header do |field, value|
221
+ next if field.downcase == 'host'
222
+ r[field] = value
223
+ end
224
+
225
+ r.body = @delegate.body
226
+ end
227
+ else
228
+ raise RuntimeError, "response #{code} should not result in redirection."
229
+ end
176
230
  end
177
231
 
178
232
  def find_delegate_class verb
@@ -290,44 +344,56 @@ module HTTP
290
344
  # Creates a GET request and executes it, returning the response.
291
345
  # @see HTTP::Client::Request#initialize
292
346
  #
347
+ # @param [String or URI] uri Remote URI.
348
+ # @param [Hash] args Options, see HTTP::Client::Request#initialize.
293
349
  # @return [HTTP::Client::Response]
294
350
  #
295
- def get *args; Request.new(GET, *args).execute; end
351
+ def get uri, args = {}; Request.new(GET, uri, args).execute; end
296
352
 
297
353
  # Creates a PUT request and executes it, returning the response.
298
354
  # @see HTTP::Client::Request#initialize
299
355
  #
356
+ # @param [String or URI] uri Remote URI.
357
+ # @param [Hash] args Options, see HTTP::Client::Request#initialize.
300
358
  # @return [HTTP::Client::Response]
301
359
  #
302
- def put *args; Request.new(PUT, *args).execute; end
360
+ def put uri, args = {}; Request.new(PUT, uri, args).execute; end
303
361
 
304
362
  # Creates a POST request and executes it, returning the response.
305
363
  # @see HTTP::Client::Request#initialize
306
364
  #
365
+ # @param [String or URI] uri Remote URI.
366
+ # @param [Hash] args Options, see HTTP::Client::Request#initialize.
307
367
  # @return [HTTP::Client::Response]
308
368
  #
309
- def post *args; Request.new(POST, *args).execute; end
369
+ def post uri, args = {}; Request.new(POST, uri, args).execute; end
310
370
 
311
371
  # Creates a DELETE request and executes it, returning the response.
312
372
  # @see HTTP::Client::Request#initialize
313
373
  #
374
+ # @param [String or URI] uri Remote URI.
375
+ # @param [Hash] args Options, see HTTP::Client::Request#initialize.
314
376
  # @return [HTTP::Client::Response]
315
377
  #
316
- def delete *args; Request.new(DELETE, *args).execute; end
378
+ def delete uri, args = {}; Request.new(DELETE, uri, args).execute; end
317
379
 
318
380
  # Creates a OPTIONS request and executes it, returning the response.
319
381
  # @see HTTP::Client::Request#initialize
320
382
  #
383
+ # @param [String or URI] uri Remote URI.
384
+ # @param [Hash] args Options, see HTTP::Client::Request#initialize.
321
385
  # @return [HTTP::Client::Response]
322
386
  #
323
- def options *args; Request.new(OPTIONS, *args).execute; end
387
+ def options uri, args = {}; Request.new(OPTIONS, uri, args).execute; end
324
388
 
325
389
  # Creates a TRACE request and executes it, returning the response.
326
390
  # @see HTTP::Client::Request#initialize
327
391
  #
392
+ # @param [String or URI] uri Remote URI.
393
+ # @param [Hash] args Options, see HTTP::Client::Request#initialize.
328
394
  # @return [HTTP::Client::Response]
329
395
  #
330
- def trace *args; Request.new(TRACE, *args).execute; end
396
+ def trace uri, args = {}; Request.new(TRACE, uri, args).execute; end
331
397
  end
332
398
  end # Client
333
399
  end # HTTP
data/test/test_request.rb CHANGED
@@ -2,20 +2,20 @@ require_relative 'helper'
2
2
 
3
3
  describe 'HTTP Client Request' do
4
4
  it 'should reject invalid arguments' do
5
- assert_raises(ArgumentError, "invalid verb") {HTTP::Client::Request.new(:foo)}
6
- assert_raises(URI::InvalidURIError, "invalid uri") {HTTP::Client::Request.new(:get, "http://")}
7
- assert_raises(ArgumentError, "invalid argument") {HTTP::Client::Request.new(:get, "http://example.org/", foo: 1)}
5
+ assert_raises(ArgumentError, 'invalid verb') {HTTP::Client::Request.new(:foo)}
6
+ assert_raises(URI::InvalidURIError, 'invalid uri') {HTTP::Client::Request.new(:get, 'http://')}
7
+ assert_raises(ArgumentError, 'invalid argument') {HTTP::Client::Request.new(:get, 'http://example.org/', foo: 1)}
8
8
  end
9
9
 
10
10
  it 'validates body based on request verb' do
11
- assert_raises(ArgumentError, "get cannot have body") {HTTP::Client::Request.new(:get, "http://a.c", files: {test: __FILE__})}
11
+ assert_raises(ArgumentError, 'get cannot have body') {HTTP::Client::Request.new(:get, 'http://a.c', files: {test: __FILE__})}
12
12
  end
13
13
 
14
14
  it 'allows creation of valid request object' do
15
15
  assert HTTP::Client::Request.new(
16
16
  :post,
17
- "http://example.org/",
18
- query: {title: "test"},
17
+ 'http://example.org/',
18
+ query: {title: 'test'},
19
19
  files: {test1: __FILE__, test2: __FILE__},
20
20
  max_redirects: 2,
21
21
  timeout: 10,
@@ -25,7 +25,7 @@ describe 'HTTP Client Request' do
25
25
  end
26
26
 
27
27
  it 'executes a request and returns reponse' do
28
- app = proc {|req| [200, {}, "Hello World!"]}
28
+ app = proc {|req| [200, {}, 'Hello World!']}
29
29
  server = TestServer.new(app)
30
30
  server.run
31
31
 
@@ -43,65 +43,119 @@ describe 'HTTP Client Request' do
43
43
  end
44
44
 
45
45
  it 'handles redirects' do
46
- app = proc do |req|
47
- case req.path
48
- when '/redirect2'
49
- [200, {}, "Hello World!"]
50
- when '/redirect1'
51
- [302, {'Location' => '/redirect2'}, "Moved!"]
52
- when '/'
53
- [302, {'Location' => '/redirect1'}, "Moved!"]
46
+ cookie = 'foo=bar; expires=Mon, 31-Dec-2038 23:59:59 GMT; path=/; domain=.127.0.0.1'
47
+
48
+ [301, 302, 303, 307, 308]. each do |code|
49
+ cookies = []
50
+ methods = []
51
+ headers = {}
52
+ app = proc do |req|
53
+ cookies << req['cookie']
54
+ case req.path
55
+ when '/redirect2'
56
+ req.each {|k,v| headers[k] = v}
57
+ methods << req.request_method
58
+ [200, {}, 'Hello World!']
59
+ when '/redirect1'
60
+ methods << req.request_method
61
+ [code, {'Location' => '/redirect2'}, 'Moved!']
62
+ when '/'
63
+ [code, {'Location' => '/redirect1', 'Set-Cookie' => cookie}, 'Moved!']
64
+ end
65
+ end
66
+
67
+ server = TestServer.new(app)
68
+ server.run
69
+
70
+ response = HTTP::Client.post(server.root)
71
+ assert_equal code, response.code
72
+ assert_equal %Q{#{server.root + '/redirect1'}}, response.headers['location']
73
+
74
+ response = HTTP::Client.post(server.root, max_redirects: 1)
75
+ assert_equal code, response.code
76
+ assert_equal %Q{#{server.root + '/redirect1'}}, response.last_effective_uri.to_s
77
+ assert_equal %Q{#{server.root + '/redirect2'}}, response.headers['location']
78
+
79
+ response = HTTP::Client.post(server.root, headers: {'x-foo-1' => 'bar'}, max_redirects: 2)
80
+ assert_equal 200, response.code
81
+ assert_equal %Q{#{server.root + '/redirect2'}}, response.last_effective_uri.to_s
82
+
83
+ server.stop
84
+ cookies.compact!
85
+ assert_equal 3, cookies.size
86
+ assert_equal 1, cookies.uniq.size
87
+ assert_equal 'foo=bar', cookies.first
88
+
89
+ methods.compact!
90
+ assert_equal 1, methods.uniq.size
91
+ if [307, 308].include?(code)
92
+ assert_equal 'POST', methods.first
93
+ else
94
+ assert_equal 'GET', methods.first
54
95
  end
96
+
97
+ assert_equal 'bar', headers['x-foo-1']
55
98
  end
56
- server = TestServer.new(app)
57
- server.run
99
+ end
58
100
 
59
- response = HTTP::Client.get(server.root)
60
- assert_equal 302, response.code
61
- assert_equal %Q{#{server.root + "/redirect1"}}, response.headers['location']
101
+ it 'handles HTTP 1.1 redirects' do
102
+ [307, 308].each do |code|
103
+ bucket = []
104
+ app = proc do |req|
105
+ case req.path
106
+ when '/redirect'
107
+ bucket = req.query
108
+ [200, {}, 'Hello World!']
109
+ when '/'
110
+ [code, {'Location' => '/redirect'}, 'Moved!']
111
+ end
112
+ end
62
113
 
63
- response = HTTP::Client.get(server.root, max_redirects: 1)
64
- assert_equal 302, response.code
65
- assert_equal %Q{#{server.root + "/redirect1"}}, response.last_effective_uri.to_s
66
- assert_equal %Q{#{server.root + "/redirect2"}}, response.headers['location']
114
+ server = TestServer.new(app)
115
+ server.run
67
116
 
68
- response = HTTP::Client.get(server.root, max_redirects: 2)
69
- assert_equal 200, response.code
70
- assert_equal %Q{#{server.root + "/redirect2"}}, response.last_effective_uri.to_s
117
+ response = HTTP::Client.post(server.root, query: {foo: 'bar'}, files: {baz: __FILE__}, max_redirects: 1)
118
+ assert_equal 200, response.code
119
+ assert_equal %Q{#{server.root + '/redirect'}}, response.last_effective_uri.to_s
120
+ server.stop
121
+
122
+ assert bucket['foo'], 'query 1 preserved'
123
+ assert bucket['baz'], 'file upload preserved'
124
+ end
71
125
  end
72
126
 
73
127
  it 'posts url encoded form' do
74
128
  qs = {}
75
129
  app = proc do |req|
76
130
  qs = req.query
77
- [200, {}, "OK!"]
131
+ [200, {}, 'OK!']
78
132
  end
79
133
  server = TestServer.new(app)
80
134
  server.run
81
135
 
82
- response = HTTP::Client.post(server.root, query: {test1: "test2"})
136
+ response = HTTP::Client.post(server.root, query: {test1: 'test2'})
83
137
  server.stop
84
138
  assert_equal 200, response.code
85
- assert_equal "test2", qs["test1"]
139
+ assert_equal 'test2', qs['test1']
86
140
  end
87
141
 
88
142
  it 'posts multi-part encoded data' do
89
143
  qs = {}
90
144
  app = proc do |req|
91
145
  qs = req.query
92
- [200, {}, "OK!"]
146
+ [200, {}, 'OK!']
93
147
  end
94
148
  server = TestServer.new(app)
95
149
  server.run
96
150
 
97
- response = HTTP::Client.post(server.root, files: {this: __FILE__}, query: {test1: "test2"})
151
+ response = HTTP::Client.post(server.root, files: {this: __FILE__}, query: {test1: 'test2'})
98
152
  server.stop
99
153
 
100
154
  assert_equal 200, response.code
101
- assert_equal "test2", qs["test1"]
155
+ assert_equal 'test2', qs['test1']
102
156
 
103
157
  data = IO.read(__FILE__)
104
- assert_equal data, qs["this"]
105
- assert_equal File.basename(__FILE__), qs["this"].filename # people should stop overloading / extending String!
158
+ assert_equal data, qs['this']
159
+ assert_equal File.basename(__FILE__), qs['this'].filename # people should stop overloading / extending String!
106
160
  end
107
161
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bharanee Rathna
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-08 00:00:00.000000000 Z
11
+ date: 2016-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mime-types