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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8fa5394fed30d8eebd829ba4c79f6ac28b47fc16
4
- data.tar.gz: d3654335bb11728650548423d57cb402eb3d5080
3
+ metadata.gz: ce1cd065ce4c93b81a5a28a949354322222d0d78
4
+ data.tar.gz: e4b2d331cc30a7780425ec9248c14ba43fcab9ad
5
5
  SHA512:
6
- metadata.gz: 429071438fa4126402282e1d1258180626f3c181192fbc9a03517920af1284d76574d3802863fdd6ac57d42bf1ad79606932c06faee21856c89572861a98b4a9
7
- data.tar.gz: b8db2ca9014d5fc387736f0c5efaba5287fc506ef8ab0ff2433bfe9dc996254e2d7c2fabf078df449962ddefd378a2d1a4a0ae7c1eab7bccfe7e31bac8810186
6
+ metadata.gz: 7fe63ab93211bb553b5f5ec8b9d62f2a7279c0896dc30ff2ff6dc1afdda0c89efcf1193f4032232aec011f2cf77f613d75a77763dfa3ba656ce07e98b72976e0
7
+ data.tar.gz: 94cfd48b04617ab0966222097c2cf11c10c6567dcc89e7decea6dd2d927e9f199cb80f8609f759ecdfa38d57ad894def14c440367f27b0d06d3b5d2bb7b3cf98
@@ -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
- MultiSpaceAllowedForOperators:
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
@@ -22,7 +22,7 @@ group :test do
22
22
  gem "coveralls"
23
23
  gem "simplecov", ">= 0.9"
24
24
  gem "json", ">= 1.8.1"
25
- gem "rubocop", "= 0.35.1"
25
+ gem "rubocop", "= 0.36.0"
26
26
  gem "rspec", "~> 3.0"
27
27
  gem "rspec-its"
28
28
  gem "yardstick"
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 | time |
42
- |--------------------------|-----------|
43
- | curb (persistent) | 2.519088 |
44
- | em-http-request | 2.731645 |
45
- | Typhoeus | 2.851911 |
46
- | StreamlyFFI (persistent) | 2.853786 |
47
- | http.rb (persistent) | 2.970702 |
48
- | http.rb | 3.588964 |
49
- | HTTParty | 3.931913 |
50
- | Net::HTTP | 3.959342 |
51
- | Net::HTTP (persistent) | 4.043674 |
52
- | open-uri | 4.479817 |
53
- | Excon (persistent) | 4.618361 |
54
- | Excon | 4.701262 |
55
- | RestClient | 26.832668 |
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
- gem "http"
82
+ ```ruby
83
+ gem "http"
84
+ ```
84
85
 
85
86
  And then execute:
86
-
87
- $ bundle
87
+ ```bash
88
+ $ bundle
89
+ ```
88
90
 
89
91
  Or install it yourself as:
90
-
91
- $ gem install http
92
+ ```bash
93
+ $ gem install http
94
+ ```
92
95
 
93
96
  Inside of your Ruby program do:
94
-
95
- require "http"
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
- ## Basic Usage
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
- Here's some simple examples to get you started:
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
@@ -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.rb"
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) }
@@ -20,6 +20,6 @@ module HTTP
20
20
 
21
21
  class << self
22
22
  # HTTP[:accept => 'text/html'].get(...)
23
- alias_method :[], :headers
23
+ alias [] headers
24
24
  end
25
25
  end
@@ -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
- if [2, 4].include?(proxy_hash.keys.size)
157
- branch default_options.with_proxy(proxy_hash)
158
- else
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
- alias_method :through, :via
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 " << Base64.strict_encode64("#{user}:#{pass}"))
208
+ auth("Basic " + Base64.strict_encode64("#{user}:#{pass}"))
210
209
  end
211
210
 
212
211
  # Get options for HTTP
@@ -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
- if default_options.persistent?
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
@@ -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
- if read_more(size) == :eof
84
- finished = true
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
- else
104
- break if @parser.headers?
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 = false
168
+ @pending_request = false
173
169
  @pending_response = true
174
170
 
175
171
  read_headers!
176
172
 
177
- if @parser.status_code == 200
178
- @parser.reset
179
- @pending_response = false
173
+ if @parser.status_code != 200
174
+ @failed_proxy_connect = true
180
175
  return
181
176
  end
182
177
 
183
- @failed_proxy_connect = true
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
- case @parser.http_version
199
- when HTTP_1_0 # HTTP/1.0 requires opt in for Keep Alive
200
- @keep_alive = @parser.headers[Headers::CONNECTION] == Client::KEEP_ALIVE
201
- when HTTP_1_1 # HTTP/1.1 is opt-out
202
- @keep_alive = @parser.headers[Headers::CONNECTION] != Client::CLOSE
203
- else # Anything else we assume doesn't supportit
204
- @keep_alive = false
205
- end
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
@@ -11,11 +11,11 @@ module HTTP
11
11
  include Enumerable
12
12
 
13
13
  # Matches HTTP header names when in "Canonical-Http-Format"
