httpx 0.13.2 → 0.14.0
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 +2 -2
- data/doc/release_notes/0_13_1.md +1 -1
- data/doc/release_notes/0_14_0.md +79 -0
- data/lib/httpx.rb +1 -2
- data/lib/httpx/callbacks.rb +12 -3
- data/lib/httpx/connection.rb +12 -9
- data/lib/httpx/connection/http1.rb +26 -11
- data/lib/httpx/connection/http2.rb +52 -8
- data/lib/httpx/headers.rb +1 -1
- data/lib/httpx/io/tcp.rb +1 -1
- data/lib/httpx/options.rb +91 -56
- data/lib/httpx/plugins/aws_sdk_authentication.rb +5 -2
- data/lib/httpx/plugins/aws_sigv4.rb +4 -4
- data/lib/httpx/plugins/basic_authentication.rb +8 -3
- data/lib/httpx/plugins/compression.rb +8 -8
- data/lib/httpx/plugins/compression/brotli.rb +4 -3
- data/lib/httpx/plugins/compression/deflate.rb +4 -3
- data/lib/httpx/plugins/compression/gzip.rb +2 -1
- data/lib/httpx/plugins/cookies.rb +3 -7
- data/lib/httpx/plugins/digest_authentication.rb +4 -4
- data/lib/httpx/plugins/expect.rb +6 -6
- data/lib/httpx/plugins/follow_redirects.rb +3 -3
- 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/multipart/part.rb +1 -1
- data/lib/httpx/plugins/proxy.rb +3 -7
- data/lib/httpx/plugins/proxy/ssh.rb +3 -3
- data/lib/httpx/plugins/rate_limiter.rb +1 -1
- data/lib/httpx/plugins/retries.rb +13 -14
- data/lib/httpx/plugins/stream.rb +96 -74
- data/lib/httpx/plugins/upgrade.rb +4 -4
- data/lib/httpx/request.rb +25 -2
- data/lib/httpx/response.rb +4 -0
- 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/connection/http1.rbs +4 -0
- data/sig/connection/http2.rbs +5 -1
- data/sig/options.rbs +9 -2
- data/sig/plugins/aws_sdk_authentication.rbs +2 -0
- data/sig/plugins/basic_authentication.rbs +2 -0
- data/sig/plugins/compression.rbs +2 -2
- data/sig/plugins/stream.rbs +17 -16
- data/sig/request.rbs +7 -2
- data/sig/response.rbs +1 -0
- data/sig/session.rbs +4 -0
- metadata +38 -35
- 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: abbeaccc55115244f08e7b39aaad174a34dd2e7aeb10b32cdc0563fbefe1b953
|
4
|
+
data.tar.gz: a39fc4e5644b21c1265840011e969c36904756573584cba0f805d568a549ec94
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82fa475dcd9ef05ebe90f0b3c742c17c33185410a70eb5af730fce393681b7f9f346decf78349614f77b76257550c0e3056e61f3b5d6cd5efdba0149eff235f6
|
7
|
+
data.tar.gz: 64ceb596415b440c99c9df31569fa0ee2f7c94e51787d5e0d84141f1ade0be92e23e2d7011a361c1366b43c4f159525599367009bd4021c358537f11c4605cac
|
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);
|
data/doc/release_notes/0_13_0.md
CHANGED
@@ -41,7 +41,7 @@ The `:transport_options` are therefore deprecated, and will be moved in a major
|
|
41
41
|
|
42
42
|
## Improvements
|
43
43
|
|
44
|
-
Some internal improvements that allow
|
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
45
|
|
46
46
|
Using exceptionless nonblocking connect calls in the supported rubies.
|
47
47
|
|
@@ -55,4 +55,4 @@ When passing open IO objects for origins (the `:io` option), `httpx` was still t
|
|
55
55
|
|
56
56
|
Fixed usage of `:io` option when passed an "authority/io" hash.
|
57
57
|
|
58
|
-
Fixing some issues around trying to connnect to the next available IPAddress when the previous one was unreachable or ETIMEDOUT.
|
58
|
+
Fixing some issues around trying to connnect to the next available IPAddress when the previous one was unreachable or ETIMEDOUT.
|
data/doc/release_notes/0_13_1.md
CHANGED
@@ -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.
|
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/connection.rb
CHANGED
@@ -69,7 +69,7 @@ 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
74
|
|
75
75
|
self.addresses = options.addresses if options.addresses
|
@@ -129,7 +129,7 @@ module HTTPX
|
|
129
129
|
end
|
130
130
|
|
131
131
|
def merge(connection)
|
132
|
-
@origins
|
132
|
+
@origins |= connection.instance_variable_get(:@origins)
|
133
133
|
connection.purge_pending do |req|
|
134
134
|
send(req)
|
135
135
|
end
|
@@ -238,9 +238,9 @@ module HTTPX
|
|
238
238
|
def timeout
|
239
239
|
return @timeout if defined?(@timeout)
|
240
240
|
|
241
|
-
return @options.timeout
|
241
|
+
return @options.timeout[:connect_timeout] if @state == :idle
|
242
242
|
|
243
|
-
@options.timeout
|
243
|
+
@options.timeout[:operation_timeout]
|
244
244
|
end
|
245
245
|
|
246
246
|
private
|
@@ -413,7 +413,7 @@ module HTTPX
|
|
413
413
|
emit(:exhausted)
|
414
414
|
end
|
415
415
|
parser.on(:origin) do |origin|
|
416
|
-
@origins
|
416
|
+
@origins |= [origin]
|
417
417
|
end
|
418
418
|
parser.on(:close) do |force|
|
419
419
|
transition(:closing)
|
@@ -443,6 +443,7 @@ module HTTPX
|
|
443
443
|
emit(:misdirected, request)
|
444
444
|
else
|
445
445
|
response = ErrorResponse.new(request, ex, @options)
|
446
|
+
request.response = response
|
446
447
|
request.emit(:response, response)
|
447
448
|
end
|
448
449
|
end
|
@@ -451,7 +452,7 @@ module HTTPX
|
|
451
452
|
def transition(nextstate)
|
452
453
|
case nextstate
|
453
454
|
when :idle
|
454
|
-
@timeout = @current_timeout = @options.timeout
|
455
|
+
@timeout = @current_timeout = @options.timeout[:connect_timeout]
|
455
456
|
|
456
457
|
when :open
|
457
458
|
return if @state == :closed
|
@@ -463,7 +464,7 @@ module HTTPX
|
|
463
464
|
|
464
465
|
send_pending
|
465
466
|
|
466
|
-
@timeout = @current_timeout = @options.timeout
|
467
|
+
@timeout = @current_timeout = @options.timeout[:operation_timeout]
|
467
468
|
emit(:open)
|
468
469
|
when :closing
|
469
470
|
return unless @state == :open
|
@@ -542,12 +543,14 @@ module HTTPX
|
|
542
543
|
def handle_error(error)
|
543
544
|
parser.handle_error(error) if @parser && parser.respond_to?(:handle_error)
|
544
545
|
while (request = @pending.shift)
|
545
|
-
|
546
|
+
response = ErrorResponse.new(request, error, @options)
|
547
|
+
request.response = response
|
548
|
+
request.emit(:response, response)
|
546
549
|
end
|
547
550
|
end
|
548
551
|
|
549
552
|
def total_timeout
|
550
|
-
total = @options.timeout
|
553
|
+
total = @options.timeout[:total_timeout]
|
551
554
|
|
552
555
|
return unless total
|
553
556
|
|
@@ -272,23 +272,18 @@ module HTTPX
|
|
272
272
|
join_headers(request) if request.state == :headers
|
273
273
|
request.transition(:body)
|
274
274
|
join_body(request) if request.state == :body
|
275
|
+
request.transition(:trailers)
|
276
|
+
# HTTP/1.1 trailers should only work for chunked encoding
|
277
|
+
join_trailers(request) if request.body.chunked? && request.state == :trailers
|
275
278
|
request.transition(:done)
|
276
279
|
end
|
277
280
|
end
|
278
281
|
|
279
282
|
def join_headers(request)
|
280
|
-
buffer
|
281
|
-
|
282
|
-
log(color: :yellow) { "<- HEADLINE: #{buffer.chomp.inspect}" }
|
283
|
-
@buffer << buffer
|
284
|
-
buffer.clear
|
283
|
+
@buffer << "#{request.verb.to_s.upcase} #{headline_uri(request)} HTTP/#{@version.join(".")}" << CRLF
|
284
|
+
log(color: :yellow) { "<- HEADLINE: #{@buffer.to_s.chomp.inspect}" }
|
285
285
|
set_protocol_headers(request)
|
286
|
-
request.headers
|
287
|
-
buffer << "#{capitalized(field)}: #{value}" << CRLF
|
288
|
-
log(color: :yellow) { "<- HEADER: #{buffer.chomp}" }
|
289
|
-
@buffer << buffer
|
290
|
-
buffer.clear
|
291
|
-
end
|
286
|
+
join_headers2(request.headers)
|
292
287
|
log { "<- " }
|
293
288
|
@buffer << CRLF
|
294
289
|
end
|
@@ -302,6 +297,26 @@ module HTTPX
|
|
302
297
|
@buffer << chunk
|
303
298
|
throw(:buffer_full, request) if @buffer.full?
|
304
299
|
end
|
300
|
+
|
301
|
+
raise request.drain_error if request.drain_error
|
302
|
+
end
|
303
|
+
|
304
|
+
def join_trailers(request)
|
305
|
+
return unless request.trailers? && request.callbacks_for?(:trailers)
|
306
|
+
|
307
|
+
join_headers2(request.trailers)
|
308
|
+
log { "<- " }
|
309
|
+
@buffer << CRLF
|
310
|
+
end
|
311
|
+
|
312
|
+
def join_headers2(headers)
|
313
|
+
buffer = "".b
|
314
|
+
headers.each do |field, value|
|
315
|
+
buffer << "#{capitalized(field)}: #{value}" << CRLF
|
316
|
+
log(color: :yellow) { "<- HEADER: #{buffer.chomp}" }
|
317
|
+
@buffer << buffer
|
318
|
+
buffer.clear
|
319
|
+
end
|
305
320
|
end
|
306
321
|
|
307
322
|
UPCASED = {
|
@@ -21,14 +21,16 @@ module HTTPX
|
|
21
21
|
|
22
22
|
def initialize(buffer, options)
|
23
23
|
@options = Options.new(options)
|
24
|
-
@
|
25
|
-
@max_requests = @options.max_requests || 0
|
24
|
+
@settings = @options.http2_settings
|
26
25
|
@pending = []
|
27
26
|
@streams = {}
|
28
27
|
@drains = {}
|
29
28
|
@pings = []
|
30
29
|
@buffer = buffer
|
31
30
|
@handshake_completed = false
|
31
|
+
@wait_for_handshake = @settings.key?(:wait_for_handshake) ? @settings.delete(:wait_for_handshake) : true
|
32
|
+
@max_concurrent_requests = @options.max_concurrent_requests || MAX_CONCURRENT_REQUESTS
|
33
|
+
@max_requests = @options.max_requests || 0
|
32
34
|
init_connection
|
33
35
|
end
|
34
36
|
|
@@ -36,7 +38,11 @@ module HTTPX
|
|
36
38
|
# waiting for WINDOW_UPDATE frames
|
37
39
|
return :r if @buffer.full?
|
38
40
|
|
39
|
-
|
41
|
+
if @connection.state == :closed
|
42
|
+
return unless @handshake_completed
|
43
|
+
|
44
|
+
return :w
|
45
|
+
end
|
40
46
|
|
41
47
|
unless (@connection.state == :connected && @handshake_completed)
|
42
48
|
return @buffer.empty? ? :r : :rw
|
@@ -75,9 +81,13 @@ module HTTPX
|
|
75
81
|
end
|
76
82
|
|
77
83
|
def can_buffer_more_requests?
|
78
|
-
@handshake_completed
|
84
|
+
if @handshake_completed
|
79
85
|
@streams.size < @max_concurrent_requests &&
|
80
|
-
|
86
|
+
@streams.size < @max_requests
|
87
|
+
else
|
88
|
+
!@wait_for_handshake &&
|
89
|
+
@streams.size < @max_concurrent_requests
|
90
|
+
end
|
81
91
|
end
|
82
92
|
|
83
93
|
def send(request)
|
@@ -140,12 +150,14 @@ module HTTPX
|
|
140
150
|
join_headers(stream, request) if request.state == :headers
|
141
151
|
request.transition(:body)
|
142
152
|
join_body(stream, request) if request.state == :body
|
153
|
+
request.transition(:trailers)
|
154
|
+
join_trailers(stream, request) if request.state == :trailers && !request.body.empty?
|
143
155
|
request.transition(:done)
|
144
156
|
end
|
145
157
|
end
|
146
158
|
|
147
159
|
def init_connection
|
148
|
-
@connection = HTTP2Next::Client.new(@
|
160
|
+
@connection = HTTP2Next::Client.new(@settings)
|
149
161
|
@connection.max_streams = @max_requests if @connection.respond_to?(:max_streams=) && @max_requests.positive?
|
150
162
|
@connection.on(:frame, &method(:on_frame))
|
151
163
|
@connection.on(:frame_sent, &method(:on_frame_sent))
|
@@ -169,6 +181,7 @@ module HTTPX
|
|
169
181
|
public :reset
|
170
182
|
|
171
183
|
def handle_stream(stream, request)
|
184
|
+
request.on(:refuse, &method(:on_stream_refuse).curry(3)[stream, request])
|
172
185
|
stream.on(:close, &method(:on_stream_close).curry(3)[stream, request])
|
173
186
|
stream.on(:half_close) do
|
174
187
|
log(level: 2) { "#{stream.id}: waiting for response..." }
|
@@ -193,6 +206,18 @@ module HTTPX
|
|
193
206
|
stream.headers(request.headers.each, end_stream: request.empty?)
|
194
207
|
end
|
195
208
|
|
209
|
+
def join_trailers(stream, request)
|
210
|
+
unless request.trailers?
|
211
|
+
stream.data("", end_stream: true) if request.callbacks_for?(:trailers)
|
212
|
+
return
|
213
|
+
end
|
214
|
+
|
215
|
+
log(level: 1, color: :yellow) do
|
216
|
+
request.trailers.each.map { |k, v| "#{stream.id}: -> HEADER: #{k}: #{v}" }.join("\n")
|
217
|
+
end
|
218
|
+
stream.headers(request.trailers.each, end_stream: true)
|
219
|
+
end
|
220
|
+
|
196
221
|
def join_body(stream, request)
|
197
222
|
return if request.empty?
|
198
223
|
|
@@ -201,13 +226,15 @@ module HTTPX
|
|
201
226
|
next_chunk = request.drain_body
|
202
227
|
log(level: 1, color: :green) { "#{stream.id}: -> DATA: #{chunk.bytesize} bytes..." }
|
203
228
|
log(level: 2, color: :green) { "#{stream.id}: -> #{chunk.inspect}" }
|
204
|
-
stream.data(chunk, end_stream: !next_chunk)
|
205
|
-
if next_chunk && @buffer.full?
|
229
|
+
stream.data(chunk, end_stream: !(next_chunk || request.trailers? || request.callbacks_for?(:trailers)))
|
230
|
+
if next_chunk && (@buffer.full? || request.body.unbounded_body?)
|
206
231
|
@drains[request] = next_chunk
|
207
232
|
throw(:buffer_full)
|
208
233
|
end
|
209
234
|
chunk = next_chunk
|
210
235
|
end
|
236
|
+
|
237
|
+
on_stream_refuse(stream, request, request.drain_error) if request.drain_error
|
211
238
|
end
|
212
239
|
|
213
240
|
######
|
@@ -215,6 +242,11 @@ module HTTPX
|
|
215
242
|
######
|
216
243
|
|
217
244
|
def on_stream_headers(stream, request, h)
|
245
|
+
if request.response && request.response.version == "2.0"
|
246
|
+
on_stream_trailers(stream, request, h)
|
247
|
+
return
|
248
|
+
end
|
249
|
+
|
218
250
|
log(color: :yellow) do
|
219
251
|
h.map { |k, v| "#{stream.id}: <- HEADER: #{k}: #{v}" }.join("\n")
|
220
252
|
end
|
@@ -227,12 +259,24 @@ module HTTPX
|
|
227
259
|
handle(request, stream) if request.expects?
|
228
260
|
end
|
229
261
|
|
262
|
+
def on_stream_trailers(stream, request, h)
|
263
|
+
log(color: :yellow) do
|
264
|
+
h.map { |k, v| "#{stream.id}: <- HEADER: #{k}: #{v}" }.join("\n")
|
265
|
+
end
|
266
|
+
request.response.merge_headers(h)
|
267
|
+
end
|
268
|
+
|
230
269
|
def on_stream_data(stream, request, data)
|
231
270
|
log(level: 1, color: :green) { "#{stream.id}: <- DATA: #{data.bytesize} bytes..." }
|
232
271
|
log(level: 2, color: :green) { "#{stream.id}: <- #{data.inspect}" }
|
233
272
|
request.response << data
|
234
273
|
end
|
235
274
|
|
275
|
+
def on_stream_refuse(stream, request, error)
|
276
|
+
stream.close
|
277
|
+
on_stream_close(stream, request, error)
|
278
|
+
end
|
279
|
+
|
236
280
|
def on_stream_close(stream, request, error)
|
237
281
|
log(level: 2) { "#{stream.id}: closing stream" }
|
238
282
|
@drains.delete(request)
|