http 5.3.1 → 6.0.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/CHANGELOG.md +241 -41
- data/LICENSE.txt +1 -1
- data/README.md +110 -13
- data/UPGRADING.md +491 -0
- data/http.gemspec +32 -29
- data/lib/http/base64.rb +11 -1
- data/lib/http/chainable/helpers.rb +62 -0
- data/lib/http/chainable/verbs.rb +136 -0
- data/lib/http/chainable.rb +232 -136
- data/lib/http/client.rb +158 -127
- data/lib/http/connection/internals.rb +141 -0
- data/lib/http/connection.rb +126 -97
- data/lib/http/content_type.rb +61 -6
- data/lib/http/errors.rb +25 -1
- data/lib/http/feature.rb +65 -5
- data/lib/http/features/auto_deflate.rb +124 -17
- data/lib/http/features/auto_inflate.rb +38 -15
- data/lib/http/features/caching/entry.rb +178 -0
- data/lib/http/features/caching/in_memory_store.rb +63 -0
- data/lib/http/features/caching.rb +216 -0
- data/lib/http/features/digest_auth.rb +234 -0
- data/lib/http/features/instrumentation.rb +97 -17
- data/lib/http/features/logging.rb +183 -5
- data/lib/http/features/normalize_uri.rb +17 -0
- data/lib/http/features/raise_error.rb +18 -3
- data/lib/http/form_data/composite_io.rb +106 -0
- data/lib/http/form_data/file.rb +95 -0
- data/lib/http/form_data/multipart/param.rb +62 -0
- data/lib/http/form_data/multipart.rb +106 -0
- data/lib/http/form_data/part.rb +52 -0
- data/lib/http/form_data/readable.rb +58 -0
- data/lib/http/form_data/urlencoded.rb +175 -0
- data/lib/http/form_data/version.rb +8 -0
- data/lib/http/form_data.rb +102 -0
- data/lib/http/headers/known.rb +3 -0
- data/lib/http/headers/normalizer.rb +17 -36
- data/lib/http/headers.rb +172 -65
- data/lib/http/mime_type/adapter.rb +24 -9
- data/lib/http/mime_type/json.rb +19 -4
- data/lib/http/mime_type.rb +21 -3
- data/lib/http/options/definitions.rb +189 -0
- data/lib/http/options.rb +172 -125
- data/lib/http/redirector.rb +80 -75
- data/lib/http/request/body.rb +87 -6
- data/lib/http/request/builder.rb +184 -0
- data/lib/http/request/proxy.rb +83 -0
- data/lib/http/request/writer.rb +76 -16
- data/lib/http/request.rb +214 -98
- data/lib/http/response/body.rb +103 -18
- data/lib/http/response/inflater.rb +35 -7
- data/lib/http/response/parser.rb +98 -4
- data/lib/http/response/status/reasons.rb +2 -4
- data/lib/http/response/status.rb +141 -31
- data/lib/http/response.rb +219 -61
- data/lib/http/retriable/delay_calculator.rb +38 -11
- data/lib/http/retriable/errors.rb +21 -0
- data/lib/http/retriable/performer.rb +82 -38
- data/lib/http/session.rb +280 -0
- data/lib/http/timeout/global.rb +147 -34
- data/lib/http/timeout/null.rb +155 -9
- data/lib/http/timeout/per_operation.rb +139 -18
- data/lib/http/uri/normalizer.rb +82 -0
- data/lib/http/uri/parsing.rb +182 -0
- data/lib/http/uri.rb +289 -124
- data/lib/http/version.rb +2 -1
- data/lib/http.rb +11 -2
- data/sig/deps.rbs +122 -0
- data/sig/http.rbs +1619 -0
- data/test/http/base64_test.rb +28 -0
- data/test/http/client_test.rb +739 -0
- data/test/http/connection_test.rb +1533 -0
- data/test/http/content_type_test.rb +190 -0
- data/test/http/errors_test.rb +28 -0
- data/test/http/feature_test.rb +49 -0
- data/test/http/features/auto_deflate_test.rb +317 -0
- data/test/http/features/auto_inflate_test.rb +213 -0
- data/test/http/features/caching_test.rb +942 -0
- data/test/http/features/digest_auth_test.rb +996 -0
- data/test/http/features/instrumentation_test.rb +246 -0
- data/test/http/features/logging_test.rb +654 -0
- data/test/http/features/normalize_uri_test.rb +41 -0
- data/test/http/features/raise_error_test.rb +77 -0
- data/test/http/form_data/composite_io_test.rb +215 -0
- data/test/http/form_data/file_test.rb +255 -0
- data/test/http/form_data/fixtures/the-http-gem.info +1 -0
- data/test/http/form_data/multipart_test.rb +303 -0
- data/test/http/form_data/part_test.rb +90 -0
- data/test/http/form_data/urlencoded_test.rb +164 -0
- data/test/http/form_data_test.rb +232 -0
- data/test/http/headers/normalizer_test.rb +93 -0
- data/test/http/headers_test.rb +888 -0
- data/test/http/mime_type/json_test.rb +39 -0
- data/test/http/mime_type_test.rb +150 -0
- data/test/http/options/base_uri_test.rb +148 -0
- data/test/http/options/body_test.rb +21 -0
- data/test/http/options/features_test.rb +38 -0
- data/test/http/options/form_test.rb +21 -0
- data/test/http/options/headers_test.rb +32 -0
- data/test/http/options/json_test.rb +21 -0
- data/test/http/options/merge_test.rb +78 -0
- data/test/http/options/new_test.rb +37 -0
- data/test/http/options/proxy_test.rb +32 -0
- data/test/http/options_test.rb +575 -0
- data/test/http/redirector_test.rb +639 -0
- data/test/http/request/body_test.rb +318 -0
- data/test/http/request/builder_test.rb +623 -0
- data/test/http/request/writer_test.rb +391 -0
- data/test/http/request_test.rb +1733 -0
- data/test/http/response/body_test.rb +292 -0
- data/test/http/response/parser_test.rb +105 -0
- data/test/http/response/status_test.rb +322 -0
- data/test/http/response_test.rb +502 -0
- data/test/http/retriable/delay_calculator_test.rb +194 -0
- data/test/http/retriable/errors_test.rb +71 -0
- data/test/http/retriable/performer_test.rb +551 -0
- data/test/http/session_test.rb +424 -0
- data/test/http/timeout/global_test.rb +239 -0
- data/test/http/timeout/null_test.rb +218 -0
- data/test/http/timeout/per_operation_test.rb +220 -0
- data/test/http/uri/normalizer_test.rb +89 -0
- data/test/http/uri_test.rb +1140 -0
- data/test/http/version_test.rb +15 -0
- data/test/http_test.rb +818 -0
- data/test/regression_tests.rb +27 -0
- data/test/support/dummy_server/encoding_routes.rb +47 -0
- data/test/support/dummy_server/routes.rb +201 -0
- data/test/support/dummy_server/servlet.rb +81 -0
- data/test/support/dummy_server.rb +200 -0
- data/{spec → test}/support/fakeio.rb +2 -2
- data/test/support/http_handling_shared/connection_reuse_tests.rb +97 -0
- data/test/support/http_handling_shared/timeout_tests.rb +134 -0
- data/test/support/http_handling_shared.rb +11 -0
- data/test/support/proxy_server.rb +207 -0
- data/test/support/servers/runner.rb +67 -0
- data/{spec → test}/support/simplecov.rb +11 -2
- data/test/support/ssl_helper.rb +108 -0
- data/test/test_helper.rb +38 -0
- metadata +108 -168
- data/.github/workflows/ci.yml +0 -67
- data/.gitignore +0 -15
- data/.rspec +0 -1
- data/.rubocop/layout.yml +0 -8
- data/.rubocop/metrics.yml +0 -4
- data/.rubocop/rspec.yml +0 -9
- data/.rubocop/style.yml +0 -32
- data/.rubocop.yml +0 -11
- data/.rubocop_todo.yml +0 -219
- data/.yardopts +0 -2
- data/CHANGES_OLD.md +0 -1002
- data/Gemfile +0 -51
- data/Guardfile +0 -18
- data/Rakefile +0 -64
- data/lib/http/headers/mixin.rb +0 -34
- data/lib/http/retriable/client.rb +0 -37
- data/logo.png +0 -0
- data/spec/lib/http/client_spec.rb +0 -556
- data/spec/lib/http/connection_spec.rb +0 -88
- data/spec/lib/http/content_type_spec.rb +0 -47
- data/spec/lib/http/features/auto_deflate_spec.rb +0 -77
- data/spec/lib/http/features/auto_inflate_spec.rb +0 -86
- data/spec/lib/http/features/instrumentation_spec.rb +0 -81
- data/spec/lib/http/features/logging_spec.rb +0 -65
- data/spec/lib/http/features/raise_error_spec.rb +0 -62
- data/spec/lib/http/headers/mixin_spec.rb +0 -36
- data/spec/lib/http/headers/normalizer_spec.rb +0 -52
- data/spec/lib/http/headers_spec.rb +0 -527
- data/spec/lib/http/options/body_spec.rb +0 -15
- data/spec/lib/http/options/features_spec.rb +0 -33
- data/spec/lib/http/options/form_spec.rb +0 -15
- data/spec/lib/http/options/headers_spec.rb +0 -24
- data/spec/lib/http/options/json_spec.rb +0 -15
- data/spec/lib/http/options/merge_spec.rb +0 -68
- data/spec/lib/http/options/new_spec.rb +0 -30
- data/spec/lib/http/options/proxy_spec.rb +0 -20
- data/spec/lib/http/options_spec.rb +0 -13
- data/spec/lib/http/redirector_spec.rb +0 -530
- data/spec/lib/http/request/body_spec.rb +0 -211
- data/spec/lib/http/request/writer_spec.rb +0 -121
- data/spec/lib/http/request_spec.rb +0 -234
- data/spec/lib/http/response/body_spec.rb +0 -85
- data/spec/lib/http/response/parser_spec.rb +0 -74
- data/spec/lib/http/response/status_spec.rb +0 -253
- data/spec/lib/http/response_spec.rb +0 -262
- data/spec/lib/http/retriable/delay_calculator_spec.rb +0 -69
- data/spec/lib/http/retriable/performer_spec.rb +0 -302
- data/spec/lib/http/uri/normalizer_spec.rb +0 -95
- data/spec/lib/http/uri_spec.rb +0 -71
- data/spec/lib/http_spec.rb +0 -535
- data/spec/regression_specs.rb +0 -24
- data/spec/spec_helper.rb +0 -89
- data/spec/support/black_hole.rb +0 -13
- data/spec/support/dummy_server/servlet.rb +0 -203
- data/spec/support/dummy_server.rb +0 -44
- data/spec/support/fuubar.rb +0 -21
- data/spec/support/http_handling_shared.rb +0 -190
- data/spec/support/proxy_server.rb +0 -39
- data/spec/support/servers/config.rb +0 -11
- data/spec/support/servers/runner.rb +0 -19
- data/spec/support/ssl_helper.rb +0 -104
- /data/{spec → test}/support/capture_warning.rb +0 -0
data/lib/http/response/body.rb
CHANGED
|
@@ -9,50 +9,90 @@ module HTTP
|
|
|
9
9
|
class Body
|
|
10
10
|
extend Forwardable
|
|
11
11
|
include Enumerable
|
|
12
|
+
|
|
12
13
|
def_delegator :to_s, :empty?
|
|
13
14
|
|
|
14
|
-
# The connection object
|
|
15
|
+
# The connection object for the request
|
|
16
|
+
#
|
|
17
|
+
# @example
|
|
18
|
+
# body.connection
|
|
15
19
|
#
|
|
16
20
|
# @return [HTTP::Connection]
|
|
21
|
+
# @api public
|
|
17
22
|
attr_reader :connection
|
|
18
23
|
|
|
24
|
+
# The encoding used for the body content
|
|
25
|
+
#
|
|
26
|
+
# @example
|
|
27
|
+
# body.encoding # => Encoding::UTF_8
|
|
28
|
+
#
|
|
29
|
+
# @return [Encoding]
|
|
30
|
+
# @api public
|
|
31
|
+
attr_reader :encoding
|
|
32
|
+
|
|
33
|
+
# Create a new Body instance
|
|
34
|
+
#
|
|
35
|
+
# @example
|
|
36
|
+
# Body.new(stream, encoding: Encoding::UTF_8)
|
|
37
|
+
#
|
|
38
|
+
# @param stream [#readpartial] the response stream
|
|
39
|
+
# @param encoding [Encoding] the encoding to use
|
|
40
|
+
# @return [Body]
|
|
41
|
+
# @api public
|
|
19
42
|
def initialize(stream, encoding: Encoding::BINARY)
|
|
20
43
|
@stream = stream
|
|
21
|
-
@connection = stream.
|
|
44
|
+
@connection = stream.respond_to?(:connection) ? stream.connection : stream
|
|
22
45
|
@streaming = nil
|
|
23
46
|
@contents = nil
|
|
24
47
|
@encoding = find_encoding(encoding)
|
|
25
48
|
end
|
|
26
49
|
|
|
50
|
+
# Read a chunk of the body
|
|
51
|
+
#
|
|
52
|
+
# @example
|
|
53
|
+
# body.readpartial # => "chunk of data"
|
|
54
|
+
#
|
|
27
55
|
# (see HTTP::Client#readpartial)
|
|
28
|
-
|
|
56
|
+
# @return [String]
|
|
57
|
+
# @raise [EOFError] when no more data left
|
|
58
|
+
# @api public
|
|
59
|
+
def readpartial(*)
|
|
29
60
|
stream!
|
|
30
|
-
chunk = @stream.readpartial(*
|
|
31
|
-
|
|
32
|
-
String.new(chunk, :encoding => @encoding) if chunk
|
|
61
|
+
chunk = @stream.readpartial(*)
|
|
62
|
+
String.new(chunk, encoding: @encoding)
|
|
33
63
|
end
|
|
34
64
|
|
|
35
65
|
# Iterate over the body, allowing it to be enumerable
|
|
66
|
+
#
|
|
67
|
+
# @example
|
|
68
|
+
# body.each { |chunk| puts chunk }
|
|
69
|
+
#
|
|
70
|
+
# @yield [chunk] Passes each chunk to the block
|
|
71
|
+
# @yieldparam chunk [String]
|
|
72
|
+
# @return [void]
|
|
73
|
+
# @api public
|
|
36
74
|
def each
|
|
37
|
-
|
|
38
|
-
yield
|
|
75
|
+
loop do
|
|
76
|
+
yield readpartial
|
|
39
77
|
end
|
|
78
|
+
rescue EOFError # rubocop:disable Lint/SuppressedException
|
|
40
79
|
end
|
|
41
80
|
|
|
42
|
-
#
|
|
81
|
+
# Eagerly consume the entire body as a string
|
|
82
|
+
#
|
|
83
|
+
# @example
|
|
84
|
+
# body.to_s # => "full response body"
|
|
85
|
+
#
|
|
86
|
+
# @return [String]
|
|
87
|
+
# @api public
|
|
43
88
|
def to_s
|
|
44
89
|
return @contents if @contents
|
|
45
90
|
|
|
46
91
|
raise StateError, "body is being streamed" unless @streaming.nil?
|
|
47
92
|
|
|
48
93
|
begin
|
|
49
|
-
@streaming
|
|
50
|
-
@contents
|
|
51
|
-
|
|
52
|
-
while (chunk = @stream.readpartial)
|
|
53
|
-
@contents << String.new(chunk, :encoding => @encoding)
|
|
54
|
-
chunk = nil # deallocate string
|
|
55
|
-
end
|
|
94
|
+
@streaming = false
|
|
95
|
+
@contents = read_contents
|
|
56
96
|
rescue
|
|
57
97
|
@contents = nil
|
|
58
98
|
raise
|
|
@@ -63,20 +103,65 @@ module HTTP
|
|
|
63
103
|
alias to_str to_s
|
|
64
104
|
|
|
65
105
|
# Assert that the body is actively being streamed
|
|
106
|
+
#
|
|
107
|
+
# @example
|
|
108
|
+
# body.stream!
|
|
109
|
+
#
|
|
110
|
+
# @return [true]
|
|
111
|
+
# @api public
|
|
66
112
|
def stream!
|
|
67
|
-
raise StateError, "body has already been consumed" if @streaming
|
|
113
|
+
raise StateError, "body has already been consumed" if @streaming.eql?(false)
|
|
68
114
|
|
|
69
115
|
@streaming = true
|
|
70
116
|
end
|
|
71
117
|
|
|
118
|
+
# Whether the body content is suitable for logging
|
|
119
|
+
#
|
|
120
|
+
# Returns true when the body encoding is not binary. Binary responses
|
|
121
|
+
# (images, audio, compressed data) produce unreadable log output.
|
|
122
|
+
#
|
|
123
|
+
# @example
|
|
124
|
+
# body.loggable? # => true
|
|
125
|
+
#
|
|
126
|
+
# @return [Boolean]
|
|
127
|
+
# @api public
|
|
128
|
+
def loggable?
|
|
129
|
+
@encoding != Encoding::BINARY
|
|
130
|
+
end
|
|
131
|
+
|
|
72
132
|
# Easier to interpret string inspect
|
|
133
|
+
#
|
|
134
|
+
# @example
|
|
135
|
+
# body.inspect # => "#<HTTP::Response::Body:3ff2 @streaming=false>"
|
|
136
|
+
#
|
|
137
|
+
# @return [String]
|
|
138
|
+
# @api public
|
|
73
139
|
def inspect
|
|
74
140
|
"#<#{self.class}:#{object_id.to_s(16)} @streaming=#{!!@streaming}>"
|
|
75
141
|
end
|
|
76
142
|
|
|
77
143
|
private
|
|
78
144
|
|
|
79
|
-
#
|
|
145
|
+
# Read all chunks into a single string
|
|
146
|
+
#
|
|
147
|
+
# @return [String]
|
|
148
|
+
# @api private
|
|
149
|
+
def read_contents
|
|
150
|
+
contents = String.new("", encoding: @encoding)
|
|
151
|
+
|
|
152
|
+
loop do
|
|
153
|
+
contents << String.new(@stream.readpartial, encoding: @encoding)
|
|
154
|
+
rescue EOFError
|
|
155
|
+
break
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
contents
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Retrieve encoding by name
|
|
162
|
+
#
|
|
163
|
+
# @return [Encoding]
|
|
164
|
+
# @api private
|
|
80
165
|
def find_encoding(encoding)
|
|
81
166
|
Encoding.find encoding
|
|
82
167
|
rescue ArgumentError
|
|
@@ -4,26 +4,54 @@ require "zlib"
|
|
|
4
4
|
|
|
5
5
|
module HTTP
|
|
6
6
|
class Response
|
|
7
|
+
# Decompresses gzip/deflate response body streams
|
|
7
8
|
class Inflater
|
|
9
|
+
# The underlying connection
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# inflater.connection
|
|
13
|
+
#
|
|
14
|
+
# @return [HTTP::Connection] the underlying connection
|
|
15
|
+
# @api public
|
|
8
16
|
attr_reader :connection
|
|
9
17
|
|
|
18
|
+
# Create a new Inflater wrapping a connection
|
|
19
|
+
#
|
|
20
|
+
# @example
|
|
21
|
+
# Inflater.new(connection)
|
|
22
|
+
#
|
|
23
|
+
# @param connection [HTTP::Connection] the connection to inflate
|
|
24
|
+
# @return [Inflater]
|
|
25
|
+
# @api public
|
|
10
26
|
def initialize(connection)
|
|
11
27
|
@connection = connection
|
|
12
28
|
end
|
|
13
29
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
# Read and inflate a chunk of the response body
|
|
31
|
+
#
|
|
32
|
+
# @example
|
|
33
|
+
# inflater.readpartial # => "decompressed data"
|
|
34
|
+
#
|
|
35
|
+
# @return [String]
|
|
36
|
+
# @raise [EOFError] when no more data left
|
|
37
|
+
# @api public
|
|
38
|
+
def readpartial(*)
|
|
39
|
+
chunk = @connection.readpartial(*)
|
|
40
|
+
zstream.inflate(chunk)
|
|
41
|
+
rescue EOFError
|
|
42
|
+
unless zstream.closed?
|
|
43
|
+
zstream.finished? ? zstream.finish : zstream.reset
|
|
20
44
|
zstream.close
|
|
21
45
|
end
|
|
22
|
-
|
|
46
|
+
|
|
47
|
+
raise
|
|
23
48
|
end
|
|
24
49
|
|
|
25
50
|
private
|
|
26
51
|
|
|
52
|
+
# Return the zlib inflate stream
|
|
53
|
+
# @return [Zlib::Inflate]
|
|
54
|
+
# @api private
|
|
27
55
|
def zstream
|
|
28
56
|
@zstream ||= Zlib::Inflate.new(32 + Zlib::MAX_WBITS)
|
|
29
57
|
end
|
data/lib/http/response/parser.rb
CHANGED
|
@@ -4,16 +4,41 @@ require "llhttp"
|
|
|
4
4
|
|
|
5
5
|
module HTTP
|
|
6
6
|
class Response
|
|
7
|
+
# HTTP response parser backed by LLHttp
|
|
7
8
|
# @api private
|
|
8
9
|
class Parser
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
# The underlying LLHttp parser
|
|
11
|
+
# @return [LLHttp::Parser] the underlying parser
|
|
12
|
+
# @api private
|
|
13
|
+
attr_reader :parser
|
|
14
|
+
|
|
15
|
+
# The parsed response headers
|
|
16
|
+
# @return [HTTP::Headers] the parsed headers
|
|
17
|
+
# @api private
|
|
18
|
+
attr_reader :headers
|
|
19
|
+
|
|
20
|
+
# The parsed HTTP status code
|
|
21
|
+
# @return [Integer, nil] the parsed status code
|
|
22
|
+
# @api private
|
|
23
|
+
attr_reader :status_code
|
|
24
|
+
|
|
25
|
+
# The parsed HTTP version string
|
|
26
|
+
# @return [String, nil] the parsed HTTP version
|
|
27
|
+
# @api private
|
|
28
|
+
attr_reader :http_version
|
|
29
|
+
|
|
30
|
+
# Create a new response parser
|
|
31
|
+
# @return [Parser]
|
|
32
|
+
# @api private
|
|
11
33
|
def initialize
|
|
12
34
|
@handler = Handler.new(self)
|
|
13
|
-
@parser = LLHttp::Parser.new(@handler, :
|
|
35
|
+
@parser = LLHttp::Parser.new(@handler, type: :response)
|
|
14
36
|
reset
|
|
15
37
|
end
|
|
16
38
|
|
|
39
|
+
# Reset parser to initial state
|
|
40
|
+
# @return [void]
|
|
41
|
+
# @api private
|
|
17
42
|
def reset
|
|
18
43
|
@parser.reset
|
|
19
44
|
@handler.reset
|
|
@@ -25,6 +50,9 @@ module HTTP
|
|
|
25
50
|
@http_version = nil
|
|
26
51
|
end
|
|
27
52
|
|
|
53
|
+
# Feed data into the parser
|
|
54
|
+
# @return [Parser]
|
|
55
|
+
# @api private
|
|
28
56
|
def add(data)
|
|
29
57
|
parser << data
|
|
30
58
|
|
|
@@ -33,30 +61,63 @@ module HTTP
|
|
|
33
61
|
raise IOError, e.message
|
|
34
62
|
end
|
|
35
63
|
|
|
64
|
+
# @see #add
|
|
65
|
+
# @api private
|
|
36
66
|
alias << add
|
|
37
67
|
|
|
68
|
+
# Reset parser state for informational (1xx) responses
|
|
69
|
+
# @return [void]
|
|
70
|
+
# @api private
|
|
71
|
+
def reset_for_informational
|
|
72
|
+
@handler.reset
|
|
73
|
+
@header_finished = false
|
|
74
|
+
@message_finished = false
|
|
75
|
+
@headers = Headers.new
|
|
76
|
+
@chunk = nil
|
|
77
|
+
@status_code = nil
|
|
78
|
+
@http_version = nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Mark headers as finished
|
|
82
|
+
# @return [void]
|
|
83
|
+
# @api private
|
|
38
84
|
def mark_header_finished
|
|
39
85
|
@header_finished = true
|
|
40
86
|
@status_code = @parser.status_code
|
|
41
87
|
@http_version = "#{@parser.http_major}.#{@parser.http_minor}"
|
|
42
88
|
end
|
|
43
89
|
|
|
90
|
+
# Check if headers have been parsed
|
|
91
|
+
# @return [Boolean]
|
|
92
|
+
# @api private
|
|
44
93
|
def headers?
|
|
45
94
|
@header_finished
|
|
46
95
|
end
|
|
47
96
|
|
|
97
|
+
# Add a parsed header field and value
|
|
98
|
+
# @return [void]
|
|
99
|
+
# @api private
|
|
48
100
|
def add_header(name, value)
|
|
49
101
|
@headers.add(name, value)
|
|
50
102
|
end
|
|
51
103
|
|
|
104
|
+
# Mark the message as fully parsed
|
|
105
|
+
# @return [void]
|
|
106
|
+
# @api private
|
|
52
107
|
def mark_message_finished
|
|
53
108
|
@message_finished = true
|
|
54
109
|
end
|
|
55
110
|
|
|
111
|
+
# Check if the full message has been parsed
|
|
112
|
+
# @return [Boolean]
|
|
113
|
+
# @api private
|
|
56
114
|
def finished?
|
|
57
115
|
@message_finished
|
|
58
116
|
end
|
|
59
117
|
|
|
118
|
+
# Append a body chunk to the buffer
|
|
119
|
+
# @return [void]
|
|
120
|
+
# @api private
|
|
60
121
|
def add_body(chunk)
|
|
61
122
|
if @chunk
|
|
62
123
|
@chunk << chunk
|
|
@@ -65,6 +126,9 @@ module HTTP
|
|
|
65
126
|
end
|
|
66
127
|
end
|
|
67
128
|
|
|
129
|
+
# Read up to size bytes from the body buffer
|
|
130
|
+
# @return [String, nil]
|
|
131
|
+
# @api private
|
|
68
132
|
def read(size)
|
|
69
133
|
return if @chunk.nil?
|
|
70
134
|
|
|
@@ -79,44 +143,74 @@ module HTTP
|
|
|
79
143
|
chunk
|
|
80
144
|
end
|
|
81
145
|
|
|
146
|
+
# Delegate handler for LLHttp parser callbacks
|
|
147
|
+
# @api private
|
|
82
148
|
class Handler < LLHttp::Delegate
|
|
149
|
+
# Create a new parser handler
|
|
150
|
+
# @return [Handler]
|
|
151
|
+
# @api private
|
|
83
152
|
def initialize(target)
|
|
84
153
|
@target = target
|
|
85
154
|
super()
|
|
86
155
|
reset
|
|
87
156
|
end
|
|
88
157
|
|
|
158
|
+
# Reset handler state
|
|
159
|
+
# @return [void]
|
|
160
|
+
# @api private
|
|
89
161
|
def reset
|
|
90
162
|
@reading_header_value = false
|
|
91
163
|
@field_value = +""
|
|
92
164
|
@field = +""
|
|
93
165
|
end
|
|
94
166
|
|
|
167
|
+
# Handle a header field token
|
|
168
|
+
# @return [void]
|
|
169
|
+
# @api private
|
|
95
170
|
def on_header_field(field)
|
|
96
171
|
append_header if @reading_header_value
|
|
97
172
|
@field << field
|
|
98
173
|
end
|
|
99
174
|
|
|
175
|
+
# Handle a header value token
|
|
176
|
+
# @return [void]
|
|
177
|
+
# @api private
|
|
100
178
|
def on_header_value(value)
|
|
101
179
|
@reading_header_value = true
|
|
102
180
|
@field_value << value
|
|
103
181
|
end
|
|
104
182
|
|
|
183
|
+
# Handle headers complete callback
|
|
184
|
+
# @return [void]
|
|
185
|
+
# @api private
|
|
105
186
|
def on_headers_complete
|
|
106
187
|
append_header if @reading_header_value
|
|
107
188
|
@target.mark_header_finished
|
|
108
189
|
end
|
|
109
190
|
|
|
191
|
+
# Handle body data callback
|
|
192
|
+
# @return [void]
|
|
193
|
+
# @api private
|
|
110
194
|
def on_body(body)
|
|
111
195
|
@target.add_body(body)
|
|
112
196
|
end
|
|
113
197
|
|
|
198
|
+
# Handle message complete callback
|
|
199
|
+
# @return [void]
|
|
200
|
+
# @api private
|
|
114
201
|
def on_message_complete
|
|
115
|
-
@target.
|
|
202
|
+
if Integer(@target.status_code) < 200
|
|
203
|
+
@target.reset_for_informational
|
|
204
|
+
else
|
|
205
|
+
@target.mark_message_finished
|
|
206
|
+
end
|
|
116
207
|
end
|
|
117
208
|
|
|
118
209
|
private
|
|
119
210
|
|
|
211
|
+
# Flush the current header to the parser
|
|
212
|
+
# @return [void]
|
|
213
|
+
# @api private
|
|
120
214
|
def append_header
|
|
121
215
|
@target.add_header(@field, @field_value)
|
|
122
216
|
@reading_header_value = false
|
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# AUTO-GENERATED FILE, DO NOT CHANGE IT MANUALLY
|
|
4
4
|
|
|
5
|
-
require "delegate"
|
|
6
|
-
|
|
7
5
|
module HTTP
|
|
8
6
|
class Response
|
|
9
|
-
class Status
|
|
7
|
+
class Status
|
|
10
8
|
# Code to Reason map
|
|
11
9
|
#
|
|
12
10
|
# @example Usage
|
|
@@ -75,7 +73,7 @@ module HTTP
|
|
|
75
73
|
508 => "Loop Detected",
|
|
76
74
|
510 => "Not Extended",
|
|
77
75
|
511 => "Network Authentication Required"
|
|
78
|
-
}.
|
|
76
|
+
}.each_value(&:freeze).freeze
|
|
79
77
|
end
|
|
80
78
|
end
|
|
81
79
|
end
|