http 1.0.2 → 1.0.3
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/.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: {}
|