httpx 0.12.0 → 0.14.1
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/doc/release_notes/0_10_1.md +1 -1
- data/doc/release_notes/0_13_0.md +58 -0
- data/doc/release_notes/0_13_1.md +5 -0
- data/doc/release_notes/0_13_2.md +9 -0
- data/doc/release_notes/0_14_0.md +79 -0
- data/doc/release_notes/0_14_1.md +7 -0
- data/lib/httpx.rb +1 -2
- data/lib/httpx/callbacks.rb +12 -3
- data/lib/httpx/chainable.rb +2 -2
- data/lib/httpx/connection.rb +29 -22
- data/lib/httpx/connection/http1.rb +35 -15
- data/lib/httpx/connection/http2.rb +61 -15
- data/lib/httpx/headers.rb +7 -3
- data/lib/httpx/io/ssl.rb +30 -17
- data/lib/httpx/io/tcp.rb +48 -27
- data/lib/httpx/io/udp.rb +31 -7
- data/lib/httpx/io/unix.rb +27 -12
- data/lib/httpx/options.rb +97 -74
- data/lib/httpx/plugins/aws_sdk_authentication.rb +5 -2
- data/lib/httpx/plugins/aws_sigv4.rb +5 -4
- data/lib/httpx/plugins/basic_authentication.rb +8 -3
- data/lib/httpx/plugins/compression.rb +24 -12
- data/lib/httpx/plugins/compression/brotli.rb +10 -7
- data/lib/httpx/plugins/compression/deflate.rb +6 -5
- data/lib/httpx/plugins/compression/gzip.rb +4 -3
- data/lib/httpx/plugins/cookies.rb +3 -7
- data/lib/httpx/plugins/digest_authentication.rb +5 -5
- data/lib/httpx/plugins/expect.rb +6 -6
- data/lib/httpx/plugins/follow_redirects.rb +4 -4
- data/lib/httpx/plugins/grpc.rb +247 -0
- data/lib/httpx/plugins/grpc/call.rb +62 -0
- data/lib/httpx/plugins/grpc/message.rb +85 -0
- data/lib/httpx/plugins/h2c.rb +43 -58
- data/lib/httpx/plugins/internal_telemetry.rb +1 -1
- data/lib/httpx/plugins/multipart/part.rb +2 -2
- data/lib/httpx/plugins/proxy.rb +3 -7
- data/lib/httpx/plugins/proxy/http.rb +5 -4
- data/lib/httpx/plugins/proxy/ssh.rb +3 -3
- data/lib/httpx/plugins/rate_limiter.rb +1 -1
- data/lib/httpx/plugins/retries.rb +14 -15
- data/lib/httpx/plugins/stream.rb +99 -75
- data/lib/httpx/plugins/upgrade.rb +84 -0
- data/lib/httpx/plugins/upgrade/h2.rb +54 -0
- data/lib/httpx/pool.rb +14 -5
- data/lib/httpx/request.rb +25 -2
- data/lib/httpx/resolver/native.rb +7 -3
- data/lib/httpx/response.rb +9 -5
- data/lib/httpx/session.rb +17 -7
- data/lib/httpx/transcoder/chunker.rb +1 -1
- data/lib/httpx/version.rb +1 -1
- data/sig/callbacks.rbs +2 -0
- data/sig/chainable.rbs +2 -1
- data/sig/connection/http1.rbs +6 -1
- data/sig/connection/http2.rbs +6 -2
- data/sig/headers.rbs +2 -2
- data/sig/options.rbs +16 -22
- data/sig/plugins/aws_sdk_authentication.rbs +2 -0
- data/sig/plugins/aws_sigv4.rbs +0 -1
- data/sig/plugins/basic_authentication.rbs +2 -0
- data/sig/plugins/compression.rbs +7 -5
- data/sig/plugins/compression/brotli.rbs +1 -1
- data/sig/plugins/compression/deflate.rbs +1 -1
- data/sig/plugins/compression/gzip.rbs +1 -1
- data/sig/plugins/cookies.rbs +0 -1
- data/sig/plugins/digest_authentication.rbs +0 -1
- data/sig/plugins/expect.rbs +0 -2
- data/sig/plugins/follow_redirects.rbs +0 -2
- data/sig/plugins/h2c.rbs +5 -10
- data/sig/plugins/persistent.rbs +0 -1
- data/sig/plugins/proxy.rbs +0 -1
- data/sig/plugins/retries.rbs +0 -4
- data/sig/plugins/stream.rbs +17 -16
- data/sig/plugins/upgrade.rbs +23 -0
- data/sig/request.rbs +7 -2
- data/sig/response.rbs +4 -1
- data/sig/session.rbs +4 -0
- metadata +21 -7
- data/lib/httpx/timeout.rb +0 -67
- data/sig/timeout.rbs +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbedc26fba4c0d9a8e0543b437ada103b42bbd89d537a50546590adb2f004d04
|
4
|
+
data.tar.gz: 6645eeb893ed1f07a8e7c7c86db73c0ff2d49f01c63e52888d7da868b925bcdc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ea37e203901dbae07960c12023cbeb2b3ee62ea461a265ab3dff8687b8874e33cf3bf0bbf62df30243030ce9420317bf635e5df1102cfa9a8503ec09949ca3c
|
7
|
+
data.tar.gz: 3515498ac93ca1ef5f165754e8caa95dbddf8aebe079b0efbf8d5a7a78a778d76a4812e4beeddc723dd6fb81dafa4a47c7ae9cb2463834ebd5cf7812ef30a45c
|
data/doc/release_notes/0_10_1.md
CHANGED
@@ -26,7 +26,7 @@ From now on, both headers and the responnse payload will also appear, so expecte
|
|
26
26
|
## Bugfixes
|
27
27
|
|
28
28
|
* HTTP/2 and HTTP/1.1 exhausted connections now get properly migrated into a new connection;
|
29
|
-
* HTTP/2 421 responses will now correctly migrate the connection and
|
29
|
+
* HTTP/2 421 responses will now correctly migrate the connection and pending requests to HTTP/1.1 (a hanging loop was being caused);
|
30
30
|
* HTTP/2 connection failed with a GOAWAY settings timeout will now return error responses (instead of hanging indefinitely);
|
31
31
|
* Non-IP proxy name-resolving errors will now move on to the next available proxy in the list (instead of hanging indefinitely);
|
32
32
|
* Non-IP DNS resolve errors for `native` and `https` variants will now return the appropriate error response (instead of hanging indefinitely);
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# 0.13.0
|
2
|
+
|
3
|
+
## Features
|
4
|
+
|
5
|
+
### Upgrade plugin
|
6
|
+
|
7
|
+
A new plugin, `:upgrade`, is now available. This plugin allows one to "hook" on HTTP/1.1's protocol upgrade mechanism (see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism), which is the mechanism that browsers use to initiate websockets (there is an example of how to use `httpx` to start a websocket client connection [in the tests](https://gitlab.com/honeyryderchuck/httpx/-/blob/master/test/support/requests/plugins/upgrade.rb))
|
8
|
+
|
9
|
+
You can read more about the `:upgrade` plugin in the [wiki](https://honeyryderchuck.gitlab.io/httpx/wiki/Connection-Upgrade).
|
10
|
+
|
11
|
+
It's the basis of two plugins:
|
12
|
+
|
13
|
+
#### `:h2c`
|
14
|
+
|
15
|
+
This plugin was been rewritten on top of the `:upgrade` plugin, and handles upgrading a plaintext (non-"https") HTTP/1.1 connection, into an HTTP/2 connection.
|
16
|
+
|
17
|
+
https://honeyryderchuck.gitlab.io/httpx/wiki/Connection-Upgrade#h2c
|
18
|
+
|
19
|
+
#### `:upgrade/h2`
|
20
|
+
|
21
|
+
This plugin handles when a server responds to a request with an `Upgrade: h2` header, does the following requests to the same origin via HTTP/2 prior knowledge (bypassing the necessity for ALPN negotiation, which is the whole point of the feature).
|
22
|
+
|
23
|
+
https://honeyryderchuck.gitlab.io/httpx/wiki/Connection-Upgrade#h2
|
24
|
+
|
25
|
+
### `:addresses` option
|
26
|
+
|
27
|
+
The `:addresses` option is now available. You can use it to pass a list of IPs to connect to:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
# will not resolve example.com, and instead connect to one of the IPs passed.
|
31
|
+
HTTPX.get("http://example.com", addresses: %w[172.5.3.1 172.5.3.2]))
|
32
|
+
```
|
33
|
+
|
34
|
+
You should also use it to connect to HTTP servers bound to a UNIX socket, in which case you'll have to provide a path:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
HTTPX.get("http://example.com", addresses: %w[/path/to/usocket]))
|
38
|
+
```
|
39
|
+
|
40
|
+
The `:transport_options` are therefore deprecated, and will be moved in a major version.
|
41
|
+
|
42
|
+
## Improvements
|
43
|
+
|
44
|
+
Some internal improvements that allow certain plugins not to "leak" globally, such as the `:compression` plugin, which used to enable compression for all the `httpx` sessions from the same process. It doesn't anymore.
|
45
|
+
|
46
|
+
Using exceptionless nonblocking connect calls in the supported rubies.
|
47
|
+
|
48
|
+
Removed unneeded APIs around the Options object (`with_` methods, or the defined options list).
|
49
|
+
|
50
|
+
## Bugfixes
|
51
|
+
|
52
|
+
HTTP/1.1 persistent connections were closing after each request after the max requests was reached. It's fixed, and the new connection will also be persistent.
|
53
|
+
|
54
|
+
When passing open IO objects for origins (the `:io` option), `httpx` was still trying to resolve the origin's domain. This not only didn't make sense, it broke if the domain is unresolvable. It has been fixed.
|
55
|
+
|
56
|
+
Fixed usage of `:io` option when passed an "authority/io" hash.
|
57
|
+
|
58
|
+
Fixing some issues around trying to connnect to the next available IPAddress when the previous one was unreachable or ETIMEDOUT.
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# 0.13.1
|
2
|
+
|
3
|
+
## Improvements
|
4
|
+
|
5
|
+
`UDPSocket#sendmsg_nonblock` is now used in the native resolver.
|
6
|
+
|
7
|
+
## Bugfixes
|
8
|
+
|
9
|
+
Usage in Windows was buggy, resulting in `Errno::EINVAL` during DNS resolving, when using the native resolver. This was due to a discrepancy between `recvfrom` behaviour in WS Sockets and Linux Sockets. This was fixed by making we the UDP socket never tries to receive before a DNS query has been actually sent.
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# 0.14.0
|
2
|
+
|
3
|
+
## Features
|
4
|
+
|
5
|
+
### GRPC plugin
|
6
|
+
|
7
|
+
A new plugin, `:grpc`, is now available. This plugin provides a simple DSL to build GRPC services and performing calls using `httpx` under the hood.
|
8
|
+
|
9
|
+
Example:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
require "httpx"
|
13
|
+
|
14
|
+
grpc = HTTPX.plugin(:grpc)
|
15
|
+
helloworld_stub = grpc.build_stub("localhost:4545")
|
16
|
+
helloworld_svc = helloworld_stub.rpc(:SayHello, HelloRequest, HelloReply)
|
17
|
+
result = helloworld_svc.say_hello(HelloRequest.new(name: "Jack")) #=> HelloReply: "Hello Jack"
|
18
|
+
```
|
19
|
+
|
20
|
+
You can read more about the `:grpc` plugin in the [wiki](https://honeyryderchuck.gitlab.io/httpx/wiki/GRPC).
|
21
|
+
|
22
|
+
### :origin
|
23
|
+
|
24
|
+
A new `:origin` option is available. You can use it for setting a base URL for subsequent relative paths on that session:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
HTTPX.get("/httpbin/get") #=> HTTPX::Error: invalid URI: /httpbin/get
|
28
|
+
|
29
|
+
httpbin = HTTPX.with(origin: "https://nghttp2.org")
|
30
|
+
httpbin.get("/httpbin/get") #=> #<Response:5420 HTTP/2.0 @status=200 ....
|
31
|
+
```
|
32
|
+
|
33
|
+
**Note!** The origin is **not** for setting base paths, i.e. if you pass it a relative path, it'll be filtered out in subsequent requests (`HTTPX.with(origin: "https://nghttp2.org/httpbin")` will still use only `"https://nghttp2.org"`).
|
34
|
+
|
35
|
+
## Improvements
|
36
|
+
|
37
|
+
* setting an unexpected option will now raise an `HTTPX::Error` with an helpful message, instead of a confusing `NoMethodError`:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
HTTPX.with(foo: "bar")
|
41
|
+
# before
|
42
|
+
#=> NoMethodError
|
43
|
+
# after
|
44
|
+
#=> HTTPX::Error: unknown option: foo
|
45
|
+
|
46
|
+
```
|
47
|
+
|
48
|
+
* `HTTPX::Options#def_option` (which can be used for setting custom plugin options) can now be passed a full body string (where the argument is `value`), although it still support the block form. This is the recommended approach, as the block form is based on `define_method`, which would make clients unusable inside ractors.
|
49
|
+
|
50
|
+
* Added support for `:wait_for_handshake` under the `http2_settings` option (`false` by default). HTTP/2 connections complete the protocol handshake before requests are sent. When this option is `true`, requests get send in the initial payload, before the HTTP/2 connection is fully acknowledged.
|
51
|
+
|
52
|
+
* 441716a5ac0f7707211ebe0048f568cf0b759c3f: The `:stream` plugin has been improved to start streaming the real response as methods are called (instead of a completely separate synchronous one, which is definitely not good):
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
session = HTTPX.plugin(:stream)
|
56
|
+
response = session.get(build_uri("/stream/3"), stream: true)
|
57
|
+
|
58
|
+
# before
|
59
|
+
response.status # this could block indefinitely, if the request truly streams infinitely.
|
60
|
+
|
61
|
+
# after
|
62
|
+
response.status # sends the request, and starts streaming the response until status is available.
|
63
|
+
response.each {|chunk|...} # and now you can start yielding the chunks...
|
64
|
+
```
|
65
|
+
|
66
|
+
|
67
|
+
## Bugfixes
|
68
|
+
|
69
|
+
* fixed usage of the `:multipart` if `pathname` isn't loaded.
|
70
|
+
* fixed HTTP/2 trailers.
|
71
|
+
* fixed connection merges with the same origin, which was causing them to be duplicated and breaking further usage. (#125)
|
72
|
+
* fixed repeated session callbacks on a connection, by ensure they're set only once.
|
73
|
+
* fixed calculation of `content-length` for streaming or chunked compressed requests.
|
74
|
+
|
75
|
+
|
76
|
+
## Chore
|
77
|
+
|
78
|
+
* using ruby base container images in CI instead.
|
79
|
+
* using truffleruby official container image.
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# 0.14.0
|
2
|
+
|
3
|
+
|
4
|
+
## Bugfixes
|
5
|
+
|
6
|
+
* fixed: HTTP/2-specific headers were being reused on insecure redirects, thereby creating an invalid request (#128);
|
7
|
+
* fixed: multipart request parts weren't using explicity set `:content_type`, instead using file mime type or "text/plain";
|
data/lib/httpx.rb
CHANGED
@@ -12,12 +12,11 @@ require "httpx/callbacks"
|
|
12
12
|
require "httpx/loggable"
|
13
13
|
require "httpx/registry"
|
14
14
|
require "httpx/transcoder"
|
15
|
-
require "httpx/options"
|
16
|
-
require "httpx/timeout"
|
17
15
|
require "httpx/pool"
|
18
16
|
require "httpx/headers"
|
19
17
|
require "httpx/request"
|
20
18
|
require "httpx/response"
|
19
|
+
require "httpx/options"
|
21
20
|
require "httpx/chainable"
|
22
21
|
|
23
22
|
# Top-Level Namespace
|
data/lib/httpx/callbacks.rb
CHANGED
@@ -6,19 +6,28 @@ module HTTPX
|
|
6
6
|
callbacks(type) << action
|
7
7
|
end
|
8
8
|
|
9
|
-
def once(
|
10
|
-
on(
|
9
|
+
def once(type, &block)
|
10
|
+
on(type) do |*args, &callback|
|
11
11
|
block.call(*args, &callback)
|
12
12
|
:delete
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
def only(type, &block)
|
17
|
+
callbacks(type).clear
|
18
|
+
on(type, &block)
|
19
|
+
end
|
20
|
+
|
16
21
|
def emit(type, *args)
|
17
|
-
callbacks(type).delete_if { |pr| pr[*args]
|
22
|
+
callbacks(type).delete_if { |pr| :delete == pr[*args] } # rubocop:disable Style/YodaCondition
|
18
23
|
end
|
19
24
|
|
20
25
|
protected
|
21
26
|
|
27
|
+
def callbacks_for?(type)
|
28
|
+
@callbacks.key?(type) && !@callbacks[type].empty?
|
29
|
+
end
|
30
|
+
|
22
31
|
def callbacks(type = nil)
|
23
32
|
return @callbacks unless type
|
24
33
|
|
data/lib/httpx/chainable.rb
CHANGED
@@ -17,12 +17,12 @@ module HTTPX
|
|
17
17
|
# :nocov:
|
18
18
|
def timeout(**args)
|
19
19
|
warn ":#{__method__} is deprecated, use :with_timeout instead"
|
20
|
-
|
20
|
+
with(timeout: args)
|
21
21
|
end
|
22
22
|
|
23
23
|
def headers(headers)
|
24
24
|
warn ":#{__method__} is deprecated, use :with_headers instead"
|
25
|
-
|
25
|
+
with(headers: headers)
|
26
26
|
end
|
27
27
|
# :nocov:
|
28
28
|
|
data/lib/httpx/connection.rb
CHANGED
@@ -69,8 +69,10 @@ module HTTPX
|
|
69
69
|
end
|
70
70
|
|
71
71
|
@inflight = 0
|
72
|
-
@keep_alive_timeout = options.timeout
|
72
|
+
@keep_alive_timeout = options.timeout[:keep_alive_timeout]
|
73
73
|
@keep_alive_timer = nil
|
74
|
+
|
75
|
+
self.addresses = options.addresses if options.addresses
|
74
76
|
end
|
75
77
|
|
76
78
|
# this is a semi-private method, to be used by the resolver
|
@@ -105,6 +107,8 @@ module HTTPX
|
|
105
107
|
|
106
108
|
return false if exhausted?
|
107
109
|
|
110
|
+
return false unless connection.addresses
|
111
|
+
|
108
112
|
!(@io.addresses & connection.addresses).empty? && @options == connection.options
|
109
113
|
end
|
110
114
|
|
@@ -125,7 +129,7 @@ module HTTPX
|
|
125
129
|
end
|
126
130
|
|
127
131
|
def merge(connection)
|
128
|
-
@origins
|
132
|
+
@origins |= connection.instance_variable_get(:@origins)
|
129
133
|
connection.purge_pending do |req|
|
130
134
|
send(req)
|
131
135
|
end
|
@@ -234,9 +238,9 @@ module HTTPX
|
|
234
238
|
def timeout
|
235
239
|
return @timeout if defined?(@timeout)
|
236
240
|
|
237
|
-
return @options.timeout
|
241
|
+
return @options.timeout[:connect_timeout] if @state == :idle
|
238
242
|
|
239
|
-
@options.timeout
|
243
|
+
@options.timeout[:operation_timeout]
|
240
244
|
end
|
241
245
|
|
242
246
|
private
|
@@ -409,7 +413,7 @@ module HTTPX
|
|
409
413
|
emit(:exhausted)
|
410
414
|
end
|
411
415
|
parser.on(:origin) do |origin|
|
412
|
-
@origins
|
416
|
+
@origins |= [origin]
|
413
417
|
end
|
414
418
|
parser.on(:close) do |force|
|
415
419
|
transition(:closing)
|
@@ -439,6 +443,7 @@ module HTTPX
|
|
439
443
|
emit(:misdirected, request)
|
440
444
|
else
|
441
445
|
response = ErrorResponse.new(request, ex, @options)
|
446
|
+
request.response = response
|
442
447
|
request.emit(:response, response)
|
443
448
|
end
|
444
449
|
end
|
@@ -447,7 +452,7 @@ module HTTPX
|
|
447
452
|
def transition(nextstate)
|
448
453
|
case nextstate
|
449
454
|
when :idle
|
450
|
-
@timeout = @current_timeout = @options.timeout
|
455
|
+
@timeout = @current_timeout = @options.timeout[:connect_timeout]
|
451
456
|
|
452
457
|
when :open
|
453
458
|
return if @state == :closed
|
@@ -459,7 +464,7 @@ module HTTPX
|
|
459
464
|
|
460
465
|
send_pending
|
461
466
|
|
462
|
-
@timeout = @current_timeout = @options.timeout
|
467
|
+
@timeout = @current_timeout = @options.timeout[:operation_timeout]
|
463
468
|
emit(:open)
|
464
469
|
when :closing
|
465
470
|
return unless @state == :open
|
@@ -472,26 +477,15 @@ module HTTPX
|
|
472
477
|
remove_instance_variable(:@total_timeout)
|
473
478
|
end
|
474
479
|
|
475
|
-
|
476
|
-
@read_buffer.clear
|
477
|
-
if @keep_alive_timer
|
478
|
-
@keep_alive_timer.cancel
|
479
|
-
remove_instance_variable(:@keep_alive_timer)
|
480
|
-
end
|
481
|
-
|
482
|
-
remove_instance_variable(:@timeout) if defined?(@timeout)
|
480
|
+
purge_after_closed
|
483
481
|
when :already_open
|
484
482
|
nextstate = :open
|
485
483
|
send_pending
|
486
484
|
end
|
487
485
|
@state = nextstate
|
488
|
-
rescue Errno::EHOSTUNREACH
|
489
|
-
# at this point, all addresses from the IO object have failed
|
490
|
-
reset
|
491
|
-
emit(:unreachable)
|
492
|
-
throw(:jump_tick)
|
493
486
|
rescue Errno::ECONNREFUSED,
|
494
487
|
Errno::EADDRNOTAVAIL,
|
488
|
+
Errno::EHOSTUNREACH,
|
495
489
|
TLSError => e
|
496
490
|
# connect errors, exit gracefully
|
497
491
|
handle_error(e)
|
@@ -499,6 +493,17 @@ module HTTPX
|
|
499
493
|
emit(:close)
|
500
494
|
end
|
501
495
|
|
496
|
+
def purge_after_closed
|
497
|
+
@io.close if @io
|
498
|
+
@read_buffer.clear
|
499
|
+
if @keep_alive_timer
|
500
|
+
@keep_alive_timer.cancel
|
501
|
+
remove_instance_variable(:@keep_alive_timer)
|
502
|
+
end
|
503
|
+
|
504
|
+
remove_instance_variable(:@timeout) if defined?(@timeout)
|
505
|
+
end
|
506
|
+
|
502
507
|
def handle_response
|
503
508
|
@inflight -= 1
|
504
509
|
return unless @inflight.zero?
|
@@ -538,12 +543,14 @@ module HTTPX
|
|
538
543
|
def handle_error(error)
|
539
544
|
parser.handle_error(error) if @parser && parser.respond_to?(:handle_error)
|
540
545
|
while (request = @pending.shift)
|
541
|
-
|
546
|
+
response = ErrorResponse.new(request, error, @options)
|
547
|
+
request.response = response
|
548
|
+
request.emit(:response, response)
|
542
549
|
end
|
543
550
|
end
|
544
551
|
|
545
552
|
def total_timeout
|
546
|
-
total = @options.timeout
|
553
|
+
total = @options.timeout[:total_timeout]
|
547
554
|
|
548
555
|
return unless total
|
549
556
|
|
@@ -10,7 +10,7 @@ module HTTPX
|
|
10
10
|
MAX_REQUESTS = 100
|
11
11
|
CRLF = "\r\n"
|
12
12
|
|
13
|
-
attr_reader :pending
|
13
|
+
attr_reader :pending, :requests
|
14
14
|
|
15
15
|
def initialize(buffer, options)
|
16
16
|
@options = Options.new(options)
|
@@ -69,7 +69,6 @@ module HTTPX
|
|
69
69
|
|
70
70
|
return if @requests.include?(request)
|
71
71
|
|
72
|
-
request.once(:headers, &method(:set_protocol_headers))
|
73
72
|
@requests << request
|
74
73
|
@pipelining = true if @requests.size > 1
|
75
74
|
end
|
@@ -236,6 +235,8 @@ module HTTPX
|
|
236
235
|
|
237
236
|
def disable_pipelining
|
238
237
|
return if @requests.empty?
|
238
|
+
# do not disable pipelining if already set to 1 request at a time
|
239
|
+
return if @max_concurrent_requests == 1
|
239
240
|
|
240
241
|
@requests.each do |r|
|
241
242
|
r.transition(:idle)
|
@@ -253,12 +254,15 @@ module HTTPX
|
|
253
254
|
end
|
254
255
|
|
255
256
|
def set_protocol_headers(request)
|
256
|
-
request.headers["host"] ||= request.authority
|
257
|
-
request.headers["connection"] ||= request.options.persistent ? "keep-alive" : "close"
|
258
257
|
if !request.headers.key?("content-length") &&
|
259
258
|
request.body.bytesize == Float::INFINITY
|
260
259
|
request.chunk!
|
261
260
|
end
|
261
|
+
|
262
|
+
{
|
263
|
+
"host" => (request.headers["host"] || request.authority),
|
264
|
+
"connection" => (request.headers["connection"] || (request.options.persistent ? "keep-alive" : "close")),
|
265
|
+
}
|
262
266
|
end
|
263
267
|
|
264
268
|
def headline_uri(request)
|
@@ -271,22 +275,18 @@ module HTTPX
|
|
271
275
|
join_headers(request) if request.state == :headers
|
272
276
|
request.transition(:body)
|
273
277
|
join_body(request) if request.state == :body
|
278
|
+
request.transition(:trailers)
|
279
|
+
# HTTP/1.1 trailers should only work for chunked encoding
|
280
|
+
join_trailers(request) if request.body.chunked? && request.state == :trailers
|
274
281
|
request.transition(:done)
|
275
282
|
end
|
276
283
|
end
|
277
284
|
|
278
285
|
def join_headers(request)
|
279
|
-
buffer
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
buffer.clear
|
284
|
-
request.headers.each do |field, value|
|
285
|
-
buffer << "#{capitalized(field)}: #{value}" << CRLF
|
286
|
-
log(color: :yellow) { "<- HEADER: #{buffer.chomp}" }
|
287
|
-
@buffer << buffer
|
288
|
-
buffer.clear
|
289
|
-
end
|
286
|
+
@buffer << "#{request.verb.to_s.upcase} #{headline_uri(request)} HTTP/#{@version.join(".")}" << CRLF
|
287
|
+
log(color: :yellow) { "<- HEADLINE: #{@buffer.to_s.chomp.inspect}" }
|
288
|
+
extra_headers = set_protocol_headers(request)
|
289
|
+
join_headers2(request.headers.each(extra_headers))
|
290
290
|
log { "<- " }
|
291
291
|
@buffer << CRLF
|
292
292
|
end
|
@@ -300,6 +300,26 @@ module HTTPX
|
|
300
300
|
@buffer << chunk
|
301
301
|
throw(:buffer_full, request) if @buffer.full?
|
302
302
|
end
|
303
|
+
|
304
|
+
raise request.drain_error if request.drain_error
|
305
|
+
end
|
306
|
+
|
307
|
+
def join_trailers(request)
|
308
|
+
return unless request.trailers? && request.callbacks_for?(:trailers)
|
309
|
+
|
310
|
+
join_headers2(request.trailers)
|
311
|
+
log { "<- " }
|
312
|
+
@buffer << CRLF
|
313
|
+
end
|
314
|
+
|
315
|
+
def join_headers2(headers)
|
316
|
+
buffer = "".b
|
317
|
+
headers.each do |field, value|
|
318
|
+
buffer << "#{capitalized(field)}: #{value}" << CRLF
|
319
|
+
log(color: :yellow) { "<- HEADER: #{buffer.chomp}" }
|
320
|
+
@buffer << buffer
|
321
|
+
buffer.clear
|
322
|
+
end
|
303
323
|
end
|
304
324
|
|
305
325
|
UPCASED = {
|