http 1.0.0.pre1 → 1.0.0.pre2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a6a3c8891e4a8af6201fcda1333d5570ca5b0c15
4
- data.tar.gz: e527a9a5e0976f1e9ef793fd451c127b76738607
3
+ metadata.gz: 88e73e87efcb7c8c34d776d5bffcf72f45c195da
4
+ data.tar.gz: d9e4ef53d51cf7fa664999fd9e81c43e40d0a73c
5
5
  SHA512:
6
- metadata.gz: 4811c0bf41f037a2615f165d03ee1fd8dee7b42a4e743e1ec35638ca2ab96c82d9b808dfe96eff083003588b98c1dcc1502b8eb23c268e7ef239e388e27a00dc
7
- data.tar.gz: 9e7357f1161890a87449b6c92040fff54d9b829481de267d85f0c9337e0ec8e9e3a6a13319ef6055875b09fd39d854f62a48179e1e248da1671c47bc609faf21
6
+ metadata.gz: afb56806f4e58c1781db4722362319930d12489b60a258a83e3bfcd035f362ab22e9605078a23d89ebf6d265508482652bdf5e26ffeb4311fba061c458e1e576
7
+ data.tar.gz: cefe686bd8276230e515498becaa20c43aa14ee4203b47497ca7cbd4c9ec56ebe15c6a908737e042001135fd664c543401d22a97674386aa08b420475e2c8530
data/.rubocop.yml CHANGED
@@ -24,7 +24,7 @@ Metrics/ModuleLength:
24
24
  Max: 120
25
25
 
26
26
  Metrics/ParameterLists:
27
- Max: 3
27
+ Max: 5
28
28
  CountKeywordArgs: true
29
29
 
30
30
  Metrics/AbcSize:
data/CHANGES.md CHANGED
@@ -1,4 +1,4 @@
1
- ## 1.0.0.pre1 (2015-12-05)
1
+ ## 1.0.0.pre2 (2015-12-18)
2
2
 