14
- CANONICAL_HEADER = /^[A-Z][a-z]*(-[A-Z][a-z]*)*$/
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
- HEADER_NAME_RE = /^[A-Za-z0-9!#\$%&'*+\-.^_`|~]+$/
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
- alias_method :[]=, :set
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
- alias_method :to_hash, :to_h
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
- alias_method :[], :coerce
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
- normalized = name[CANONICAL_HEADER]
195
- normalized ||= name.split(/[\-_]/).map(&:capitalize).join("-")
194
+ return name if name =~ CANONICAL_NAME_RE
196
195
 
197
- return normalized if normalized =~ HEADER_NAME_RE
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
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module HTTP
2
3
  class Headers
3
4
  # Content-Types that are acceptable for the response.
@@ -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
- # RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1
27
- METHODS = [:options, :get, :head, :post, :put, :delete, :trace, :connect]
27
+ METHODS = [
28
+ # RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1
29
+ :options, :get, :head, :post, :put, :delete, :trace, :connect,
28
30
 
29
- # RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV
30
- METHODS.concat [:propfind, :proppatch, :mkcol, :copy, :move, :lock, :unlock]
31
+ # RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV
32
+ :propfind, :proppatch, :mkcol, :copy, :move, :lock, :unlock,
31
33
 
32
- # RFC 3648: WebDAV Ordered Collections Protocol
33
- METHODS.concat [:orderpatch]
34
+ # RFC 3648: WebDAV Ordered Collections Protocol
35
+ :orderpatch,
34
36
 
35
- # RFC 3744: WebDAV Access Control Protocol
36
- METHODS.concat [:acl]
37
+ # RFC 3744: WebDAV Access Control Protocol
38
+ :acl,
37
39
 
38
- # draft-dusseault-http-patch: PATCH Method for HTTP
39
- METHODS.concat [:patch]
40
+ # draft-dusseault-http-patch: PATCH Method for HTTP
41
+ :patch,
40
42
 
41
- # draft-reschke-webdav-search: WebDAV Search
42
- METHODS.concat [:search]
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 :uri)
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)
@@ -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) + (CRLF) * 2
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
- if data.length > length
98
- data = data[length..-1]
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
 
@@ -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 :uri) if opts.include? :uri
38
- @status = HTTP::Response::Status.new(opts.fetch :status)
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
- alias_method :to_str, :to_s
62
+ alias to_str to_s
63
63
 
64
64
  # @!method readpartial
65
65
  # (see HTTP::Response::Body#readpartial)
@@ -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(@encoding)
47
+ @contents = "".force_encoding(encoding)
41
48
  while (chunk = @client.readpartial)
42
- @contents << chunk.force_encoding(@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
- alias_method :to_str, :to_s
58
+ alias to_str to_s
52
59
 
53
60
  # Assert that the body is actively being streamed
54
61
  def stream!
@@ -11,7 +11,7 @@ module HTTP
11
11
  def add(data)
12
12
  @parser << data
13
13
  end
14
- alias_method :<<, :add
14
+ alias << add
15
15
 
16
16
  def headers?
17
17
  !!@headers
@@ -28,7 +28,7 @@ module HTTP
28
28
 
29
29
  fail Error, "Can't coerce #{object.class}(#{object}) to #{self}"
30
30
  end
31
- alias_method :[], :coerce
31
+ alias [] coerce
32
32
 
33
33
  private
34
34
 
@@ -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
- alias_method :<<, :write
57
+ alias << write
58
58
 
59
59
  private
60
60
 
@@ -48,7 +48,7 @@ module HTTP
48
48
  def write(data)
49
49
  @socket.write(data)
50
50
  end
51
- alias_method :<<, :write
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
- # JRuby may still raise exceptions on SSL sockets even though
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
- # JRuby may still raise exceptions on SSL sockets even though
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, "Read timed out after #{write_timeout} seconds"
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
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "addressable/uri"
2
3
 
3
4
  module HTTP
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module HTTP
2
- VERSION = "1.0.2".freeze
3
+ VERSION = "1.0.3".freeze
3
4
  end
@@ -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 opts[:uri].query).to eq("foo" => %w(bar))
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 opts[:uri].query).to eq("foo" => %w(bar), "baz" => %w(quux))
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 opts[:uri].query).to eq "a[]" => %w(b c), "d" => %w(e)
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 "", "foobar" }.
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 "Content-Type", "application/json" }
125
+ before { headers.set("Content-Type", "application/json") }
126
126
 
127
127
  it "returns array of associated values" do
128
- expect(headers.get "Content-Type").to eq %w(application/json)
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 :content_type).to eq %w(application/json)
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 :accept).to eq []
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 "foo bar" }.
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).to match_array([
457
- %w(Set-Cookie hoo=ray),
458
- %w(Set-Cookie woo=hoo)
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 :coerce).to eq 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 "Bad request").to eq described_class.new 400
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 :bad_request).to eq described_class.new 400
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 :foobar }.to raise_error HTTP::Error
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 200.1).to eq described_class.new 200
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 true }.to raise_error HTTP::Error
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 :coerce).to eq 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 "application/json").to eq "foo" => "bar"
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 :json).to eq "foo" => "bar"
93
+ expect(response.parse(:json)).to eq "foo" => "bar"
94
94
  end
95
95
  end
96
96
  end
@@ -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).times.map { |i| characters[i % characters.length] }.join
60
+ Array.new(size + fuzzer) { |i| characters[i % characters.length] }.join
61
61
  end
62
62
 
63
63
  it "returns a large body" do
@@ -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 fails with github" do
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 failes ith googleapis" do
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
@@ -3,10 +3,12 @@
3
3
  require "simplecov"
4
4
  require "coveralls"
5
5
 
6
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
7
- SimpleCov::Formatter::HTMLFormatter,
8
- Coveralls::SimpleCov::Formatter
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/"
@@ -1,7 +1,7 @@
1
1
  module ServerRunner
2
- def run_server(name, &block)
2
+ def run_server(name)
3
3
  let! name do
4
- server = block.call
4
+ server = yield
5
5
 
6
6
  Thread.new { server.start }
7
7
 
@@ -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.2
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-01-15 00:00:00.000000000 Z
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.rb
165
+ homepage: https://github.com/httprb/http
166
166
  licenses:
167
167
  - MIT
168
168
  metadata: {}