http 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -10
- data/CHANGES.md +13 -0
- data/Gemfile +1 -1
- data/README.md +32 -237
- data/http.gemspec +1 -1
- data/lib/http.rb +1 -1
- data/lib/http/chainable.rb +6 -7
- data/lib/http/client.rb +3 -5
- data/lib/http/connection.rb +19 -22
- data/lib/http/headers.rb +9 -8
- data/lib/http/headers/known.rb +1 -0
- data/lib/http/request.rb +18 -15
- data/lib/http/request/writer.rb +5 -7
- data/lib/http/response.rb +3 -3
- data/lib/http/response/body.rb +10 -3
- data/lib/http/response/parser.rb +1 -1
- data/lib/http/response/status.rb +1 -1
- data/lib/http/timeout/global.rb +4 -4
- data/lib/http/timeout/null.rb +5 -5
- data/lib/http/timeout/per_operation.rb +7 -17
- data/lib/http/uri.rb +1 -0
- data/lib/http/version.rb +2 -1
- data/spec/lib/http/client_spec.rb +3 -3
- data/spec/lib/http/headers_spec.rb +15 -12
- data/spec/lib/http/response/status_spec.rb +6 -6
- data/spec/lib/http/response_spec.rb +2 -2
- data/spec/lib/http_spec.rb +1 -1
- data/spec/regression_specs.rb +2 -2
- data/spec/spec_helper.rb +6 -4
- data/spec/support/servers/runner.rb +2 -2
- data/spec/support/ssl_helper.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce1cd065ce4c93b81a5a28a949354322222d0d78
|
4
|
+
data.tar.gz: e4b2d331cc30a7780425ec9248c14ba43fcab9ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7fe63ab93211bb553b5f5ec8b9d62f2a7279c0896dc30ff2ff6dc1afdda0c89efcf1193f4032232aec011f2cf77f613d75a77763dfa3ba656ce07e98b72976e0
|
7
|
+
data.tar.gz: 94cfd48b04617ab0966222097c2cf11c10c6567dcc89e7decea6dd2d927e9f199cb80f8609f759ecdfa38d57ad894def14c440367f27b0d06d3b5d2bb7b3cf98
|
data/.rubocop.yml
CHANGED
@@ -61,17 +61,8 @@ Style/HashSyntax:
|
|
61
61
|
Style/Lambda:
|
62
62
|
Enabled: false
|
63
63
|
|
64
|
-
Style/SingleSpaceBeforeFirstArg:
|
65
|
-
Enabled: false
|
66
|
-
|
67
64
|
Style/SpaceAroundOperators:
|
68
|
-
|
69
|
-
- "="
|
70
|
-
- "=>"
|
71
|
-
- "||"
|
72
|
-
- "||="
|
73
|
-
- "&&"
|
74
|
-
- "&&="
|
65
|
+
AllowForAlignment: true
|
75
66
|
|
76
67
|
Style/SpaceInsideHashLiteralBraces:
|
77
68
|
EnforcedStyle: no_space
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## 1.0.3 (2016-03-16)
|
2
|
+
|
3
|
+
* [#314](https://github.com/httprb/http/pull/314)
|
4
|
+
Validate charset before forcing encoding.
|
5
|
+
([@kylekyle])
|
6
|
+
|
7
|
+
|
8
|
+
* [#318](https://github.com/httprb/http/pull/318)
|
9
|
+
Remove redundant string allocations upon header names normalization.
|
10
|
+
([@ixti])
|
11
|
+
|
12
|
+
|
1
13
|
## 1.0.2 (2016-01-15)
|
2
14
|
|
3
15
|
* [#295](https://github.com/httprb/http/pull/295):
|
@@ -464,3 +476,4 @@ end
|
|
464
476
|
[@hundredwatt]: https://github.com/hundredwatt
|
465
477
|
[@jwinter]: https://github.com/jwinter
|
466
478
|
[@nerdrew]: https://github.com/nerdrew
|
479
|
+
[@kylekyle]: https://github.com/kylekyle
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -38,21 +38,21 @@ Top three reasons:
|
|
38
38
|
http.rb achieves the best performance of any Ruby HTTP library which
|
39
39
|
implements the HTTP protocol in Ruby instead of C:
|
40
40
|
|
41
|
-
| HTTP client |
|
42
|
-
|
43
|
-
| curb (persistent) | 2.
|
44
|
-
| em-http-request | 2.
|
45
|
-
| Typhoeus | 2.
|
46
|
-
| StreamlyFFI (persistent) | 2.
|
47
|
-
| http.rb (persistent) | 2.
|
48
|
-
| http.rb | 3.
|
49
|
-
| HTTParty | 3.
|
50
|
-
| Net::HTTP | 3.
|
51
|
-
| Net::HTTP (persistent) | 4.
|
52
|
-
| open-uri | 4.
|
53
|
-
| Excon (persistent) | 4.
|
54
|
-
| Excon | 4.
|
55
|
-
| RestClient | 26.
|
41
|
+
| HTTP client | Time | Implementation |
|
42
|
+
|--------------------------|--------|-----------------------|
|
43
|
+
| curb (persistent) | 2.519 | libcurl wrapper |
|
44
|
+
| em-http-request | 2.731 | EM + http_parser.rb |
|
45
|
+
| Typhoeus | 2.851 | libcurl wrapper |
|
46
|
+
| StreamlyFFI (persistent) | 2.853 | libcurl wrapper |
|
47
|
+
| http.rb (persistent) | 2.970 | Ruby + http_parser.rb |
|
48
|
+
| http.rb | 3.588 | Ruby + http_parser.rb |
|
49
|
+
| HTTParty | 3.931 | Net::HTTP wrapper |
|
50
|
+
| Net::HTTP | 3.959 | Pure Ruby |
|
51
|
+
| Net::HTTP (persistent) | 4.043 | Pure Ruby |
|
52
|
+
| open-uri | 4.479 | Net::HTTP wrapper |
|
53
|
+
| Excon (persistent) | 4.618 | Pure Ruby |
|
54
|
+
| Excon | 4.701 | Pure Ruby |
|
55
|
+
| RestClient | 26.838 | Net::HTTP wrapper |
|
56
56
|
|
57
57
|
Benchmarks performed using excon's benchmarking tool
|
58
58
|
|
@@ -79,20 +79,24 @@ https://github.com/httprb/http/issues
|
|
79
79
|
## Installation
|
80
80
|
|
81
81
|
Add this line to your application's Gemfile:
|
82
|
-
|
83
|
-
|
82
|
+
```ruby
|
83
|
+
gem "http"
|
84
|
+
```
|
84
85
|
|
85
86
|
And then execute:
|
86
|
-
|
87
|
-
|
87
|
+
```bash
|
88
|
+
$ bundle
|
89
|
+
```
|
88
90
|
|
89
91
|
Or install it yourself as:
|
90
|
-
|
91
|
-
|
92
|
+
```bash
|
93
|
+
$ gem install http
|
94
|
+
```
|
92
95
|
|
93
96
|
Inside of your Ruby program do:
|
94
|
-
|
95
|
-
|
97
|
+
```ruby
|
98
|
+
require "http"
|
99
|
+
```
|
96
100
|
|
97
101
|
...to pull it in as a dependency.
|
98
102
|
|
@@ -102,13 +106,14 @@ Inside of your Ruby program do:
|
|
102
106
|
[Please see the http.rb wiki](https://github.com/httprb/http/wiki)
|
103
107
|
for more detailed documentation and usage notes.
|
104
108
|
|
109
|
+
The following API documentation is also available:
|
105
110
|
|
106
|
-
|
111
|
+
* [YARD API documentation](http://www.rubydoc.info/gems/http/frames)
|
112
|
+
* [Chainable module (all chainable methods)](http://www.rubydoc.info/gems/http/HTTP/Chainable)
|
107
113
|
|
108
|
-
|
114
|
+
### Basic Usage
|
109
115
|
|
110
|
-
|
111
|
-
### GET requests
|
116
|
+
Here's some simple examples to get you started:
|
112
117
|
|
113
118
|
```ruby
|
114
119
|
>> HTTP.get("https://github.com").to_s
|
@@ -141,216 +146,6 @@ The response body can be streamed with `HTTP::Response::Body#readpartial`:
|
|
141
146
|
In practice you'll want to bind the HTTP::Response::Body to a local variable (e.g.
|
142
147
|
"body") and call readpartial on it repeatedly until it returns `nil`.
|
143
148
|
|
144
|
-
|
145
|
-
### POST requests
|
146
|
-
|
147
|
-
Making POST requests is simple too. Want to POST a form?
|
148
|
-
|
149
|
-
```ruby
|
150
|
-
HTTP.post("http://example.com/resource", :form => {:foo => "42"})
|
151
|
-
```
|
152
|
-
Making GET requests with query string parameters is as simple.
|
153
|
-
|
154
|
-
```ruby
|
155
|
-
HTTP.get("http://example.com/resource", :params => {:foo => "bar"})
|
156
|
-
```
|
157
|
-
|
158
|
-
Want to POST with a specific body, JSON for instance?
|
159
|
-
|
160
|
-
```ruby
|
161
|
-
HTTP.post("http://example.com/resource", :json => { :foo => "42" })
|
162
|
-
```
|
163
|
-
|
164
|
-
Or just a plain body?
|
165
|
-
|
166
|
-
```ruby
|
167
|
-
HTTP.post("http://example.com/resource", :body => "foo=42&bar=baz")
|
168
|
-
```
|
169
|
-
|
170
|
-
Posting a file?
|
171
|
-
|
172
|
-
``` ruby
|
173
|
-
HTTP.post("http://examplc.com/resource", :form => {
|
174
|
-
:username => "ixti",
|
175
|
-
:avatar => HTTP::FormData::File.new("/home/ixit/avatar.png")
|
176
|
-
})
|
177
|
-
```
|
178
|
-
|
179
|
-
It's easy!
|
180
|
-
|
181
|
-
|
182
|
-
### Proxy Support
|
183
|
-
|
184
|
-
Making request behind proxy is as simple as making them directly. Just specify
|
185
|
-
hostname (or IP address) of your proxy server and its port, and here you go:
|
186
|
-
|
187
|
-
```ruby
|
188
|
-
HTTP.via("proxy-hostname.local", 8080)
|
189
|
-
.get("http://example.com/resource")
|
190
|
-
```
|
191
|
-
|
192
|
-
Proxy needs authentication? No problem:
|
193
|
-
|
194
|
-
```ruby
|
195
|
-
HTTP.via("proxy-hostname.local", 8080, "username", "password")
|
196
|
-
.get("http://example.com/resource")
|
197
|
-
```
|
198
|
-
|
199
|
-
|
200
|
-
### Adding Headers
|
201
|
-
|
202
|
-
The HTTP gem uses the concept of chaining to simplify requests. Let's say
|
203
|
-
you want to get the latest commit of this library from GitHub in JSON format.
|
204
|
-
One way we could do this is by tacking a filename on the end of the URL:
|
205
|
-
|
206
|
-
```ruby
|
207
|
-
HTTP.get("https://github.com/httprb/http/commit/HEAD.json")
|
208
|
-
```
|
209
|
-
|
210
|
-
The GitHub API happens to support this approach, but really this is a bit of a
|
211
|
-
hack that makes it easy for people typing URLs into the address bars of
|
212
|
-
browsers to perform the act of content negotiation. Since we have access to
|
213
|
-
the full, raw power of HTTP, we can perform content negotiation the way HTTP
|
214
|
-
intends us to, by using the Accept header:
|
215
|
-
|
216
|
-
```ruby
|
217
|
-
HTTP.headers(:accept => "application/json")
|
218
|
-
.get("https://github.com/httprb/http/commit/HEAD")
|
219
|
-
```
|
220
|
-
|
221
|
-
This requests JSON from GitHub. GitHub is smart enough to understand our
|
222
|
-
request and returns a response with `Content-Type: application/json`.
|
223
|
-
|
224
|
-
Shorter alias exists for `HTTP.headers`:
|
225
|
-
|
226
|
-
```ruby
|
227
|
-
HTTP[:accept => "application/json"]
|
228
|
-
.get("https://github.com/httprb/http/commit/HEAD")
|
229
|
-
```
|
230
|
-
|
231
|
-
|
232
|
-
### Authorization Header
|
233
|
-
|
234
|
-
With [HTTP Basic Authentication](http://tools.ietf.org/html/rfc2617) using
|
235
|
-
a username and password:
|
236
|
-
|
237
|
-
```ruby
|
238
|
-
HTTP.basic_auth(:user => "user", :pass => "pass")
|
239
|
-
# <HTTP::Headers {"Authorization"=>"Basic dXNlcjpwYXNz"}>
|
240
|
-
```
|
241
|
-
|
242
|
-
Or with plain as-is value:
|
243
|
-
|
244
|
-
```ruby
|
245
|
-
HTTP.auth("Bearer VGhlIEhUVFAgR2VtLCBST0NLUw")
|
246
|
-
# <HTTP::Headers {"Authorization"=>"Bearer VGhlIEhUVFAgR2VtLCBST0NLUw"}>
|
247
|
-
```
|
248
|
-
|
249
|
-
And Chain all together!
|
250
|
-
|
251
|
-
```ruby
|
252
|
-
HTTP.basic_auth(:user => "user", :pass => "pass")
|
253
|
-
.headers("Cookie" => "9wq3w")
|
254
|
-
.get("https://example.com")
|
255
|
-
```
|
256
|
-
|
257
|
-
|
258
|
-
### Content Negotiation
|
259
|
-
|
260
|
-
As important a concept as content negotiation is to HTTP, it sure should be easy,
|
261
|
-
right? But usually it's not, and so we end up adding ".json" onto the ends of
|
262
|
-
our URLs because the existing mechanisms make it too hard. It should be easy:
|
263
|
-
|
264
|
-
```ruby
|
265
|
-
HTTP.accept(:json).get("https://github.com/httprb/http/commit/HEAD")
|
266
|
-
```
|
267
|
-
|
268
|
-
This adds the appropriate Accept header for retrieving a JSON response for the
|
269
|
-
given resource.
|
270
|
-
|
271
|
-
|
272
|
-
### Reuse HTTP connection: HTTP Keep-Alive
|
273
|
-
|
274
|
-
If you need to make many successive requests against the same host,
|
275
|
-
you can create client with persistent connection to the host:
|
276
|
-
|
277
|
-
``` ruby
|
278
|
-
begin
|
279
|
-
# create HTTP client with persistent connection to api.icndb.com:
|
280
|
-
http = HTTP.persistent "http://api.icndb.com"
|
281
|
-
|
282
|
-
# issue multiple requests using same connection:
|
283
|
-
jokes = 100.times.map { http.get("/jokes/random").to_s }
|
284
|
-
ensure
|
285
|
-
# close underlying connection when you don't need it anymore
|
286
|
-
http.close if http
|
287
|
-
end
|
288
|
-
|
289
|
-
```
|
290
|
-
|
291
|
-
If the optional code block is given, it will be passed the client with
|
292
|
-
persistent connection to the host as an argument and `client.close` will be
|
293
|
-
automatically called when the block terminates.
|
294
|
-
The value of the block will be returned:
|
295
|
-
|
296
|
-
``` ruby
|
297
|
-
jokes = HTTP.persistent "http://api.icndb.com" do |http|
|
298
|
-
100.times.map { http.get("/jokes/random").to_s }
|
299
|
-
end
|
300
|
-
```
|
301
|
-
|
302
|
-
##### NOTICE
|
303
|
-
|
304
|
-
You must consume response before sending next request via persistent connection.
|
305
|
-
That means you need to call `#to_s`, `#parse` or `#flush` on response object.
|
306
|
-
In the example above we used `http.get("/jokes/random").to_s` to get response
|
307
|
-
bodies. That works perfectly fine, because `#to_s` reads off the response.
|
308
|
-
|
309
|
-
Sometimes you don't need response body, or need whole response object to
|
310
|
-
access it's status, headers etc instead. You can either call `#to_s` to
|
311
|
-
make sure response was flushed and then use response object itself, or use
|
312
|
-
`#flush` (syntax sugar for `#tap(&:to_s)` that will do that for you:
|
313
|
-
|
314
|
-
|
315
|
-
``` ruby
|
316
|
-
contents = HTTP.persistent "http://en.wikipedia.org" do |http|
|
317
|
-
%w(Hypertext_Transfer_Protocol Git GitHub Linux Hurd).map do
|
318
|
-
http.get("/wiki/#{target}").flush
|
319
|
-
end
|
320
|
-
end
|
321
|
-
```
|
322
|
-
|
323
|
-
|
324
|
-
### Timeouts
|
325
|
-
|
326
|
-
By default, HTTP does not timeout on a request. You can enable per operation
|
327
|
-
(each read/write/connect call) or global (sum of all read/write/connect calls).
|
328
|
-
|
329
|
-
Per operation timeouts are what `Net::HTTP` and the majority of HTTP clients do:
|
330
|
-
|
331
|
-
``` ruby
|
332
|
-
HTTP.timeout(:per_operation, :write => 2, :connect => 5, :read => 10)
|
333
|
-
.get "http://example.com"
|
334
|
-
|
335
|
-
# For convinience, you can omit timeout type in this case. So following has
|
336
|
-
# same result as the above:
|
337
|
-
|
338
|
-
HTTP.timeout(:write => 2, :connect => 5, :read => 10).get "http://example.com"
|
339
|
-
```
|
340
|
-
|
341
|
-
Global timeouts let you set an upper bound of how long a request can take,
|
342
|
-
without having to rely on `Timeout.timeout`:
|
343
|
-
|
344
|
-
``` ruby
|
345
|
-
HTTP.timeout(:global, :write => 1, :connect => 1, :read => 1)
|
346
|
-
.get "http://example.com"
|
347
|
-
```
|
348
|
-
|
349
|
-
Uses a timeout of 3 seconds, for the entire `get` call.
|
350
|
-
|
351
|
-
*Warning!* You cannot use Celluloid::IO with timeouts currently.
|
352
|
-
|
353
|
-
|
354
149
|
## Supported Ruby Versions
|
355
150
|
|
356
151
|
This library aims to support and is [tested against][travis] the following Ruby
|
data/http.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |gem|
|
|
13
13
|
DESCRIPTION
|
14
14
|
|
15
15
|
gem.summary = "HTTP should be easy"
|
16
|
-
gem.homepage = "https://github.com/httprb/http
|
16
|
+
gem.homepage = "https://github.com/httprb/http"
|
17
17
|
gem.licenses = ["MIT"]
|
18
18
|
|
19
19
|
gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
data/lib/http.rb
CHANGED
data/lib/http/chainable.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "base64"
|
2
3
|
|
3
4
|
require "http/headers"
|
@@ -153,13 +154,11 @@ module HTTP
|
|
153
154
|
proxy_hash[:proxy_username] = proxy[2] if proxy[2].is_a?(String)
|
154
155
|
proxy_hash[:proxy_password] = proxy[3] if proxy[3].is_a?(String)
|
155
156
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
fail(RequestError, "invalid HTTP proxy: #{proxy_hash}")
|
160
|
-
end
|
157
|
+
fail(RequestError, "invalid HTTP proxy: #{proxy_hash}") unless [2, 4].include?(proxy_hash.keys.size)
|
158
|
+
|
159
|
+
branch default_options.with_proxy(proxy_hash)
|
161
160
|
end
|
162
|
-
|
161
|
+
alias through via
|
163
162
|
|
164
163
|
# Make client follow redirects.
|
165
164
|
# @param opts
|
@@ -206,7 +205,7 @@ module HTTP
|
|
206
205
|
user = opts.fetch :user
|
207
206
|
pass = opts.fetch :pass
|
208
207
|
|
209
|
-
auth("Basic "
|
208
|
+
auth("Basic " + Base64.strict_encode64("#{user}:#{pass}"))
|
210
209
|
end
|
211
210
|
|
212
211
|
# Get options for HTTP
|
data/lib/http/client.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "forwardable"
|
2
3
|
|
3
4
|
require "http/form_data"
|
@@ -137,13 +138,10 @@ module HTTP
|
|
137
138
|
headers = opts.headers
|
138
139
|
|
139
140
|
# Tell the server to keep the conn open
|
140
|
-
|
141
|
-
headers[Headers::CONNECTION] = KEEP_ALIVE
|
142
|
-
else
|
143
|
-
headers[Headers::CONNECTION] = CLOSE
|
144
|
-
end
|
141
|
+
headers[Headers::CONNECTION] = default_options.persistent? ? KEEP_ALIVE : CLOSE
|
145
142
|
|
146
143
|
cookies = opts.cookies.values
|
144
|
+
|
147
145
|
unless cookies.empty?
|
148
146
|
cookies = opts.headers.get(Headers::COOKIE).concat(cookies).join("; ")
|
149
147
|
headers[Headers::COOKIE] = cookies
|
data/lib/http/connection.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "forwardable"
|
2
3
|
|
3
4
|
require "http/client"
|
@@ -80,13 +81,8 @@ module HTTP
|
|
80
81
|
def readpartial(size = BUFFER_SIZE)
|
81
82
|
return unless @pending_response
|
82
83
|
|
83
|
-
|
84
|
-
|
85
|
-
else
|
86
|
-
finished = @parser.finished?
|
87
|
-
end
|
88
|
-
|
89
|
-
chunk = @parser.chunk
|
84
|
+
finished = (read_more(size) == :eof) || @parser.finished?
|
85
|
+
chunk = @parser.chunk
|
90
86
|
|
91
87
|
finish_response if finished
|
92
88
|
|
@@ -100,8 +96,8 @@ module HTTP
|
|
100
96
|
if read_more(BUFFER_SIZE) == :eof
|
101
97
|
fail EOFError unless @parser.headers?
|
102
98
|
break
|
103
|
-
|
104
|
-
break
|
99
|
+
elsif @parser.headers?
|
100
|
+
break
|
105
101
|
end
|
106
102
|
end
|
107
103
|
|
@@ -169,18 +165,18 @@ module HTTP
|
|
169
165
|
|
170
166
|
req.connect_using_proxy @socket
|
171
167
|
|
172
|
-
@pending_request
|
168
|
+
@pending_request = false
|
173
169
|
@pending_response = true
|
174
170
|
|
175
171
|
read_headers!
|
176
172
|
|
177
|
-
if @parser.status_code
|
178
|
-
@
|
179
|
-
@pending_response = false
|
173
|
+
if @parser.status_code != 200
|
174
|
+
@failed_proxy_connect = true
|
180
175
|
return
|
181
176
|
end
|
182
177
|
|
183
|
-
@
|
178
|
+
@parser.reset
|
179
|
+
@pending_response = false
|
184
180
|
end
|
185
181
|
|
186
182
|
# Resets expiration of persistent connection.
|
@@ -195,14 +191,15 @@ module HTTP
|
|
195
191
|
def set_keep_alive
|
196
192
|
return @keep_alive = false unless @persistent
|
197
193
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
194
|
+
@keep_alive =
|
195
|
+
case @parser.http_version
|
196
|
+
when HTTP_1_0 # HTTP/1.0 requires opt in for Keep Alive
|
197
|
+
@parser.headers[Headers::CONNECTION] == Client::KEEP_ALIVE
|
198
|
+
when HTTP_1_1 # HTTP/1.1 is opt-out
|
199
|
+
@parser.headers[Headers::CONNECTION] != Client::CLOSE
|
200
|
+
else # Anything else we assume doesn't supportit
|
201
|
+
false
|
202
|
+
end
|
206
203
|
end
|
207
204
|
|
208
205
|
# Feeds some more data into parser
|
data/lib/http/headers.rb
CHANGED
@@ -11,11 +11,11 @@ module HTTP
|
|
11
11
|
include Enumerable
|
12
12
|
|
13
13
|
# Matches HTTP header names when in "Canonical-Http-Format"
|
14
|
-
|
14
|
+
CANONICAL_NAME_RE = /^[A-Z][a-z]*(?:-[A-Z][a-z]*)*$/
|
15
15
|
|
16
16
|
# Matches valid header field name according to RFC.
|
17
17
|
# @see http://tools.ietf.org/html/rfc7230#section-3.2
|
18
|
-
|
18
|
+
COMPLIANT_NAME_RE = /^[A-Za-z0-9!#\$%&'*+\-.^_`|~]+$/
|
19
19
|
|
20
20
|
# Class constructor.
|
21
21
|
def initialize
|
@@ -30,7 +30,7 @@ module HTTP
|
|
30
30
|
delete(name)
|
31
31
|
add(name, value)
|
32
32
|
end
|
33
|
-
|
33
|
+
alias []= set
|
34
34
|
|
35
35
|
# Removes header.
|
36
36
|
#
|
@@ -80,7 +80,7 @@ module HTTP
|
|
80
80
|
def to_h
|
81
81
|
Hash[keys.map { |k| [k, self[k]] }]
|
82
82
|
end
|
83
|
-
|
83
|
+
alias to_hash to_h
|
84
84
|
|
85
85
|
# Returns headers key/value pairs.
|
86
86
|
#
|
@@ -179,7 +179,7 @@ module HTTP
|
|
179
179
|
object.each { |k, v| headers.add k, v }
|
180
180
|
headers
|
181
181
|
end
|
182
|
-
|
182
|
+
alias [] coerce
|
183
183
|
end
|
184
184
|
|
185
185
|
private
|
@@ -191,10 +191,11 @@ module HTTP
|
|
191
191
|
# match {HEADER_NAME_RE}
|
192
192
|
# @return [String] canonical HTTP header name
|
193
193
|
def normalize_header(name)
|
194
|
-
|
195
|
-
normalized ||= name.split(/[\-_]/).map(&:capitalize).join("-")
|
194
|
+
return name if name =~ CANONICAL_NAME_RE
|
196
195
|
|
197
|
-
|
196
|
+
normalized = name.split(/[\-_]/).each(&:capitalize!).join("-")
|
197
|
+
|
198
|
+
return normalized if normalized =~ COMPLIANT_NAME_RE
|
198
199
|
|
199
200
|
fail InvalidHeaderNameError, "Invalid HTTP header field name: #{name.inspect}"
|
200
201
|
end
|
data/lib/http/headers/known.rb
CHANGED
data/lib/http/request.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "forwardable"
|
2
3
|
require "base64"
|
3
4
|
require "time"
|
@@ -23,26 +24,28 @@ module HTTP
|
|
23
24
|
# Default User-Agent header value
|
24
25
|
USER_AGENT = "http.rb/#{HTTP::VERSION}".freeze
|
25
26
|
|
26
|
-
|
27
|
-
|
27
|
+
METHODS = [
|
28
|
+
# RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1
|
29
|
+
:options, :get, :head, :post, :put, :delete, :trace, :connect,
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
+
# RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV
|
32
|
+
:propfind, :proppatch, :mkcol, :copy, :move, :lock, :unlock,
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
+
# RFC 3648: WebDAV Ordered Collections Protocol
|
35
|
+
:orderpatch,
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
+
# RFC 3744: WebDAV Access Control Protocol
|
38
|
+
:acl,
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
+
# draft-dusseault-http-patch: PATCH Method for HTTP
|
41
|
+
:patch,
|
40
42
|
|
41
|
-
|
42
|
-
|
43
|
+
# draft-reschke-webdav-search: WebDAV Search
|
44
|
+
:search
|
45
|
+
].freeze
|
43
46
|
|
44
47
|
# Allowed schemes
|
45
|
-
SCHEMES = [:http, :https, :ws, :wss]
|
48
|
+
SCHEMES = [:http, :https, :ws, :wss].freeze
|
46
49
|
|
47
50
|
# Default ports of supported schemes
|
48
51
|
PORTS = {
|
@@ -50,7 +53,7 @@ module HTTP
|
|
50
53
|
:https => 443,
|
51
54
|
:ws => 80,
|
52
55
|
:wss => 443
|
53
|
-
}
|
56
|
+
}.freeze
|
54
57
|
|
55
58
|
# Method is given as a lowercase symbol e.g. :get, :post
|
56
59
|
attr_reader :verb
|
@@ -71,7 +74,7 @@ module HTTP
|
|
71
74
|
# @option opts [String] :body
|
72
75
|
def initialize(opts)
|
73
76
|
@verb = opts.fetch(:verb).to_s.downcase.to_sym
|
74
|
-
@uri = normalize_uri(opts.fetch
|
77
|
+
@uri = normalize_uri(opts.fetch(:uri))
|
75
78
|
@scheme = @uri.scheme.to_s.downcase.to_sym if @uri.scheme
|
76
79
|
|
77
80
|
fail(UnsupportedMethodError, "unknown method: #{verb}") unless METHODS.include?(@verb)
|
data/lib/http/request/writer.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "http/headers"
|
2
3
|
|
3
4
|
module HTTP
|
@@ -16,7 +17,7 @@ module HTTP
|
|
16
17
|
CHUNKED_END = "#{ZERO}#{CRLF}#{CRLF}".freeze
|
17
18
|
|
18
19
|
# Types valid to be used as body source
|
19
|
-
VALID_BODY_TYPES = [String, NilClass, Enumerable]
|
20
|
+
VALID_BODY_TYPES = [String, NilClass, Enumerable].freeze
|
20
21
|
|
21
22
|
def initialize(socket, body, headers, headline)
|
22
23
|
@body = body
|
@@ -62,7 +63,7 @@ module HTTP
|
|
62
63
|
def join_headers
|
63
64
|
# join the headers array with crlfs, stick two on the end because
|
64
65
|
# that ends the request header
|
65
|
-
@request_header.join(CRLF) +
|
66
|
+
@request_header.join(CRLF) + CRLF * 2
|
66
67
|
end
|
67
68
|
|
68
69
|
def send_request
|
@@ -94,11 +95,8 @@ module HTTP
|
|
94
95
|
def write(data)
|
95
96
|
until data.empty?
|
96
97
|
length = @socket.write(data)
|
97
|
-
|
98
|
-
|
99
|
-
else
|
100
|
-
break
|
101
|
-
end
|
98
|
+
break unless data.length > length
|
99
|
+
data = data[length..-1]
|
102
100
|
end
|
103
101
|
end
|
104
102
|
|
data/lib/http/response.rb
CHANGED
@@ -34,8 +34,8 @@ module HTTP
|
|
34
34
|
# @option opts [String] :uri
|
35
35
|
def initialize(opts)
|
36
36
|
@version = opts.fetch(:version)
|
37
|
-
@uri = HTTP::URI.parse(opts.fetch
|
38
|
-
@status = HTTP::Response::Status.new(opts.fetch
|
37
|
+
@uri = HTTP::URI.parse(opts.fetch(:uri)) if opts.include? :uri
|
38
|
+
@status = HTTP::Response::Status.new(opts.fetch(:status))
|
39
39
|
@headers = HTTP::Headers.coerce(opts[:headers] || {})
|
40
40
|
|
41
41
|
if opts.include?(:connection)
|
@@ -59,7 +59,7 @@ module HTTP
|
|
59
59
|
# @!method to_s
|
60
60
|
# (see HTTP::Response::Body#to_s)
|
61
61
|
def_delegator :body, :to_s
|
62
|
-
|
62
|
+
alias to_str to_s
|
63
63
|
|
64
64
|
# @!method readpartial
|
65
65
|
# (see HTTP::Response::Body#readpartial)
|
data/lib/http/response/body.rb
CHANGED
@@ -35,11 +35,18 @@ module HTTP
|
|
35
35
|
|
36
36
|
fail StateError, "body is being streamed" unless @streaming.nil?
|
37
37
|
|
38
|
+
# see issue 312
|
39
|
+
begin
|
40
|
+
encoding = Encoding.find @encoding
|
41
|
+
rescue ArgumentError
|
42
|
+
encoding = Encoding::BINARY
|
43
|
+
end
|
44
|
+
|
38
45
|
begin
|
39
46
|
@streaming = false
|
40
|
-
@contents = "".force_encoding(
|
47
|
+
@contents = "".force_encoding(encoding)
|
41
48
|
while (chunk = @client.readpartial)
|
42
|
-
@contents << chunk.force_encoding(
|
49
|
+
@contents << chunk.force_encoding(encoding)
|
43
50
|
end
|
44
51
|
rescue
|
45
52
|
@contents = nil
|
@@ -48,7 +55,7 @@ module HTTP
|
|
48
55
|
|
49
56
|
@contents
|
50
57
|
end
|
51
|
-
|
58
|
+
alias to_str to_s
|
52
59
|
|
53
60
|
# Assert that the body is actively being streamed
|
54
61
|
def stream!
|
data/lib/http/response/parser.rb
CHANGED
data/lib/http/response/status.rb
CHANGED
data/lib/http/timeout/global.rb
CHANGED
@@ -32,13 +32,13 @@ module HTTP
|
|
32
32
|
reset_timer
|
33
33
|
|
34
34
|
begin
|
35
|
-
socket.connect_nonblock
|
35
|
+
@socket.connect_nonblock
|
36
36
|
rescue IO::WaitReadable
|
37
|
-
IO.select([socket], nil, nil, time_left)
|
37
|
+
IO.select([@socket], nil, nil, time_left)
|
38
38
|
log_time
|
39
39
|
retry
|
40
40
|
rescue IO::WaitWritable
|
41
|
-
IO.select(nil, [socket], nil, time_left)
|
41
|
+
IO.select(nil, [@socket], nil, time_left)
|
42
42
|
log_time
|
43
43
|
retry
|
44
44
|
end
|
@@ -54,7 +54,7 @@ module HTTP
|
|
54
54
|
perform_io { write_nonblock(data) }
|
55
55
|
end
|
56
56
|
|
57
|
-
|
57
|
+
alias << write
|
58
58
|
|
59
59
|
private
|
60
60
|
|
data/lib/http/timeout/null.rb
CHANGED
@@ -48,7 +48,7 @@ module HTTP
|
|
48
48
|
def write(data)
|
49
49
|
@socket.write(data)
|
50
50
|
end
|
51
|
-
|
51
|
+
alias << write
|
52
52
|
|
53
53
|
# These cops can be re-eanbled after we go Ruby 2.0+ only
|
54
54
|
# rubocop:disable Lint/UselessAccessModifier, Metrics/BlockNesting
|
@@ -60,7 +60,7 @@ module HTTP
|
|
60
60
|
def rescue_readable
|
61
61
|
yield
|
62
62
|
rescue IO::WaitReadable
|
63
|
-
retry if IO.select([socket], nil, nil, read_timeout)
|
63
|
+
retry if IO.select([@socket], nil, nil, read_timeout)
|
64
64
|
raise TimeoutError, "Read timed out after #{read_timeout} seconds"
|
65
65
|
end
|
66
66
|
|
@@ -68,7 +68,7 @@ module HTTP
|
|
68
68
|
def rescue_writable
|
69
69
|
yield
|
70
70
|
rescue IO::WaitWritable
|
71
|
-
retry if IO.select(nil, [socket], nil, write_timeout)
|
71
|
+
retry if IO.select(nil, [@socket], nil, write_timeout)
|
72
72
|
raise TimeoutError, "Write timed out after #{write_timeout} seconds"
|
73
73
|
end
|
74
74
|
else
|
@@ -78,7 +78,7 @@ module HTTP
|
|
78
78
|
def rescue_readable
|
79
79
|
yield
|
80
80
|
rescue IO::WaitReadable
|
81
|
-
retry if socket.to_io.wait_readable(read_timeout)
|
81
|
+
retry if @socket.to_io.wait_readable(read_timeout)
|
82
82
|
raise TimeoutError, "Read timed out after #{read_timeout} seconds"
|
83
83
|
end
|
84
84
|
|
@@ -86,7 +86,7 @@ module HTTP
|
|
86
86
|
def rescue_writable
|
87
87
|
yield
|
88
88
|
rescue IO::WaitWritable
|
89
|
-
retry if socket.to_io.wait_writable(write_timeout)
|
89
|
+
retry if @socket.to_io.wait_writable(write_timeout)
|
90
90
|
raise TimeoutError, "Write timed out after #{write_timeout} seconds"
|
91
91
|
end
|
92
92
|
end
|
@@ -39,7 +39,7 @@ module HTTP
|
|
39
39
|
# Read data from the socket
|
40
40
|
def readpartial(size)
|
41
41
|
rescue_readable do
|
42
|
-
socket.read_nonblock(size)
|
42
|
+
@socket.read_nonblock(size)
|
43
43
|
end
|
44
44
|
rescue EOFError
|
45
45
|
:eof
|
@@ -48,7 +48,7 @@ module HTTP
|
|
48
48
|
# Write data to the socket
|
49
49
|
def write(data)
|
50
50
|
rescue_writable do
|
51
|
-
socket.write_nonblock(data)
|
51
|
+
@socket.write_nonblock(data)
|
52
52
|
end
|
53
53
|
rescue EOFError
|
54
54
|
:eof
|
@@ -59,19 +59,14 @@ module HTTP
|
|
59
59
|
# Read data from the socket
|
60
60
|
def readpartial(size)
|
61
61
|
loop do
|
62
|
-
|
63
|
-
# we explicitly specify `:exception => false`
|
64
|
-
result = rescue_readable do
|
65
|
-
socket.read_nonblock(size, :exception => false)
|
66
|
-
end
|
67
|
-
|
62
|
+
result = @socket.read_nonblock(size, :exception => false)
|
68
63
|
if result.nil?
|
69
64
|
return :eof
|
70
65
|
elsif result != :wait_readable
|
71
66
|
return result
|
72
67
|
end
|
73
68
|
|
74
|
-
unless socket.to_io.wait_readable(read_timeout)
|
69
|
+
unless @socket.to_io.wait_readable(read_timeout)
|
75
70
|
fail TimeoutError, "Read timed out after #{read_timeout} seconds"
|
76
71
|
end
|
77
72
|
end
|
@@ -80,16 +75,11 @@ module HTTP
|
|
80
75
|
# Write data to the socket
|
81
76
|
def write(data)
|
82
77
|
loop do
|
83
|
-
|
84
|
-
# we explicitly specify `:exception => false`
|
85
|
-
result = rescue_writable do
|
86
|
-
socket.write_nonblock(data, :exception => false)
|
87
|
-
end
|
88
|
-
|
78
|
+
result = @socket.write_nonblock(data, :exception => false)
|
89
79
|
return result unless result == :wait_writable
|
90
80
|
|
91
|
-
unless socket.to_io.wait_writable(write_timeout)
|
92
|
-
fail TimeoutError, "
|
81
|
+
unless @socket.to_io.wait_writable(write_timeout)
|
82
|
+
fail TimeoutError, "Write timed out after #{write_timeout} seconds"
|
93
83
|
end
|
94
84
|
end
|
95
85
|
end
|
data/lib/http/uri.rb
CHANGED
data/lib/http/version.rb
CHANGED
@@ -110,7 +110,7 @@ RSpec.describe HTTP::Client do
|
|
110
110
|
|
111
111
|
it "accepts params within the provided URL" do
|
112
112
|
expect(HTTP::Request).to receive(:new) do |opts|
|
113
|
-
expect(CGI.parse
|
113
|
+
expect(CGI.parse(opts[:uri].query)).to eq("foo" => %w(bar))
|
114
114
|
end
|
115
115
|
|
116
116
|
client.get("http://example.com/?foo=bar")
|
@@ -118,7 +118,7 @@ RSpec.describe HTTP::Client do
|
|
118
118
|
|
119
119
|
it "combines GET params from the URI with the passed in params" do
|
120
120
|
expect(HTTP::Request).to receive(:new) do |opts|
|
121
|
-
expect(CGI.parse
|
121
|
+
expect(CGI.parse(opts[:uri].query)).to eq("foo" => %w(bar), "baz" => %w(quux))
|
122
122
|
end
|
123
123
|
|
124
124
|
client.get("http://example.com/?foo=bar", :params => {:baz => "quux"})
|
@@ -142,7 +142,7 @@ RSpec.describe HTTP::Client do
|
|
142
142
|
|
143
143
|
it "does not corrupts index-less arrays" do
|
144
144
|
expect(HTTP::Request).to receive(:new) do |opts|
|
145
|
-
expect(CGI.parse
|
145
|
+
expect(CGI.parse(opts[:uri].query)).to eq "a[]" => %w(b c), "d" => %w(e)
|
146
146
|
end
|
147
147
|
|
148
148
|
client.get("http://example.com/?a[]=b&a[]=c", :params => {:d => "e"})
|
@@ -111,7 +111,7 @@ RSpec.describe HTTP::Headers do
|
|
111
111
|
end
|
112
112
|
|
113
113
|
it "fails with empty header name" do
|
114
|
-
expect { headers.add
|
114
|
+
expect { headers.add("", "foobar") }.
|
115
115
|
to raise_error HTTP::InvalidHeaderNameError
|
116
116
|
end
|
117
117
|
|
@@ -122,29 +122,29 @@ RSpec.describe HTTP::Headers do
|
|
122
122
|
end
|
123
123
|
|
124
124
|
describe "#get" do
|
125
|
-
before { headers.set
|
125
|
+
before { headers.set("Content-Type", "application/json") }
|
126
126
|
|
127
127
|
it "returns array of associated values" do
|
128
|
-
expect(headers.get
|
128
|
+
expect(headers.get("Content-Type")).to eq %w(application/json)
|
129
129
|
end
|
130
130
|
|
131
131
|
it "normalizes header name" do
|
132
|
-
expect(headers.get
|
132
|
+
expect(headers.get(:content_type)).to eq %w(application/json)
|
133
133
|
end
|
134
134
|
|
135
135
|
context "when header does not exists" do
|
136
136
|
it "returns empty array" do
|
137
|
-
expect(headers.get
|
137
|
+
expect(headers.get(:accept)).to eq []
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
141
141
|
it "fails with empty header name" do
|
142
|
-
expect { headers.get
|
142
|
+
expect { headers.get("") }.
|
143
143
|
to raise_error HTTP::InvalidHeaderNameError
|
144
144
|
end
|
145
145
|
|
146
146
|
it "fails with invalid header name" do
|
147
|
-
expect { headers.get
|
147
|
+
expect { headers.get("foo bar") }.
|
148
148
|
to raise_error HTTP::InvalidHeaderNameError
|
149
149
|
end
|
150
150
|
end
|
@@ -453,15 +453,18 @@ RSpec.describe HTTP::Headers do
|
|
453
453
|
let(:headers) { {"Set-Cookie" => "hoo=ray", "set-cookie" => "woo=hoo"} }
|
454
454
|
|
455
455
|
it "adds all headers" do
|
456
|
-
expect(described_class.coerce(headers).to_a).
|
457
|
-
|
458
|
-
|
459
|
-
|
456
|
+
expect(described_class.coerce(headers).to_a).
|
457
|
+
to match_array(
|
458
|
+
[
|
459
|
+
%w(Set-Cookie hoo=ray),
|
460
|
+
%w(Set-Cookie woo=hoo)
|
461
|
+
]
|
462
|
+
)
|
460
463
|
end
|
461
464
|
end
|
462
465
|
|
463
466
|
it "is aliased as .[]" do
|
464
|
-
expect(described_class.method
|
467
|
+
expect(described_class.method(:coerce)).to eq described_class.method(:[])
|
465
468
|
end
|
466
469
|
end
|
467
470
|
end
|
@@ -96,7 +96,7 @@ RSpec.describe HTTP::Response::Status do
|
|
96
96
|
describe ".coerce" do
|
97
97
|
context "with String" do
|
98
98
|
it "coerces reasons" do
|
99
|
-
expect(described_class.coerce
|
99
|
+
expect(described_class.coerce("Bad request")).to eq described_class.new 400
|
100
100
|
end
|
101
101
|
|
102
102
|
it "fails when reason is unknown" do
|
@@ -106,26 +106,26 @@ RSpec.describe HTTP::Response::Status do
|
|
106
106
|
|
107
107
|
context "with Symbol" do
|
108
108
|
it "coerces symbolized reasons" do
|
109
|
-
expect(described_class.coerce
|
109
|
+
expect(described_class.coerce(:bad_request)).to eq described_class.new 400
|
110
110
|
end
|
111
111
|
|
112
112
|
it "fails when symbolized reason is unknown" do
|
113
|
-
expect { described_class.coerce
|
113
|
+
expect { described_class.coerce(:foobar) }.to raise_error HTTP::Error
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
117
|
context "with Numeric" do
|
118
118
|
it "coerces as Fixnum code" do
|
119
|
-
expect(described_class.coerce
|
119
|
+
expect(described_class.coerce(200.1)).to eq described_class.new 200
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
123
|
it "fails if coercion failed" do
|
124
|
-
expect { described_class.coerce
|
124
|
+
expect { described_class.coerce(true) }.to raise_error HTTP::Error
|
125
125
|
end
|
126
126
|
|
127
127
|
it "is aliased as `.[]`" do
|
128
|
-
expect(described_class.method
|
128
|
+
expect(described_class.method(:coerce)).to eq described_class.method :[]
|
129
129
|
end
|
130
130
|
end
|
131
131
|
end
|
@@ -86,11 +86,11 @@ RSpec.describe HTTP::Response do
|
|
86
86
|
context "with explicitly given mime type" do
|
87
87
|
let(:content_type) { "application/deadbeef" }
|
88
88
|
it "ignores mime_type of response" do
|
89
|
-
expect(response.parse
|
89
|
+
expect(response.parse("application/json")).to eq "foo" => "bar"
|
90
90
|
end
|
91
91
|
|
92
92
|
it "supports MIME type aliases" do
|
93
|
-
expect(response.parse
|
93
|
+
expect(response.parse(:json)).to eq "foo" => "bar"
|
94
94
|
end
|
95
95
|
end
|
96
96
|
end
|
data/spec/lib/http_spec.rb
CHANGED
@@ -57,7 +57,7 @@ RSpec.describe HTTP do
|
|
57
57
|
|
58
58
|
let(:characters) { ("A".."Z").to_a }
|
59
59
|
let(:request_body) do
|
60
|
-
(size + fuzzer)
|
60
|
+
Array.new(size + fuzzer) { |i| characters[i % characters.length] }.join
|
61
61
|
end
|
62
62
|
|
63
63
|
it "returns a large body" do
|
data/spec/regression_specs.rb
CHANGED
@@ -2,12 +2,12 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
RSpec.describe "Regression testing" do
|
4
4
|
describe "#248" do
|
5
|
-
it "does not
|
5
|
+
it "does not fail with github" do
|
6
6
|
github_uri = "http://github.com/"
|
7
7
|
expect { HTTP.get(github_uri).to_s }.not_to raise_error
|
8
8
|
end
|
9
9
|
|
10
|
-
it "does not
|
10
|
+
it "does not fail with googleapis" do
|
11
11
|
google_uri = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json"
|
12
12
|
expect { HTTP.get(google_uri).to_s }.not_to raise_error
|
13
13
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,10 +3,12 @@
|
|
3
3
|
require "simplecov"
|
4
4
|
require "coveralls"
|
5
5
|
|
6
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
7
|
+
[
|
8
|
+
SimpleCov::Formatter::HTMLFormatter,
|
9
|
+
Coveralls::SimpleCov::Formatter
|
10
|
+
]
|
11
|
+
)
|
10
12
|
|
11
13
|
SimpleCov.start do
|
12
14
|
add_filter "/spec/"
|
data/spec/support/ssl_helper.rb
CHANGED
@@ -6,7 +6,7 @@ module SSLHelper
|
|
6
6
|
CERTS_PATH = Pathname.new File.expand_path("../../../tmp/certs", __FILE__)
|
7
7
|
|
8
8
|
class RootCertificate < ::CertificateAuthority::Certificate
|
9
|
-
EXTENSIONS = {"keyUsage" => {"usage" => %w(critical keyCertSign)}}
|
9
|
+
EXTENSIONS = {"keyUsage" => {"usage" => %w(critical keyCertSign)}}.freeze
|
10
10
|
|
11
11
|
def initialize
|
12
12
|
super()
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: http
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Arcieri
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2016-
|
14
|
+
date: 2016-03-16 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: http_parser.rb
|
@@ -162,7 +162,7 @@ files:
|
|
162
162
|
- spec/support/servers/config.rb
|
163
163
|
- spec/support/servers/runner.rb
|
164
164
|
- spec/support/ssl_helper.rb
|
165
|
-
homepage: https://github.com/httprb/http
|
165
|
+
homepage: https://github.com/httprb/http
|
166
166
|
licenses:
|
167
167
|
- MIT
|
168
168
|
metadata: {}
|