http 0.7.4 → 0.8.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/.rubocop.yml +5 -2
- data/CHANGES.md +24 -7
- data/CONTRIBUTING.md +25 -0
- data/Gemfile +24 -22
- data/Guardfile +2 -2
- data/README.md +34 -4
- data/Rakefile +7 -7
- data/examples/parallel_requests_with_celluloid.rb +2 -2
- data/http.gemspec +12 -12
- data/lib/http.rb +11 -10
- data/lib/http/cache.rb +146 -0
- data/lib/http/cache/headers.rb +100 -0
- data/lib/http/cache/null_cache.rb +13 -0
- data/lib/http/chainable.rb +14 -3
- data/lib/http/client.rb +64 -80
- data/lib/http/connection.rb +139 -0
- data/lib/http/content_type.rb +2 -2
- data/lib/http/errors.rb +7 -1
- data/lib/http/headers.rb +21 -8
- data/lib/http/headers/mixin.rb +1 -1
- data/lib/http/mime_type.rb +2 -2
- data/lib/http/mime_type/adapter.rb +2 -2
- data/lib/http/mime_type/json.rb +4 -4
- data/lib/http/options.rb +65 -74
- data/lib/http/redirector.rb +3 -3
- data/lib/http/request.rb +20 -13
- data/lib/http/request/caching.rb +95 -0
- data/lib/http/request/writer.rb +5 -5
- data/lib/http/response.rb +15 -9
- data/lib/http/response/body.rb +21 -8
- data/lib/http/response/caching.rb +142 -0
- data/lib/http/response/io_body.rb +63 -0
- data/lib/http/response/parser.rb +1 -1
- data/lib/http/response/status.rb +4 -12
- data/lib/http/response/status/reasons.rb +53 -53
- data/lib/http/response/string_body.rb +53 -0
- data/lib/http/version.rb +1 -1
- data/spec/lib/http/cache/headers_spec.rb +77 -0
- data/spec/lib/http/cache_spec.rb +182 -0
- data/spec/lib/http/client_spec.rb +123 -95
- data/spec/lib/http/content_type_spec.rb +25 -25
- data/spec/lib/http/headers/mixin_spec.rb +8 -8
- data/spec/lib/http/headers_spec.rb +213 -173
- data/spec/lib/http/options/body_spec.rb +5 -5
- data/spec/lib/http/options/form_spec.rb +3 -3
- data/spec/lib/http/options/headers_spec.rb +7 -7
- data/spec/lib/http/options/json_spec.rb +3 -3
- data/spec/lib/http/options/merge_spec.rb +26 -22
- data/spec/lib/http/options/new_spec.rb +10 -10
- data/spec/lib/http/options/proxy_spec.rb +8 -8
- data/spec/lib/http/options_spec.rb +2 -2
- data/spec/lib/http/redirector_spec.rb +32 -32
- data/spec/lib/http/request/caching_spec.rb +133 -0
- data/spec/lib/http/request/writer_spec.rb +26 -26
- data/spec/lib/http/request_spec.rb +63 -58
- data/spec/lib/http/response/body_spec.rb +13 -13
- data/spec/lib/http/response/caching_spec.rb +201 -0
- data/spec/lib/http/response/io_body_spec.rb +35 -0
- data/spec/lib/http/response/status_spec.rb +25 -25
- data/spec/lib/http/response/string_body_spec.rb +35 -0
- data/spec/lib/http/response_spec.rb +64 -45
- data/spec/lib/http_spec.rb +103 -76
- data/spec/spec_helper.rb +10 -12
- data/spec/support/connection_reuse_shared.rb +100 -0
- data/spec/support/create_certs.rb +12 -12
- data/spec/support/dummy_server.rb +11 -11
- data/spec/support/dummy_server/servlet.rb +43 -31
- data/spec/support/proxy_server.rb +31 -25
- metadata +57 -8
- data/spec/support/example_server.rb +0 -30
- data/spec/support/example_server/servlet.rb +0 -102
data/lib/http/request/writer.rb
CHANGED
@@ -32,10 +32,10 @@ module HTTP
|
|
32
32
|
# Adds the headers to the header array for the given request body we are working
|
33
33
|
# with
|
34
34
|
def add_body_type_headers
|
35
|
-
if @body.is_a?(String) && !@headers[
|
35
|
+
if @body.is_a?(String) && !@headers["Content-Length"]
|
36
36
|
@request_header << "Content-Length: #{@body.bytesize}"
|
37
|
-
elsif @body.is_a?(Enumerable) &&
|
38
|
-
fail(RequestError,
|
37
|
+
elsif @body.is_a?(Enumerable) && "chunked" != @headers["Transfer-Encoding"]
|
38
|
+
fail(RequestError, "invalid transfer encoding")
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -64,11 +64,11 @@ module HTTP
|
|
64
64
|
@socket << chunk << CRLF
|
65
65
|
end
|
66
66
|
|
67
|
-
@socket <<
|
67
|
+
@socket << "0" << CRLF * 2
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
|
71
|
+
private
|
72
72
|
|
73
73
|
def validate_body_type!
|
74
74
|
return if VALID_BODY_TYPES.any? { |type| @body.is_a? type }
|
data/lib/http/response.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
require
|
1
|
+
require "forwardable"
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
3
|
+
require "http/headers"
|
4
|
+
require "http/content_type"
|
5
|
+
require "http/mime_type"
|
6
|
+
require "http/response/caching"
|
7
|
+
require "http/response/status"
|
8
|
+
require "time"
|
7
9
|
|
8
10
|
module HTTP
|
9
11
|
class Response
|
@@ -16,7 +18,7 @@ module HTTP
|
|
16
18
|
STATUS_CODES = Status::REASONS
|
17
19
|
|
18
20
|
# @deprecated Will be removed in 1.0.0
|
19
|
-
SYMBOL_TO_STATUS_CODE = Hash[STATUS_CODES.map { |k, v| [v.downcase.gsub(/\s|-/,
|
21
|
+
SYMBOL_TO_STATUS_CODE = Hash[STATUS_CODES.map { |k, v| [v.downcase.gsub(/\s|-/, "_").to_sym, k] }].freeze
|
20
22
|
|
21
23
|
# @return [Status]
|
22
24
|
attr_reader :status
|
@@ -29,7 +31,6 @@ module HTTP
|
|
29
31
|
|
30
32
|
def initialize(status, version, headers, body, uri = nil) # rubocop:disable ParameterLists
|
31
33
|
@version, @body, @uri = version, body, uri
|
32
|
-
|
33
34
|
@status = HTTP::Response::Status.new status
|
34
35
|
@headers = HTTP::Headers.coerce(headers || {})
|
35
36
|
end
|
@@ -73,7 +74,7 @@ module HTTP
|
|
73
74
|
#
|
74
75
|
# @return [HTTP::ContentType]
|
75
76
|
def content_type
|
76
|
-
@content_type ||= ContentType.parse headers[
|
77
|
+
@content_type ||= ContentType.parse headers["Content-Type"]
|
77
78
|
end
|
78
79
|
|
79
80
|
# MIME type of response (if any)
|
@@ -102,7 +103,12 @@ module HTTP
|
|
102
103
|
|
103
104
|
# Inspect a response
|
104
105
|
def inspect
|
105
|
-
"#<#{self.class}/#{@version} #{code} #{reason} #{headers.inspect}>"
|
106
|
+
"#<#{self.class}/#{@version} #{code} #{reason} #{headers.to_h.inspect}>"
|
107
|
+
end
|
108
|
+
|
109
|
+
# @return [HTTP::Response::Caching]
|
110
|
+
def caching
|
111
|
+
Caching.new self
|
106
112
|
end
|
107
113
|
end
|
108
114
|
end
|
data/lib/http/response/body.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "forwardable"
|
2
|
+
require "http/client"
|
3
3
|
|
4
4
|
module HTTP
|
5
5
|
class Response
|
@@ -10,13 +10,16 @@ module HTTP
|
|
10
10
|
def_delegator :to_s, :empty?
|
11
11
|
|
12
12
|
def initialize(client)
|
13
|
-
@client
|
14
|
-
@streaming
|
15
|
-
@contents
|
13
|
+
@client = client
|
14
|
+
@streaming = nil
|
15
|
+
@contents = nil
|
16
|
+
@active_seq = client.sequence_id
|
16
17
|
end
|
17
18
|
|
18
19
|
# (see HTTP::Client#readpartial)
|
19
20
|
def readpartial(*args)
|
21
|
+
check_sequence!
|
22
|
+
|
20
23
|
stream!
|
21
24
|
@client.readpartial(*args)
|
22
25
|
end
|
@@ -31,11 +34,13 @@ module HTTP
|
|
31
34
|
# @return [String] eagerly consume the entire body as a string
|
32
35
|
def to_s
|
33
36
|
return @contents if @contents
|
34
|
-
|
37
|
+
|
38
|
+
fail StateError, "body is being streamed" unless @streaming.nil?
|
39
|
+
check_sequence!
|
35
40
|
|
36
41
|
begin
|
37
42
|
@streaming = false
|
38
|
-
@contents =
|
43
|
+
@contents = ""
|
39
44
|
while (chunk = @client.readpartial)
|
40
45
|
@contents << chunk
|
41
46
|
end
|
@@ -48,9 +53,17 @@ module HTTP
|
|
48
53
|
end
|
49
54
|
alias_method :to_str, :to_s
|
50
55
|
|
56
|
+
def check_sequence!
|
57
|
+
return unless @active_seq != @client.sequence_id
|
58
|
+
|
59
|
+
fail StateError, "Sequence ID #{@active_seq} does not match #{@client.sequence_id}. You must read the entire request off."
|
60
|
+
end
|
61
|
+
|
62
|
+
private :check_sequence!
|
63
|
+
|
51
64
|
# Assert that the body is actively being streamed
|
52
65
|
def stream!
|
53
|
-
fail StateError,
|
66
|
+
fail StateError, "body has already been consumed" if @streaming == false
|
54
67
|
@streaming = true
|
55
68
|
end
|
56
69
|
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require "http/cache/headers"
|
2
|
+
require "http/response/string_body"
|
3
|
+
require "http/response/io_body"
|
4
|
+
|
5
|
+
module HTTP
|
6
|
+
class Response
|
7
|
+
# Decorator class for responses to provide convenience methods
|
8
|
+
# related to caching.
|
9
|
+
class Caching < DelegateClass(HTTP::Response)
|
10
|
+
CACHEABLE_RESPONSE_CODES = [200, 203, 300, 301, 410].freeze
|
11
|
+
|
12
|
+
def initialize(obj)
|
13
|
+
super
|
14
|
+
@requested_at = nil
|
15
|
+
@received_at = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [HTTP::Response::Caching]
|
19
|
+
def caching
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Boolean] true iff this response is stale
|
24
|
+
def stale?
|
25
|
+
expired? || cache_headers.must_revalidate?
|
26
|
+
end
|
27
|
+
|
28
|
+
# @returns [Boolean] true iff this response has expired
|
29
|
+
def expired?
|
30
|
+
current_age >= cache_headers.max_age
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [Boolean] true iff this response is cacheable
|
34
|
+
#
|
35
|
+
# ---
|
36
|
+
# A Vary header field-value of "*" always fails to match and
|
37
|
+
# subsequent requests on that resource can only be properly
|
38
|
+
# interpreted by the
|
39
|
+
def cacheable?
|
40
|
+
@cacheable ||=
|
41
|
+
begin
|
42
|
+
CACHEABLE_RESPONSE_CODES.include?(code) \
|
43
|
+
&& !(cache_headers.vary_star? ||
|
44
|
+
cache_headers.no_store? ||
|
45
|
+
cache_headers.no_cache?)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Numeric] the current age (in seconds) of this response
|
50
|
+
#
|
51
|
+
# ---
|
52
|
+
# Algo from https://tools.ietf.org/html/rfc2616#section-13.2.3
|
53
|
+
def current_age
|
54
|
+
now = Time.now
|
55
|
+
age_value = headers.get("Age").map(&:to_i).max || 0
|
56
|
+
|
57
|
+
apparent_age = [0, received_at - server_response_time].max
|
58
|
+
corrected_received_age = [apparent_age, age_value].max
|
59
|
+
response_delay = [0, received_at - requested_at].max
|
60
|
+
corrected_initial_age = corrected_received_age + response_delay
|
61
|
+
resident_time = [0, now - received_at].max
|
62
|
+
|
63
|
+
corrected_initial_age + resident_time
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return [Time] the time at which this response was requested
|
67
|
+
def requested_at
|
68
|
+
@requested_at ||= received_at
|
69
|
+
end
|
70
|
+
attr_writer :requested_at
|
71
|
+
|
72
|
+
# @return [Time] the time at which this response was received
|
73
|
+
def received_at
|
74
|
+
@received_at ||= Time.now
|
75
|
+
end
|
76
|
+
attr_writer :received_at
|
77
|
+
|
78
|
+
# Update self based on this response being revalidated by the
|
79
|
+
# server.
|
80
|
+
def validated!(validating_response)
|
81
|
+
headers.merge!(validating_response.headers)
|
82
|
+
self.requested_at = validating_response.requested_at
|
83
|
+
self.received_at = validating_response.received_at
|
84
|
+
end
|
85
|
+
|
86
|
+
# @return [HTTP::Cache::Headers] cache control headers helper object.
|
87
|
+
def cache_headers
|
88
|
+
@cache_headers ||= HTTP::Cache::Headers.new headers
|
89
|
+
end
|
90
|
+
|
91
|
+
def body
|
92
|
+
@body ||= if __getobj__.body.respond_to? :each
|
93
|
+
__getobj__.body
|
94
|
+
else
|
95
|
+
StringBody.new(__getobj__.body.to_s)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def body=(new_body)
|
100
|
+
@body = if new_body.respond_to?(:readpartial) && new_body.respond_to?(:read)
|
101
|
+
# IO-ish, probably a rack cache response body
|
102
|
+
IoBody.new(new_body)
|
103
|
+
|
104
|
+
elsif new_body.respond_to? :join
|
105
|
+
# probably an array of body parts (rack cache does this sometimes)
|
106
|
+
StringBody.new(new_body.join(""))
|
107
|
+
|
108
|
+
elsif new_body.respond_to? :readpartial
|
109
|
+
# normal body, just use it.
|
110
|
+
new_body
|
111
|
+
|
112
|
+
else
|
113
|
+
# backstop, just to_s it
|
114
|
+
StringBody.new(new_body.to_s)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def vary
|
119
|
+
headers.get("Vary").first
|
120
|
+
end
|
121
|
+
|
122
|
+
protected
|
123
|
+
|
124
|
+
# @return [Time] the time at which the server generated this response.
|
125
|
+
def server_response_time
|
126
|
+
headers.get("Date")
|
127
|
+
.map(&method(:to_time_or_epoch))
|
128
|
+
.max || begin
|
129
|
+
# set it if it is not already set
|
130
|
+
headers["Date"] = received_at.httpdate
|
131
|
+
received_at
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def to_time_or_epoch(t_str)
|
136
|
+
Time.httpdate(t_str)
|
137
|
+
rescue ArgumentError
|
138
|
+
Time.at(0)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module HTTP
|
2
|
+
class Response
|
3
|
+
# A Body class that wraps an IO, rather than a the client
|
4
|
+
# object.
|
5
|
+
class IoBody
|
6
|
+
include Enumerable
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
# @return [String,nil] the next `size` octets part of the
|
10
|
+
# body, or nil if whole body has already been read.
|
11
|
+
def readpartial(size = HTTP::Connection::BUFFER_SIZE)
|
12
|
+
stream!
|
13
|
+
return nil if stream.eof?
|
14
|
+
|
15
|
+
stream.readpartial(size)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Iterate over the body, allowing it to be enumerable
|
19
|
+
def each
|
20
|
+
while (part = readpartial)
|
21
|
+
yield part
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [String] eagerly consume the entire body as a string
|
26
|
+
def to_s
|
27
|
+
@contents ||= readall
|
28
|
+
end
|
29
|
+
alias_method :to_str, :to_s
|
30
|
+
|
31
|
+
def_delegator :to_s, :empty?
|
32
|
+
|
33
|
+
# Assert that the body is actively being streamed
|
34
|
+
def stream!
|
35
|
+
fail StateError, "body has already been consumed" if @streaming == false
|
36
|
+
@streaming = true
|
37
|
+
end
|
38
|
+
|
39
|
+
# Easier to interpret string inspect
|
40
|
+
def inspect
|
41
|
+
"#<#{self.class}:#{object_id.to_s(16)} @streaming=#{!!@streaming}>"
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def initialize(an_io)
|
47
|
+
@streaming = nil
|
48
|
+
@stream = an_io
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_reader :contents, :stream
|
52
|
+
|
53
|
+
def readall
|
54
|
+
fail StateError, "body is being streamed" unless @streaming.nil?
|
55
|
+
|
56
|
+
@streaming = false
|
57
|
+
"".tap do |buf|
|
58
|
+
buf << stream.read until stream.eof?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/http/response/parser.rb
CHANGED
data/lib/http/response/status.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
1
|
+
require "delegate"
|
2
2
|
|
3
|
-
require
|
3
|
+
require "http/response/status/reasons"
|
4
4
|
|
5
5
|
module HTTP
|
6
6
|
class Response
|
@@ -22,7 +22,6 @@ module HTTP
|
|
22
22
|
when object.is_a?(String) then SYMBOL_CODES[symbolize object]
|
23
23
|
when object.is_a?(Symbol) then SYMBOL_CODES[object]
|
24
24
|
when object.is_a?(Numeric) then object.to_i
|
25
|
-
else nil
|
26
25
|
end
|
27
26
|
|
28
27
|
return new code if code
|
@@ -31,7 +30,7 @@ module HTTP
|
|
31
30
|
end
|
32
31
|
alias_method :[], :coerce
|
33
32
|
|
34
|
-
|
33
|
+
private
|
35
34
|
|
36
35
|
# Symbolizes given string
|
37
36
|
#
|
@@ -44,7 +43,7 @@ module HTTP
|
|
44
43
|
# @param [#to_s] str
|
45
44
|
# @return [Symbol]
|
46
45
|
def symbolize(str)
|
47
|
-
str.to_s.downcase.gsub(/-/,
|
46
|
+
str.to_s.downcase.gsub(/-/, " ").gsub(/[^a-z ]/, "").gsub(/\s+/, "_").to_sym
|
48
47
|
end
|
49
48
|
end
|
50
49
|
|
@@ -73,13 +72,6 @@ module HTTP
|
|
73
72
|
# @return [Fixnum] status code
|
74
73
|
attr_reader :code
|
75
74
|
|
76
|
-
if RUBY_VERSION < '1.9.0'
|
77
|
-
# @param [#to_i] code
|
78
|
-
def initialize(code)
|
79
|
-
super __setobj__ code
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
75
|
# @see REASONS
|
84
76
|
# @return [String, nil] status message
|
85
77
|
def reason
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "delegate"
|
2
2
|
|
3
3
|
module HTTP
|
4
4
|
class Response
|
@@ -13,59 +13,59 @@ module HTTP
|
|
13
13
|
#
|
14
14
|
# @return [Hash<Fixnum => String>]
|
15
15
|
REASONS = {
|
16
|
-
100 =>
|
17
|
-
101 =>
|
18
|
-
102 =>
|
19
|
-
200 =>
|
20
|
-
201 =>
|
21
|
-
202 =>
|
22
|
-
203 =>
|
23
|
-
204 =>
|
24
|
-
205 =>
|
25
|
-
206 =>
|
26
|
-
207 =>
|
27
|
-
226 =>
|
28
|
-
300 =>
|
29
|
-
301 =>
|
30
|
-
302 =>
|
31
|
-
303 =>
|
32
|
-
304 =>
|
33
|
-
305 =>
|
34
|
-
306 =>
|
35
|
-
307 =>
|
36
|
-
308 =>
|
37
|
-
400 =>
|
38
|
-
401 =>
|
39
|
-
402 =>
|
40
|
-
403 =>
|
41
|
-
404 =>
|
42
|
-
405 =>
|
43
|
-
406 =>
|
44
|
-
407 =>
|
45
|
-
408 =>
|
46
|
-
409 =>
|
47
|
-
410 =>
|
48
|
-
411 =>
|
49
|
-
412 =>
|
50
|
-
413 =>
|
51
|
-
414 =>
|
52
|
-
415 =>
|
53
|
-
416 =>
|
54
|
-
417 =>
|
16
|
+
100 => "Continue",
|
17
|
+
101 => "Switching Protocols",
|
18
|
+
102 => "Processing",
|
19
|
+
200 => "OK",
|
20
|
+
201 => "Created",
|
21
|
+
202 => "Accepted",
|
22
|
+
203 => "Non-Authoritative Information",
|
23
|
+
204 => "No Content",
|
24
|
+
205 => "Reset Content",
|
25
|
+
206 => "Partial Content",
|
26
|
+
207 => "Multi-Status",
|
27
|
+
226 => "IM Used",
|
28
|
+
300 => "Multiple Choices",
|
29
|
+
301 => "Moved Permanently",
|
30
|
+
302 => "Found",
|
31
|
+
303 => "See Other",
|
32
|
+
304 => "Not Modified",
|
33
|
+
305 => "Use Proxy",
|
34
|
+
306 => "Reserved",
|
35
|
+
307 => "Temporary Redirect",
|
36
|
+
308 => "Permanent Redirect",
|
37
|
+
400 => "Bad Request",
|
38
|
+
401 => "Unauthorized",
|
39
|
+
402 => "Payment Required",
|
40
|
+
403 => "Forbidden",
|
41
|
+
404 => "Not Found",
|
42
|
+
405 => "Method Not Allowed",
|
43
|
+
406 => "Not Acceptable",
|
44
|
+
407 => "Proxy Authentication Required",
|
45
|
+
408 => "Request Timeout",
|
46
|
+
409 => "Conflict",
|
47
|
+
410 => "Gone",
|
48
|
+
411 => "Length Required",
|
49
|
+
412 => "Precondition Failed",
|
50
|
+
413 => "Request Entity Too Large",
|
51
|
+
414 => "Request-URI Too Long",
|
52
|
+
415 => "Unsupported Media Type",
|
53
|
+
416 => "Requested Range Not Satisfiable",
|
54
|
+
417 => "Expectation Failed",
|
55
55
|
418 => "I'm a Teapot",
|
56
|
-
422 =>
|
57
|
-
423 =>
|
58
|
-
424 =>
|
59
|
-
426 =>
|
60
|
-
500 =>
|
61
|
-
501 =>
|
62
|
-
502 =>
|
63
|
-
503 =>
|
64
|
-
504 =>
|
65
|
-
505 =>
|
66
|
-
506 =>
|
67
|
-
507 =>
|
68
|
-
510 =>
|
56
|
+
422 => "Unprocessable Entity",
|
57
|
+
423 => "Locked",
|
58
|
+
424 => "Failed Dependency",
|
59
|
+
426 => "Upgrade Required",
|
60
|
+
500 => "Internal Server Error",
|
61
|
+
501 => "Not Implemented",
|
62
|
+
502 => "Bad Gateway",
|
63
|
+
503 => "Service Unavailable",
|
64
|
+
504 => "Gateway Timeout",
|
65
|
+
505 => "HTTP Version Not Supported",
|
66
|
+
506 => "Variant Also Negotiates",
|
67
|
+
507 => "Insufficient Storage",
|
68
|
+
510 => "Not Extended"
|
69
69
|
}.each { |_, v| v.freeze }.freeze
|
70
70
|
end
|
71
71
|
end
|