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 +4 -4
- data/CHANGELOG +6 -0
- data/README.md +42 -27
- data/lib/http/client.rb +129 -63
- data/test/test_request.rb +89 -35
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9e9eae81102b0be33c27dc85929a220ab8bfee5
|
4
|
+
data.tar.gz: 4a2f85ca306800e17f5ee29a459ff2747a70eacf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 770fd61b83f170d613ca39ee167fd652adbb88654e01b13f34fda61e68f93a038d44f8cd719e6327bbe6ba0ecd5cd4c6af94df90c65b5899ba332d3779ba548c
|
7
|
+
data.tar.gz: 2d96e1124de41b12e14ce29f6de8d9e78029a5b6ed70fb19d25781cc196f040e23a5c477363f01da49f448d624ae120a3825ff104f85b54bf7faa722952119bf
|
data/CHANGELOG
CHANGED
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://
|
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://
|
19
|
-
res = HTTP::Client.
|
20
|
-
|
21
|
-
|
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
|
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 =>
|
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 |
|
64
|
-
| ssl_verify | Integer | OpenSSL verification
|
65
|
-
| jar | HTTP::CookieJar | Optional cookie jar to use. Relies on HTTP::CookieJar from http-cookie gem. |
|
66
|
-
|
67
|
-
##
|
68
|
-
|
69
|
-
|
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.
|
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
|
-
|
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
|
-
|
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
|
35
|
-
# @param
|
36
|
-
# @param
|
37
|
-
# @
|
38
|
-
# @
|
39
|
-
# @
|
40
|
-
# @
|
41
|
-
# @
|
42
|
-
# @
|
43
|
-
# @
|
44
|
-
# @
|
45
|
-
# @
|
46
|
-
# @
|
47
|
-
# @
|
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!
|
57
|
-
|
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
|
-
@
|
81
|
-
@ssl_verify
|
82
|
-
@jar
|
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
|
-
|
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
|
-
|
101
|
-
|
102
|
-
|
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(
|
129
|
+
cookie = HTTP::Cookie.cookie_value(@jar.cookies(last_effective_uri))
|
105
130
|
if cookie && !cookie.empty?
|
106
|
-
|
131
|
+
redirect_delegate.add_field('Cookie', cookie)
|
107
132
|
end
|
108
133
|
|
109
|
-
response = request!(
|
110
|
-
@jar.parse(response['set-cookie'].to_s,
|
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,
|
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
|
-
|
119
|
-
case
|
147
|
+
uri = uri.kind_of?(URI) ? uri : URI.parse(uri)
|
148
|
+
case uri
|
120
149
|
when URI::HTTP, URI::HTTPS
|
121
|
-
|
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
|
128
|
-
klass
|
129
|
-
|
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
|
137
|
-
|
138
|
-
|
139
|
-
|
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
|
-
|
143
|
-
|
179
|
+
delegate = klass.new(uri, headers)
|
180
|
+
delegate.set_form_data(qs)
|
144
181
|
else
|
145
|
-
|
146
|
-
|
182
|
+
uri.query = URI.encode_www_form(qs)
|
183
|
+
delegate = klass.new(uri, headers)
|
147
184
|
end
|
148
185
|
else
|
149
|
-
|
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
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
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,
|
6
|
-
assert_raises(URI::InvalidURIError,
|
7
|
-
assert_raises(ArgumentError,
|
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,
|
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
|
-
|
18
|
-
query: {title:
|
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, {},
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
57
|
-
server.run
|
99
|
+
end
|
58
100
|
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
64
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
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, {},
|
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:
|
136
|
+
response = HTTP::Client.post(server.root, query: {test1: 'test2'})
|
83
137
|
server.stop
|
84
138
|
assert_equal 200, response.code
|
85
|
-
assert_equal
|
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, {},
|
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:
|
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
|
155
|
+
assert_equal 'test2', qs['test1']
|
102
156
|
|
103
157
|
data = IO.read(__FILE__)
|
104
|
-
assert_equal data, qs[
|
105
|
-
assert_equal File.basename(__FILE__), qs[
|
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.
|
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-
|
11
|
+
date: 2016-06-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mime-types
|