3
3
  * [#265](https://github.com/httprb/http/pull/265/):
4
4
  Remove deprecations ([@tarcieri]):
@@ -14,182 +14,199 @@
14
14
  - HTTP::Response#status_code (use #status or #code)
15
15
  - HTTP::Response::Status#symbolize (use #to_sym)
16
16
 
17
+ * [#269](https://github.com/httprb/http/pull/273/):
18
+ Close connection in case of error during request.
19
+ ([@ixti])
20
+
21
+ * [#271](https://github.com/httprb/http/pull/273/):
22
+ High-level exception wrappers for low-level I/O errors.
23
+ ([@ixti])
24
+
25
+ * [#273](https://github.com/httprb/http/pull/273/):
26
+ Add encoding option.
27
+ ([@connorhd])
28
+
29
+ * [#275](https://github.com/httprb/http/pull/273/):
30
+ Support for disabling Nagle's algorithm with `HTTP.nodelay`.
31
+ ([@nerdrew])
32
+
17
33
  ## 0.9.8 (2015-09-29)
18
34
 
19
35
  * [#260](https://github.com/httprb/http/pull/258):
20
36
  Fixed global timeout persisting time left across requests when reusing connections.
21
- ([@zanker][])
37
+ ([@zanker])
38
+
22
39
 
23
40
  ## 0.9.7 (2015-09-19)
24
41
 
25
42
  * [#258](https://github.com/httprb/http/pull/258):
26
43
  Unified strategy for handling exception-based and exceptionless non-blocking
27
- I/O. Fixes SSL support on JRuby 9000. ([@tarcieri][])
44
+ I/O. Fixes SSL support on JRuby 9000. ([@tarcieri])
28
45
 
29
46
 
30
47
  ## 0.9.6 (2015-09-06)
31
48
 
32
49
  * [#254](https://github.com/httprb/http/pull/254):
33
50
  Removed use of an ActiveSupport specific method #present?
34
- ([@tarcieri][])
51
+ ([@tarcieri])
35
52
 
36
53
 
37
54
  ## 0.9.5 (2015-09-06)
38
55
 
39
56
  * [#252](https://github.com/httprb/http/pull/252):
40
57
  Fixed infinite hang/timeout when a request contained more than ~16,363 bytes.
41
- ([@zanker][])
58
+ ([@zanker])
42
59
 
43
60
 
44
61
  ## 0.9.4 (2015-08-26)
45
62
 
46
63
  * [#246](https://github.com/httprb/http/issues/246):
47
64
  Fixes regression when body streaming was failing on some URIs.
48
- ([@zanker][])
65
+ ([@zanker])
49
66
  * [#243](https://github.com/httprb/http/issues/243):
50
- Fixes require timeout statements. ([@ixti][])
67
+ Fixes require timeout statements. ([@ixti])
51
68
 
52
69
 
53
70
  ## 0.9.3 (2015-08-19)
54
71
 
55
72
  * [#246](https://github.com/httprb/http/issues/246):
56
- Fixed request URI normalization. ([@ixti][])
73
+ Fixed request URI normalization. ([@ixti])
57
74
  - Avoids query component normalization
58
75
  - Omits fragment component in headline
59
76
 
60
77
 
61
78
  ## 0.9.2 (2015-08-18)
62
79
 
63
- * Fixed exceptionless NIO EOF handling. ([@zanker][])
80
+ * Fixed exceptionless NIO EOF handling. ([@zanker])
64
81
 
65
82
 
66
83
  ## 0.9.1 (2015-08-14)
67
84
 
68
85
  * [#246](https://github.com/httprb/http/issues/246):
69
- Fix params special-chars escaping. ([@ixti][])
86
+ Fix params special-chars escaping. ([@ixti])
70
87
 
71
88
 
72
89
  ## 0.9.0 (2015-07-23)
73
90
 
74
91
  * [#240](https://github.com/httprb/http/pull/240):
75
- Support for caching removed. ([@tarcieri][])
92
+ Support for caching removed. ([@tarcieri])
76
93
  * JRuby 9000 compatibility
77
94
 
78
95
 
79
96
  ## 0.8.14 (2015-08-19)
80
97
 
81
- * Backport request URI normalization fixes from master. ([@ixti][])
98
+ * Backport request URI normalization fixes from master. ([@ixti])
82
99
 
83
100
 
84
101
  ## 0.8.13 (2015-08-14)
85
102
 
86
- * Backport params special-chars escaping fix from `v0.9.1`. ([@ixti][])
103
+ * Backport params special-chars escaping fix from `v0.9.1`. ([@ixti])
87
104
 
88
105
 
89
106
  ## 0.8.12 (2015-05-26)
90
107
 
91
- * Fix `HTTP.timeout` API (was loosing previously defined options). ([@ixti][])
108
+ * Fix `HTTP.timeout` API (was loosing previously defined options). ([@ixti])
92
109
 
93
110
 
94
111
  ## 0.8.11 (2015-05-22)
95
112
 
96
113
  * [#229](https://github.com/httprb/http/pull/229):
97
- SNI support for HTTPS connections. ([@tarcieri][])
114
+ SNI support for HTTPS connections. ([@tarcieri])
98
115
  * [#227](https://github.com/httprb/http/pull/227):
99
- Use "http.rb" in the User-Agent string. ([@tarcieri][])
116
+ Use "http.rb" in the User-Agent string. ([@tarcieri])
100
117
 
101
118
 
102
119
  ## 0.8.10 (2015-05-14)
103
120
 
104
- * Fix cookie headers generation. ([@ixti][])
121
+ * Fix cookie headers generation. ([@ixti])
105
122
 
106
123
 
107
124
  ## 0.8.9 (2015-05-11)
108
125
 
109
- * Add cookies support. ([@ixti][])
126
+ * Add cookies support. ([@ixti])
110
127
  * [#219](https://github.com/httprb/http/pull/219):
111
- Enforce stringified body encoding. ([@Connorhd][])
128
+ Enforce stringified body encoding. ([@Connorhd])
112
129
 
113
130
 
114
131
  ## 0.8.8 (2015-05-09)
115
132
 
116
133
  * [#217](https://github.com/httprb/http/issues/217):
117
- Fix CONNECT header for proxies. ([@Connorhd][])
134
+ Fix CONNECT header for proxies. ([@Connorhd])
118
135
 
119
136
 
120
137
  ## 0.8.7 (2015-05-08)
121
138
 
122
- * Fix `HTTP.timeout` API with options only given. ([@ixti][])
139
+ * Fix `HTTP.timeout` API with options only given. ([@ixti])
123
140
 
124
141
 
125
142
  ## 0.8.6 (2015-05-08)
126
143
 
127
144
  * [#215](https://github.com/httprb/http/pull/215):
128
- Reset global timeouts after the request finishes. ([@zanker][])
145
+ Reset global timeouts after the request finishes. ([@zanker])
129
146
 
130
147
 
131
148
  ## 0.8.5 (2015-05-06)
132
149
 
133
150
  * [#205](https://github.com/httprb/http/issues/205):
134
- Add simple timeouts configuration API. ([@ixti][])
135
- * Deprecate `Request#request_header`. Use `Request#headline` instead. ([@ixti][])
151
+ Add simple timeouts configuration API. ([@ixti])
152
+ * Deprecate `Request#request_header`. Use `Request#headline` instead. ([@ixti])
136
153
 
137
154
 
138
155
  ## 0.8.4 (2015-04-23)
139
156
 
140
- * Deprecate `#default_headers` and `#default_headers=`. ([@ixti][])
157
+ * Deprecate `#default_headers` and `#default_headers=`. ([@ixti])
141
158
  * [#207](https://github.com/httprb/http/issues/207):
142
- Deprecate chainable methods with `with_` prefix. ([@ixti][])
159
+ Deprecate chainable methods with `with_` prefix. ([@ixti])
143
160
  * [#186](https://github.com/httprb/http/pull/186):
144
- Add support of HTTPS connections through proxy. ([@Connorhd][])
161
+ Add support of HTTPS connections through proxy. ([@Connorhd])
145
162
 
146
163
 
147
164
  ## 0.8.3 (2015-04-07)
148
165
 
149
166
  * [#206](https://github.com/httprb/http/issues/206):
150
- Fix request headline. ([@ixti][])
151
- * Remove deprecated `Request#__method__`. ([@ixti][])
167
+ Fix request headline. ([@ixti])
168
+ * Remove deprecated `Request#__method__`. ([@ixti])
152
169
 
153
170
 
154
171
  ## 0.8.2 (2015-04-06)
155
172
 
156
173
  * [#203](https://github.com/httprb/http/issues/203):
157
- Fix Celluloid::IO compatibility. ([@ixti][])
158
- * Cleanup obsolete code. ([@zanker][])
174
+ Fix Celluloid::IO compatibility. ([@ixti])
175
+ * Cleanup obsolete code. ([@zanker])
159
176
 
160
177
 
161
178
  ## 0.8.1 (2015-04-02)
162
179
 
163
180
  * [#202](https://github.com/httprb/http/issues/202):
164
- Add missing `require "resolv"`. ([@ixti][])
181
+ Add missing `require "resolv"`. ([@ixti])
165
182
  * [#200](https://github.com/httprb/http/issues/200),
166
183
  [#201](https://github.com/httprb/http/pull/201):
167
- Add block-form `#persistent` calls. ([@ixti][])
184
+ Add block-form `#persistent` calls. ([@ixti])
168
185
 
169
186
 
170
187
  ## 0.8.0 (2015-04-01)
171
188
 
172
189
  * [#199](https://github.com/httprb/http/pull/199):
173
- Properly handle WaitWritable for SSL. ([@zanker][])
190
+ Properly handle WaitWritable for SSL. ([@zanker])
174
191
  * [#197](https://github.com/httprb/http/pull/197):
175
- Add support for non-ASCII URis. ([@ixti][])
192
+ Add support for non-ASCII URis. ([@ixti])
176
193
  * [#187](https://github.com/httprb/http/pull/187),
177
194
  [#194](https://github.com/httprb/http/pull/194),
178
195
  [#195](https://github.com/httprb/http/pull/195):
179
- Add configurable connection timeouts. ([@zanker][])
196
+ Add configurable connection timeouts. ([@zanker])
180
197
  * [#179](https://github.com/httprb/http/pull/179):
181
- Refactor requests redirect following logic. ([@ixti][])
182
- * Support for persistent HTTP connections ([@zanker][])
198
+ Refactor requests redirect following logic. ([@ixti])
199
+ * Support for persistent HTTP connections ([@zanker])
183
200
  * [#77](https://github.com/httprb/http/issues/77),
184
201
  [#177](https://github.com/httprb/http/pull/177):
185
- Add caching support. ([@Asmod4n][], [@pezra][])
202
+ Add caching support. ([@Asmod4n], [@pezra])
186
203
  * [#176](https://github.com/httprb/http/pull/176):
187
204
  Improve servers used in specs boot up. Issue was initially raised up
188
- by [@olegkovalenko][]. ([@ixti][])
189
- * Reflect FormData rename changes (FormData -> HTTP::FormData). ([@ixti][])
205
+ by [@olegkovalenko]. ([@ixti])
206
+ * Reflect FormData rename changes (FormData -> HTTP::FormData). ([@ixti])
190
207
  * [#173](https://github.com/httprb/http/pull/173):
191
208
  `HTTP::Headers` now raises `HTTP::InvalidHeaderNameError` in case of
192
- (surprise) invalid HTTP header field name (e.g.`"Foo:Bar"`). ([@ixti][])
209
+ (surprise) invalid HTTP header field name (e.g.`"Foo:Bar"`). ([@ixti])
193
210
 
194
211
 
195
212
  ## 0.7.3 (2015-03-24)
@@ -197,7 +214,7 @@
197
214
  * SECURITY FIX: http.rb failed to call the `#post_connection_check` method on
198
215
  SSL connections. This method implements hostname verification, and without it
199
216
  `http.rb` was vulnerable to MitM attacks. The problem was corrected by calling
200
- `#post_connection_check` (CVE-2015-1828) ([@zanker][])
217
+ `#post_connection_check` (CVE-2015-1828) ([@zanker])
201
218
 
202
219
 
203
220
  ## 0.7.2 (2015-03-02)
@@ -215,33 +232,33 @@
215
232
 
216
233
  * [#73](https://github.com/httprb/http/issues/73),
217
234
  [#167](https://github.com/httprb/http/pull/167):
218
- Add support of multipart form data. ([@ixti][])
235
+ Add support of multipart form data. ([@ixti])
219
236
  * Fix URI path normalization: `https://github.com` -> `https://github.com/`.
220
- ([@ixti][])
237
+ ([@ixti])
221
238
  * [#163](https://github.com/httprb/http/pull/163),
222
239
  [#166](https://github.com/httprb/http/pull/166),
223
240
  [#152](https://github.com/httprb/http/issues/152):
224
- Fix handling of EOF which caused infinite loop. ([@mickm][], [@ixti][])
225
- * Drop Ruby 1.8.7 support. ([@ixti][])
241
+ Fix handling of EOF which caused infinite loop. ([@mickm], [@ixti])
242
+ * Drop Ruby 1.8.7 support. ([@ixti])
226
243
  * [#150](https://github.com/httprb/http/issues/150):
227
- Fix default Host header value. ([@ixti][])
228
- * Remove BearerToken authorization header. ([@ixti][])
244
+ Fix default Host header value. ([@ixti])
245
+ * Remove BearerToken authorization header. ([@ixti])
229
246
  * `#auth` sugar now accepts only string value of Authorization header.
230
247
  Calling `#auth(:basic, opts)` is deprecated, use `#basic_auth(opts)` instead.
231
- ([@ixti][])
232
- * Fix handling of chunked responses without Content-Length header. ([@ixti][])
248
+ ([@ixti])
249
+ * Fix handling of chunked responses without Content-Length header. ([@ixti])
233
250
  * Remove `HTTP::Request#method` and deprecate `HTTP::Request#__method__`
234
- ([@sferik][])
251
+ ([@sferik])
235
252
  * Deprecate `HTTP::Response::STATUS_CODES`,
236
- use `HTTP::Response::Status::REASONS` instead ([@ixti][])
237
- * Deprecate `HTTP::Response::SYMBOL_TO_STATUS_CODE` ([@ixti][])
238
- * Deprecate `HTTP::Response#status_code` ([@ixti][])
239
- * `HTTP::Response#status` now returns `HTTP::Response::Status`. ([@ixti][])
253
+ use `HTTP::Response::Status::REASONS` instead ([@ixti])
254
+ * Deprecate `HTTP::Response::SYMBOL_TO_STATUS_CODE` ([@ixti])
255
+ * Deprecate `HTTP::Response#status_code` ([@ixti])
256
+ * `HTTP::Response#status` now returns `HTTP::Response::Status`. ([@ixti])
240
257
  * `HTTP::Response#reason` and `HTTP::Response#code` are proxies them
241
- to corresponding methods of `HTTP::Response#status` ([@ixti][])
258
+ to corresponding methods of `HTTP::Response#status` ([@ixti])
242
259
  * Rename `HTTP.with_follow` to `HTTP.follow` and mark former one as being
243
- deprecated ([@ixti][])
244
- * Delegate `HTTP::Response#readpartial` to `HTTP::Response::Body` ([@ixti][])
260
+ deprecated ([@ixti])
261
+ * Delegate `HTTP::Response#readpartial` to `HTTP::Response::Body` ([@ixti])
245
262
 
246
263
 
247
264
  ## 0.6.4 (2015-03-25)
@@ -249,57 +266,57 @@
249
266
  * SECURITY FIX: http.rb failed to call the `#post_connection_check` method on
250
267
  SSL connections. This method implements hostname verification, and without it
251
268
  `http.rb` was vulnerable to MitM attacks. The problem was corrected by calling
252
- `#post_connection_check` (CVE-2015-1828) ([@zanker][], backported by [@nicoolas25][])
269
+ `#post_connection_check` (CVE-2015-1828) ([@zanker], backported by [@nicoolas25])
253
270
 
254
271
 
255
272
  ## 0.6.3 (2014-11-14)
256
273
 
257
274
  * [#166](https://github.com/httprb/http/pull/166):
258
- Backported EOF fix from master branch. ([@ixti][])
275
+ Backported EOF fix from master branch. ([@ixti])
259
276
 
260
277
 
261
278
  ## 0.6.2 (2014-08-06)
262
279
 
263
280
  * [#150](https://github.com/httprb/http/issues/150):
264
- Fix default Host header value. ([@ixti][])
265
- * Deprecate BearerToken authorization header. ([@ixti][])
266
- * Fix handling of chunked responses without Content-Length header. ([@ixti][])
281
+ Fix default Host header value. ([@ixti])
282
+ * Deprecate BearerToken authorization header. ([@ixti])
283
+ * Fix handling of chunked responses without Content-Length header. ([@ixti])
267
284
  * Rename `HTTP.with_follow` to `HTTP.follow` and mark former one as being
268
- deprecated ([@ixti][])
285
+ deprecated ([@ixti])
269
286
 
270
287
 
271
288
  ## 0.6.1 (2014-05-07)
272
289
 
273
- * Fix request `Content-Length` calculation for Unicode ([@challengee][])
274
- * Add `Response#flush` ([@ixti][])
275
- * Fix `Response::Body#readpartial` default size ([@hannesg][], [@ixti][])
276
- * Add missing `CRLF` for chunked bodies ([@hannesg][])
277
- * Fix forgotten CGI require ([@ixti][])
278
- * Improve README ([@tarcieri][])
290
+ * Fix request `Content-Length` calculation for Unicode ([@challengee])
291
+ * Add `Response#flush` ([@ixti])
292
+ * Fix `Response::Body#readpartial` default size ([@hannesg], [@ixti])
293
+ * Add missing `CRLF` for chunked bodies ([@hannesg])
294
+ * Fix forgotten CGI require ([@ixti])
295
+ * Improve README ([@tarcieri])
279
296
 
280
297
 
281
298
  ## 0.6.0 (2014-04-04)
282
299
 
283
- * Rename `HTTP::Request#method` to `HTTP::Request#verb` ([@krainboltgreene][])
284
- * Add `HTTP::ResponseBody` class ([@tarcieri][])
285
- * Change API of response on `HTTP::Client.request` and "friends" (`#get`, `#post`, etc) ([@tarcieri][])
286
- * Add `HTTP::Response#readpartial` ([@tarcieri][])
287
- * Add `HTTP::Headers` class ([@ixti][])
288
- * Fix and improve following redirects ([@ixti][])
289
- * Add `HTTP::Request#redirect` ([@ixti][])
290
- * Add `HTTP::Response#content_type` ([@ixti][])
291
- * Add `HTTP::Response#mime_type` ([@ixti][])
292
- * Add `HTTP::Response#charset` ([@ixti][])
293
- * Improve error message upon invalid URI scheme ([@ixti][])
294
- * Consolidate errors under common `HTTP::Error` namespace ([@ixti][])
295
- * Add easy way of adding Authorization header ([@ixti][])
296
- * Fix proxy support ([@hundredwatt][])
297
- * Fix and improve query params handing ([@jwinter][])
298
- * Change API of custom MIME type parsers ([@ixti][])
299
- * Remove `HTTP::Chainable#with_response` ([@ixti][])
300
- * Remove `HTTP::Response::BodyDelegator` ([@ixti][])
301
- * Remove `HTTP::Response#parsed_body` ([@ixti][])
302
- * Bump up input buffer from 4K to 16K ([@tarcieri][])
300
+ * Rename `HTTP::Request#method` to `HTTP::Request#verb` ([@krainboltgreene])
301
+ * Add `HTTP::ResponseBody` class ([@tarcieri])
302
+ * Change API of response on `HTTP::Client.request` and "friends" (`#get`, `#post`, etc) ([@tarcieri])
303
+ * Add `HTTP::Response#readpartial` ([@tarcieri])
304
+ * Add `HTTP::Headers` class ([@ixti])
305
+ * Fix and improve following redirects ([@ixti])
306
+ * Add `HTTP::Request#redirect` ([@ixti])
307
+ * Add `HTTP::Response#content_type` ([@ixti])
308
+ * Add `HTTP::Response#mime_type` ([@ixti])
309
+ * Add `HTTP::Response#charset` ([@ixti])
310
+ * Improve error message upon invalid URI scheme ([@ixti])
311
+ * Consolidate errors under common `HTTP::Error` namespace ([@ixti])
312
+ * Add easy way of adding Authorization header ([@ixti])
313
+ * Fix proxy support ([@hundredwatt])
314
+ * Fix and improve query params handing ([@jwinter])
315
+ * Change API of custom MIME type parsers ([@ixti])
316
+ * Remove `HTTP::Chainable#with_response` ([@ixti])
317
+ * Remove `HTTP::Response::BodyDelegator` ([@ixti])
318
+ * Remove `HTTP::Response#parsed_body` ([@ixti])
319
+ * Bump up input buffer from 4K to 16K ([@tarcieri])
303
320
 
304
321
  ``` ruby
305
322
  # Main API change you will mention is that `request` method and it's
@@ -313,7 +330,7 @@ parsed_body = HTTP.get("http://example.com/users.json").parse
313
330
  # Second major change in API is work with request/response headers
314
331
  # It is now delegated to `HTTP::Headers` class, so you can check it's
315
332
  # documentation for details, here we will only outline main difference.
316
- # Duckface (`[]=`) does not appends headers anymore
333
+ # Duckface (`=`) does not appends headers anymore
317
334
 
318
335
  request[:content_type] = "text/plain"
319
336
  request[:content_type] = "text/html"
@@ -345,7 +362,7 @@ end
345
362
 
346
363
  ## 0.5.1 (2014-05-27)
347
364
 
348
- * Backports redirector fixes from 0.6.0 ([@ixti][])
365
+ * Backports redirector fixes from 0.6.0 ([@ixti])
349
366
  * EOL of 0.5.X branch.
350
367
 
351
368
 
data/README.md CHANGED
@@ -55,6 +55,10 @@ Top three reasons:
55
55
 
56
56
  Benchmarks performed using excon's benchmarking tool
57
57
 
58
+ DISCLAIMER: Most benchmarks you find in READMEs are crap,
59
+ including this one. These are out-of-date. If you care about
60
+ performance, benchmark for yourself for your own use cases!
61
+
58
62
  ## Help and Discussion
59
63
 
60
64
  If you need help or just want to talk about the http.rb,
@@ -180,6 +180,11 @@ module HTTP
180
180
  branch default_options.with_cookies(cookies)
181
181
  end
182
182
 
183
+ # Force a specific encoding for response body
184
+ def encoding(encoding)
185
+ branch default_options.with_encoding(encoding)
186
+ end
187
+
183
188
  # Accept the given MIME type(s)
184
189
  # @param type
185
190
  def accept(type)
@@ -217,6 +222,11 @@ module HTTP
217
222
  @default_options = HTTP::Options.new(opts)
218
223
  end
219
224
 
225
+ # Set TCP_NODELAY on the socket
226
+ def nodelay
227
+ branch default_options.with_nodelay(true)
228
+ end
229
+
220
230
  private
221
231
 
222
232
  # :nodoc:
data/lib/http/client.rb CHANGED
@@ -61,11 +61,12 @@ module HTTP
61
61
  end
62
62
 
63
63
  res = Response.new(
64
- @connection.status_code,
65
- @connection.http_version,
66
- @connection.headers,
67
- Response::Body.new(@connection),
68
- req.uri
64
+ :status => @connection.status_code,
65
+ :version => @connection.http_version,
66
+ :headers => @connection.headers,
67
+ :connection => @connection,
68
+ :encoding => options.encoding,
69
+ :uri => req.uri
69
70
  )
70
71
 
71
72
  @connection.finish_response if req.verb == :head
@@ -73,9 +74,7 @@ module HTTP
73
74
 
74
75
  res
75
76
  rescue
76
- # On any exception we reset the conn. This is a safety measure, to ensure
77
- # we don't have conns in a bad state resulting in mixed requests/responses
78
- close if persistent?
77
+ close
79
78
  raise
80
79
  end
81
80
 
@@ -20,6 +20,7 @@ module HTTP
20
20
 
21
21
  # @param [HTTP::Request] req
22
22
  # @param [HTTP::Options] options
23
+ # @raise [HTTP::ConnectionError] when failed to connect
23
24
  def initialize(req, options)
24
25
  @persistent = options.persistent?
25
26
  @keep_alive_timeout = options.keep_alive_timeout.to_f
@@ -30,11 +31,13 @@ module HTTP
30
31
  @parser = Response::Parser.new
31
32
 
32
33
  @socket = options.timeout_class.new(options.timeout_options)
33
- @socket.connect(options.socket_class, req.socket_host, req.socket_port)
34
+ @socket.connect(options.socket_class, req.socket_host, req.socket_port, options.nodelay)
34
35
 
35
36
  send_proxy_connect_request(req)
36
37
  start_tls(req, options)
37
38
  reset_timer
39
+ rescue SocketError, SystemCallError => e
40
+ raise ConnectionError, "failed to connect: #{e}"
38
41
  end
39
42
 
40
43
  # @see (HTTP::Response::Parser#status_code)
@@ -104,7 +107,7 @@ module HTTP
104
107
 
105
108
  set_keep_alive
106
109
  rescue IOError, Errno::ECONNRESET, Errno::EPIPE => e
107
- raise IOError, "problem making HTTP request: #{e}"
110
+ raise ConnectionError, "failed to read headers: #{e}"
108
111
  end
109
112
 
110
113
  # Callback for when we've reached the end of a response
data/lib/http/errors.rb CHANGED
@@ -2,6 +2,9 @@ module HTTP
2
2
  # Generic error
3
3
  class Error < StandardError; end
4
4
 
5
+ # Generic Connection error
6
+ class ConnectionError < Error; end
7
+
5
8
  # Generic Request error
6
9
  class RequestError < Error; end
7
10
 
data/lib/http/options.rb CHANGED
@@ -43,11 +43,13 @@ module HTTP
43
43
  :timeout_class => self.class.default_timeout_class,
44
44
  :timeout_options => {},
45
45
  :socket_class => self.class.default_socket_class,
46
+ :nodelay => false,
46
47
  :ssl_socket_class => self.class.default_ssl_socket_class,
47
48
  :ssl => {},
48
49
  :keep_alive_timeout => 5,
49
50
  :headers => {},
50
- :cookies => {}
51
+ :cookies => {},
52
+ :encoding => nil
51
53
  }
52
54
 
53
55
  opts_w_defaults = defaults.merge(options)
@@ -66,9 +68,13 @@ module HTTP
66
68
  end
67
69
  end
68
70
 
71
+ def_option :encoding do |encoding|
72
+ self.encoding = Encoding.find(encoding)
73
+ end
74
+
69
75
  %w(
70
76
  proxy params form json body follow response
71
- socket_class ssl_socket_class ssl_context ssl
77
+ socket_class nodelay ssl_socket_class ssl_context ssl
72
78
  persistent keep_alive_timeout timeout_class timeout_options
73
79
  ).each do |method_name|
74
80
  def_option method_name
@@ -18,7 +18,7 @@ module HTTP
18
18
  # Types valid to be used as body source
19
19
  VALID_BODY_TYPES = [String, NilClass, Enumerable]
20
20
 
21
- def initialize(socket, body, headers, headline) # rubocop:disable ParameterLists
21
+ def initialize(socket, body, headers, headline)
22
22
  @body = body
23
23
  @socket = socket
24
24
  @headers = headers
data/lib/http/response.rb CHANGED
@@ -23,12 +23,27 @@ module HTTP
23
23
  # @return [URI, nil]
24
24
  attr_reader :uri
25
25
 
26
- def initialize(status, version, headers, body, uri = nil) # rubocop:disable ParameterLists
27
- @version = version
28
- @body = body
29
- @uri = uri && HTTP::URI.parse(uri)
30
- @status = HTTP::Response::Status.new status
31
- @headers = HTTP::Headers.coerce(headers || {})
26
+ # Inits a new instance
27
+ #
28
+ # @option opts [Integer] :status Status code
29
+ # @option opts [String] :version HTTP version
30
+ # @option opts [Hash] :headers
31
+ # @option opts [HTTP::Connection] :connection
32
+ # @option opts [String] :encoding Encoding to use when reading body
33
+ # @option opts [String] :body
34
+ # @option opts [String] :uri
35
+ def initialize(opts)
36
+ @version = opts.fetch(:version)
37
+ @uri = opts.include?(:uri) && HTTP::URI.parse(opts.fetch(:uri))
38
+ @status = HTTP::Response::Status.new opts.fetch(:status)
39
+ @headers = HTTP::Headers.coerce(opts.fetch(:headers, {}))
40
+
41
+ if opts.include?(:connection)
42
+ encoding = opts[:encoding] || charset || Encoding::BINARY
43
+ @body = Response::Body.new(opts.fetch(:connection), encoding)
44
+ else
45
+ @body = opts.fetch(:body)
46
+ end
32
47
  end
33
48
 
34
49
  # @!method reason
@@ -70,19 +85,15 @@ module HTTP
70
85
  @content_type ||= ContentType.parse headers[Headers::CONTENT_TYPE]
71
86
  end
72
87
 
73
- # MIME type of response (if any)
74
- #
75
- # @return [String, nil]
76
- def mime_type
77
- @mime_type ||= content_type.mime_type
78
- end
88
+ # @!method mime_type
89
+ # MIME type of response (if any)
90
+ # @return [String, nil]
91
+ def_delegator :content_type, :mime_type
79
92
 
80
- # Charset of response (if any)
81
- #
82
- # @return [String, nil]
83
- def charset
84
- @charset ||= content_type.charset
85
- end
93
+ # @!method charset
94
+ # Charset of response (if any)
95
+ # @return [String, nil]
96
+ def_delegator :content_type, :charset
86
97
 
87
98
  def cookies
88
99
  @cookies ||= headers.each_with_object CookieJar.new do |(k, v), jar|
@@ -9,10 +9,11 @@ module HTTP
9
9
  include Enumerable
10
10
  def_delegator :to_s, :empty?
11
11
 
12
- def initialize(client)
13
- @client = client
14
- @streaming = nil
15
- @contents = nil
12
+ def initialize(client, encoding)
13
+ @client = client
14
+ @streaming = nil
15
+ @contents = nil
16
+ @encoding = encoding
16
17
  end
17
18
 
18
19
  # (see HTTP::Client#readpartial)
@@ -36,9 +37,9 @@ module HTTP
36
37
 
37
38
  begin
38
39
  @streaming = false
39
- @contents = "".force_encoding(Encoding::UTF_8)
40
+ @contents = "".force_encoding(@encoding)
40
41
  while (chunk = @client.readpartial)
41
- @contents << chunk.force_encoding(Encoding::ASCII_8BIT)
42
+ @contents << chunk.force_encoding(@encoding)
42
43
  end
43
44
  rescue
44
45
  @contents = nil
@@ -108,6 +108,7 @@ module HTTP
108
108
  end
109
109
 
110
110
  def __setobj__(obj)
111
+ fail TypeError, "Expected #{obj.inspect} to respond to #to_i" unless obj.respond_to? :to_i
111
112
  @code = obj.to_i
112
113
  end
113
114
 
@@ -18,10 +18,11 @@ module HTTP
18
18
  @total_timeout = time_left
19
19
  end
20
20
 
21
- def connect(socket_class, host, port)
21
+ def connect(socket_class, host, port, nodelay = false)
22
22
  reset_timer
23
23
  ::Timeout.timeout(time_left, TimeoutError) do
24
24
  @socket = socket_class.open(host, port)
25
+ @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) if nodelay
25
26
  end
26
27
 
27
28
  log_time
@@ -14,8 +14,9 @@ module HTTP
14
14
  end
15
15
 
16
16
  # Connects to a socket
17
- def connect(socket_class, host, port)
17
+ def connect(socket_class, host, port, nodelay = false)
18
18
  @socket = socket_class.open(host, port)
19
+ @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) if nodelay
19
20
  end
20
21
 
21
22
  # Starts a SSL connection on a socket
@@ -19,9 +19,10 @@ module HTTP
19
19
  @connect_timeout = options.fetch(:connect_timeout, CONNECT_TIMEOUT)
20
20
  end
21
21
 
22
- def connect(socket_class, host, port)
22
+ def connect(socket_class, host, port, nodelay = false)
23
23
  ::Timeout.timeout(connect_timeout, TimeoutError) do
24
24
  @socket = socket_class.open(host, port)
25
+ @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) if nodelay
25
26
  end
26
27
  end
27
28
 
data/lib/http/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module HTTP
2
- VERSION = "1.0.0.pre1".freeze
2
+ VERSION = "1.0.0.pre2".freeze
3
3
  end
@@ -26,11 +26,18 @@ RSpec.describe HTTP::Client do
26
26
  end
27
27
 
28
28
  def redirect_response(location, status = 302)
29
- HTTP::Response.new(status, "1.1", {"Location" => location}, "")
29
+ HTTP::Response.new(
30
+ :status => status,
31
+ :version => "1.1",
32
+ :headers => {"Location" => location},
33
+ :body => "")
30
34
  end
31
35
 
32
36
  def simple_response(body, status = 200)
33
- HTTP::Response.new(status, "1.1", {}, body)
37
+ HTTP::Response.new(
38
+ :status => status,
39
+ :version => "1.1",
40
+ :body => body)
34
41
  end
35
42
 
36
43
  describe "following redirects" do
@@ -53,8 +53,10 @@ RSpec.describe HTTP::Options, "merge" do
53
53
  :proxy => {:proxy_address => "127.0.0.1", :proxy_port => 8080},
54
54
  :follow => nil,
55
55
  :socket_class => described_class.default_socket_class,
56
+ :nodelay => false,
56
57
  :ssl_socket_class => described_class.default_ssl_socket_class,
57
58
  :ssl_context => nil,
58
- :cookies => {})
59
+ :cookies => {},
60
+ :encoding => nil)
59
61
  end
60
62
  end
@@ -1,6 +1,11 @@
1
1
  RSpec.describe HTTP::Redirector do
2
2
  def simple_response(status, body = "", headers = {})
3
- HTTP::Response.new(status, "1.1", headers, body)
3
+ HTTP::Response.new(
4
+ :status => status,
5
+ :version => "1.1",
6
+ :headers => headers,
7
+ :body => body
8
+ )
4
9
  end
5
10
 
6
11
  def redirect_response(status, location)
@@ -37,7 +37,7 @@ RSpec.describe HTTP::Request::Writer do
37
37
  let(:body) { 123 }
38
38
 
39
39
  it "raises an error" do
40
- expect { writer }.to raise_error
40
+ expect { writer }.to raise_error(HTTP::RequestError)
41
41
  end
42
42
  end
43
43
  end
@@ -59,12 +59,12 @@ RSpec.describe HTTP::Request::Writer do
59
59
 
60
60
  context "when Transfer-Encoding not set" do
61
61
  let(:headers) { HTTP::Headers.new }
62
- specify { expect { writer.stream }.to raise_error }
62
+ specify { expect { writer.stream }.to raise_error(HTTP::RequestError) }
63
63
  end
64
64
 
65
65
  context "when Transfer-Encoding is not chunked" do
66
66
  let(:headers) { HTTP::Headers.coerce "Transfer-Encoding" => "gzip" }
67
- specify { expect { writer.stream }.to raise_error }
67
+ specify { expect { writer.stream }.to raise_error(HTTP::RequestError) }
68
68
  end
69
69
  end
70
70
 
@@ -4,7 +4,7 @@ RSpec.describe HTTP::Response::Body do
4
4
 
5
5
  before { allow(client).to receive(:readpartial) { chunks.shift } }
6
6
 
7
- subject(:body) { described_class.new client }
7
+ subject(:body) { described_class.new client, Encoding::UTF_8 }
8
8
 
9
9
  it "streams bodies from responses" do
10
10
  expect(subject.to_s).to eq "Hello, World!"
@@ -1,7 +1,7 @@
1
1
  RSpec.describe HTTP::Response::Status do
2
2
  describe ".new" do
3
3
  it "fails if given value does not respond to #to_i" do
4
- expect { described_class.new double }.to raise_error
4
+ expect { described_class.new double }.to raise_error TypeError
5
5
  end
6
6
 
7
7
  it "accepts any object that responds to #to_i" do
@@ -2,7 +2,16 @@ RSpec.describe HTTP::Response do
2
2
  let(:body) { "Hello world!" }
3
3
  let(:uri) { "http://example.com/" }
4
4
  let(:headers) { {} }
5
- subject(:response) { HTTP::Response.new 200, "1.1", headers, body, uri }
5
+
6
+ subject(:response) do
7
+ HTTP::Response.new(
8
+ :status => 200,
9
+ :version => "1.1",
10
+ :headers => headers,
11
+ :body => body,
12
+ :uri => uri
13
+ )
14
+ end
6
15
 
7
16
  it "includes HTTP::Headers::Mixin" do
8
17
  expect(described_class).to include HTTP::Headers::Mixin
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+
1
3
  require "json"
2
4
 
3
5
  require "support/dummy_server"
@@ -160,14 +162,36 @@ RSpec.describe HTTP do
160
162
  context "loading binary data" do
161
163
  it "is encoded as bytes" do
162
164
  response = HTTP.get "#{dummy.endpoint}/bytes"
163
- expect(response.to_s.encoding).to eq(Encoding::ASCII_8BIT)
165
+ expect(response.to_s.encoding).to eq(Encoding::BINARY)
166
+ end
167
+ end
168
+
169
+ context "loading endpoint with charset" do
170
+ it "uses charset from headers" do
171
+ response = HTTP.get "#{dummy.endpoint}/iso-8859-1"
172
+ expect(response.to_s.encoding).to eq(Encoding::ISO8859_1)
173
+ expect(response.to_s.encode(Encoding::UTF_8)).to eq("testæ")
174
+ end
175
+
176
+ context "with encoding option" do
177
+ it "respects option" do
178
+ response = HTTP.get "#{dummy.endpoint}/iso-8859-1", "encoding" => Encoding::BINARY
179
+ expect(response.to_s.encoding).to eq(Encoding::BINARY)
180
+ end
164
181
  end
165
182
  end
166
183
 
167
- context "loading text" do
168
- it "is utf-8 encoded" do
184
+ context "passing a string encoding type" do
185
+ it "finds encoding" do
186
+ response = HTTP.get dummy.endpoint, "encoding" => "ascii"
187
+ expect(response.to_s.encoding).to eq(Encoding::ASCII)
188
+ end
189
+ end
190
+
191
+ context "loading text with no charset" do
192
+ it "is binary encoded" do
169
193
  response = HTTP.get dummy.endpoint
170
- expect(response.to_s.encoding).to eq(Encoding::UTF_8)
194
+ expect(response.to_s.encoding).to eq(Encoding::BINARY)
171
195
  end
172
196
  end
173
197
 
@@ -337,5 +361,40 @@ RSpec.describe HTTP do
337
361
  client = HTTP.headers("Cookie" => "foo=bar").cookies(:baz => :moo)
338
362
  expect(client.get(endpoint).to_s).to eq "foo: bar\nbaz: moo"
339
363
  end
364
+
365
+ it "unifies socket errors into HTTP::ConnectionError" do
366
+ expect { HTTP.get "http://thishostshouldnotexists.com" }.to raise_error HTTP::ConnectionError
367
+ expect { HTTP.get "http://127.0.0.1:000" }.to raise_error HTTP::ConnectionError
368
+ end
369
+ end
370
+
371
+ describe ".nodelay" do
372
+ before do
373
+ HTTP.default_options = {:socket_class => socket_spy_class}
374
+ end
375
+
376
+ after do
377
+ HTTP.default_options = {}
378
+ end
379
+
380
+ let(:socket_spy_class) do
381
+ Class.new(TCPSocket) do
382
+ def self.setsockopt_calls
383
+ @setsockopt_calls ||= []
384
+ end
385
+
386
+ def setsockopt(*args)
387
+ self.class.setsockopt_calls << args
388
+ super
389
+ end
390
+ end
391
+ end
392
+
393
+ it "sets TCP_NODELAY on the underlying socket" do
394
+ HTTP.get(dummy.endpoint)
395
+ expect(socket_spy_class.setsockopt_calls).to eq([])
396
+ HTTP.nodelay.get(dummy.endpoint)
397
+ expect(socket_spy_class.setsockopt_calls).to eq([[Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1]])
398
+ end
340
399
  end
341
400
  end
@@ -56,7 +56,7 @@ RSpec.shared_context "handles shared connections" do
56
56
  # rubocop:enable Style/RescueModifier
57
57
 
58
58
  # Should error because we tried to use a bad socket
59
- expect { client.get("#{server.endpoint}/socket").body.to_s }.to raise_error(IOError)
59
+ expect { client.get("#{server.endpoint}/socket").body.to_s }.to raise_error HTTP::ConnectionError
60
60
 
61
61
  # Should succeed since we create a new socket
62
62
  second_socket = client.get("#{server.endpoint}/socket").body.to_s
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+
1
3
  class DummyServer < WEBrick::HTTPServer
2
4
  class Servlet < WEBrick::HTTPServlet::AbstractServlet
3
5
  def self.sockets
@@ -129,6 +131,11 @@ class DummyServer < WEBrick::HTTPServer
129
131
  res.body = bytes.pack("c*")
130
132
  end
131
133
 
134
+ get "/iso-8859-1" do |_req, res|
135
+ res["Content-Type"] = "text/plain; charset=ISO-8859-1"
136
+ res.body = "testæ".encode(Encoding::ISO8859_1)
137
+ end
138
+
132
139
  get "/cookies" do |req, res|
133
140
  res["Set-Cookie"] = "foo=bar"
134
141
  res.body = req.cookies.map { |c| [c.name, c.value].join ": " }.join("\n")
@@ -173,7 +173,7 @@ RSpec.shared_context "HTTP handling" do
173
173
  # rubocop:enable Style/RescueModifier
174
174
 
175
175
  # Should error because we tried to use a bad socket
176
- expect { client.get("#{server.endpoint}/socket").body.to_s }.to raise_error(IOError)
176
+ expect { client.get("#{server.endpoint}/socket").body.to_s }.to raise_error HTTP::ConnectionError
177
177
 
178
178
  # Should succeed since we create a new socket
179
179
  second_socket_id = client.get("#{server.endpoint}/socket").body.to_s
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.0.pre1
4
+ version: 1.0.0.pre2
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: 2015-12-05 00:00:00.000000000 Z
14
+ date: 2015-12-18 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: http_parser.rb
@@ -104,7 +104,6 @@ files:
104
104
  - LICENSE.txt
105
105
  - README.md
106
106
  - Rakefile
107
- - examples/parallel_requests_with_celluloid.rb
108
107
  - http.gemspec
109
108
  - lib/http.rb
110
109
  - lib/http/chainable.rb
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # Example of using the HTTP Gem with Celluloid::IO
4
- # Make sure to 'gem install celluloid-io' before running
5
- #
6
- # Run as: bundle exec examples/parallel_requests_with_celluloid.rb
7
- #
8
-
9
- require "celluloid/io"
10
- require "http"
11
-
12
- class HttpFetcher
13
- include Celluloid::IO
14
-
15
- def fetch(url)
16
- # Note: For SSL support specify:
17
- # ssl_socket_class: Celluloid::IO::SSLSocket
18
- HTTP.get(url, :socket_class => Celluloid::IO::TCPSocket)
19
- end
20
- end
21
-
22
- fetcher = HttpFetcher.new
23
-
24
- urls = %w(http://ruby-lang.org/ http://rubygems.org/ http://celluloid.io/)
25
-
26
- # Kick off a bunch of future calls to HttpFetcher to grab the URLs in parallel
27
- futures = urls.map { |u| [u, fetcher.future.fetch(u)] }
28
-
29
- # Consume the results as they come in
30
- futures.each do |url, future|
31
- # Wait for HttpFetcher#fetch to complete for this request
32
- response = future.value
33
- puts "Got #{url}: #{response.inspect}"
34
- end
35
-
36
- # Suppress Celluloid's shutdown messages
37
- # Otherwise the example is a bit noisy :|
38
- exit!