http-client 0.1.1 → 0.1.2

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