protocol-rack 0.21.1 → 0.22.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
- checksums.yaml.gz.sig +0 -0
- data/lib/protocol/rack/adapter/generic.rb +21 -24
- data/lib/protocol/rack/adapter/rack2.rb +6 -6
- data/lib/protocol/rack/adapter/rack3.rb +3 -3
- data/lib/protocol/rack/adapter.rb +10 -10
- data/lib/protocol/rack/body/enumerable.rb +5 -4
- data/lib/protocol/rack/body/streaming.rb +1 -2
- data/lib/protocol/rack/body.rb +7 -9
- data/lib/protocol/rack/constants.rb +6 -6
- data/lib/protocol/rack/input.rb +1 -1
- data/lib/protocol/rack/request.rb +5 -4
- data/lib/protocol/rack/response.rb +16 -11
- data/lib/protocol/rack/version.rb +2 -2
- data/readme.md +4 -6
- data/releases.md +4 -0
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b6af833f22e0c72b843fb6abd8497a49177d41f964087c7dea8b7c5f4c9e7036
|
|
4
|
+
data.tar.gz: 9dd305e81599e12dce90c2a4f8f268f78e438c8268016914a373c22db15202ec
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 71724669695ee82106f8f454405aab15127a1e4a0f8e41607104bf7dee85d4f458cee2c4399f4ba8cde1dccd3a8a23daa278e33984f3e2fdbc8a4eedb16c3c2b
|
|
7
|
+
data.tar.gz: f498823e4ef6522b1c8f3bea9e58090c87c52163237a59d6ac257233bb13cc9c3430ec18792475ddfd6bac5a2cd51fae67c49b5261c1d51fd1b71fa62d24354b
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
|
@@ -30,13 +30,13 @@ module Protocol
|
|
|
30
30
|
# @parameter path [String] The path to the Rackup file.
|
|
31
31
|
# @returns [Interface(:call)] The Rack application.
|
|
32
32
|
def self.parse_file(...)
|
|
33
|
-
# This is the old interface, which was changed in Rack 3
|
|
33
|
+
# This is the old interface, which was changed in Rack 3:
|
|
34
34
|
::Rack::Builder.parse_file(...).first
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
# Initialize the
|
|
37
|
+
# Initialize the Rack adapter middleware.
|
|
38
38
|
#
|
|
39
|
-
# @parameter app [Interface(:call)] The
|
|
39
|
+
# @parameter app [Interface(:call)] The Rack middleware.
|
|
40
40
|
# @raises [ArgumentError] If the app does not respond to `call`.
|
|
41
41
|
def initialize(app)
|
|
42
42
|
@app = app
|
|
@@ -51,20 +51,20 @@ module Protocol
|
|
|
51
51
|
Console
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
# Unwrap HTTP headers into the CGI-style expected by Rack middleware, and add them to the
|
|
54
|
+
# Unwrap HTTP headers into the CGI-style expected by Rack middleware, and add them to the Rack `env`.
|
|
55
55
|
#
|
|
56
|
-
#
|
|
56
|
+
# For example, `accept-encoding` becomes `HTTP_ACCEPT_ENCODING`.
|
|
57
57
|
#
|
|
58
|
-
#
|
|
58
|
+
# Header keys with underscores will generate the same CGI-style header key as headers with dashes.
|
|
59
59
|
#
|
|
60
|
-
#
|
|
60
|
+
# For example, `accept_encoding` becomes `HTTP_ACCEPT_ENCODING` too.
|
|
61
61
|
#
|
|
62
62
|
# You should not implicitly trust the `HTTP_` headers for security purposes, as they are generated by the client.
|
|
63
63
|
#
|
|
64
64
|
# Multiple headers are combined with a comma, with one exception: `HTTP_COOKIE` headers are combined with a semicolon.
|
|
65
65
|
#
|
|
66
66
|
# @parameter headers [Protocol::HTTP::Headers] The raw HTTP request headers.
|
|
67
|
-
# @parameter env [Hash] The
|
|
67
|
+
# @parameter env [Hash] The Rack request `env`.
|
|
68
68
|
def unwrap_headers(headers, env)
|
|
69
69
|
headers.each do |key, value|
|
|
70
70
|
http_key = "HTTP_#{key.upcase.tr('-', '_')}"
|
|
@@ -81,17 +81,17 @@ module Protocol
|
|
|
81
81
|
end
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
-
# Process the incoming request into a valid
|
|
84
|
+
# Process the incoming request into a valid Rack `env`.
|
|
85
85
|
#
|
|
86
86
|
# - Set the `env['CONTENT_TYPE']` and `env['CONTENT_LENGTH']` based on the incoming request body.
|
|
87
87
|
# - Set the `env['HTTP_HOST']` header to the request authority.
|
|
88
88
|
# - Set the `env['HTTP_X_FORWARDED_PROTO']` header to the request scheme.
|
|
89
|
-
# - Set `env['REMOTE_ADDR']` to the request remote
|
|
89
|
+
# - Set `env['REMOTE_ADDR']` to the request remote address.
|
|
90
90
|
#
|
|
91
91
|
# @parameter request [Protocol::HTTP::Request] The incoming request.
|
|
92
92
|
# @parameter env [Hash] The rack `env`.
|
|
93
93
|
def unwrap_request(request, env)
|
|
94
|
-
# The request protocol, either from the upgrade header or the HTTP/2 pseudo header of the same name
|
|
94
|
+
# The request protocol, either from the upgrade header or the HTTP/2 pseudo header of the same name:
|
|
95
95
|
if protocol = request.protocol
|
|
96
96
|
env[RACK_PROTOCOL] = protocol
|
|
97
97
|
end
|
|
@@ -100,7 +100,7 @@ module Protocol
|
|
|
100
100
|
env[CGI::CONTENT_TYPE] = content_type
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
-
# In some situations we don't know the content length, e.g. when using chunked encoding, or when decompressing the body
|
|
103
|
+
# In some situations we don't know the content length, e.g. when using chunked encoding, or when decompressing the body:
|
|
104
104
|
if body = request.body and length = body.length
|
|
105
105
|
env[CGI::CONTENT_LENGTH] = length.to_s
|
|
106
106
|
end
|
|
@@ -108,7 +108,7 @@ module Protocol
|
|
|
108
108
|
# We ignore trailers for the purpose of constructing the rack environment:
|
|
109
109
|
self.unwrap_headers(request.headers.header, env)
|
|
110
110
|
|
|
111
|
-
# For the sake of compatibility, we set the `HTTP_UPGRADE` header to the requested protocol
|
|
111
|
+
# For the sake of compatibility, we set the `HTTP_UPGRADE` header to the requested protocol:
|
|
112
112
|
if protocol = request.protocol and request.version.start_with?("HTTP/1")
|
|
113
113
|
env[CGI::HTTP_UPGRADE] = Array(protocol).join(",")
|
|
114
114
|
end
|
|
@@ -118,7 +118,7 @@ module Protocol
|
|
|
118
118
|
env[RACK_HIJACK] = proc{request.hijack!.io}
|
|
119
119
|
end
|
|
120
120
|
|
|
121
|
-
# HTTP/2 prefers `:authority` over `host`, so we do this for backwards compatibility
|
|
121
|
+
# HTTP/2 prefers `:authority` over `host`, so we do this for backwards compatibility:
|
|
122
122
|
env[CGI::HTTP_HOST] ||= request.authority
|
|
123
123
|
|
|
124
124
|
if peer = request.peer
|
|
@@ -149,18 +149,15 @@ module Protocol
|
|
|
149
149
|
def handle_error(env, status, headers, body, error)
|
|
150
150
|
Console.error(self, "Error occurred during request processing:", error)
|
|
151
151
|
|
|
152
|
-
# Close the response body if it exists and supports closing
|
|
152
|
+
# Close the response body if it exists and supports closing:
|
|
153
153
|
body&.close if body.respond_to?(:close)
|
|
154
154
|
|
|
155
|
-
# Invoke `rack.response_finished` callbacks in reverse order of registration.
|
|
156
|
-
# This ensures that callbacks registered later are invoked first, matching the Rack specification.
|
|
155
|
+
# Invoke `rack.response_finished` callbacks in reverse order of registration. This ensures that callbacks registered later are invoked first, matching the Rack specification.
|
|
157
156
|
env&.[](RACK_RESPONSE_FINISHED)&.reverse_each do |callback|
|
|
158
157
|
begin
|
|
159
158
|
callback.call(env, status, headers, error)
|
|
160
159
|
rescue => callback_error
|
|
161
|
-
# If a callback raises an exception, log it but continue invoking other callbacks.
|
|
162
|
-
# The Rack specification states that callbacks should not raise exceptions, but we handle
|
|
163
|
-
# this gracefully to prevent one misbehaving callback from breaking others.
|
|
160
|
+
# If a callback raises an exception, log it but continue invoking other callbacks. The Rack specification states that callbacks should not raise exceptions, but we handle this gracefully to prevent one misbehaving callback from breaking others.
|
|
164
161
|
Console.error(self, "Error occurred during response finished callback:", callback_error)
|
|
165
162
|
end
|
|
166
163
|
end
|
|
@@ -168,7 +165,7 @@ module Protocol
|
|
|
168
165
|
return failure_response(error)
|
|
169
166
|
end
|
|
170
167
|
|
|
171
|
-
# Build a
|
|
168
|
+
# Build a Rack `env` from the incoming request and apply it to the Rack middleware.
|
|
172
169
|
#
|
|
173
170
|
# @parameter request [Protocol::HTTP::Request] The incoming request.
|
|
174
171
|
# @returns [Protocol::HTTP::Response] The HTTP response.
|
|
@@ -178,12 +175,12 @@ module Protocol
|
|
|
178
175
|
|
|
179
176
|
status, headers, body = @app.call(env)
|
|
180
177
|
|
|
181
|
-
# The status must always be an integer
|
|
178
|
+
# The status must always be an integer:
|
|
182
179
|
unless status.is_a?(Integer)
|
|
183
180
|
raise ArgumentError, "Status must be an integer!"
|
|
184
181
|
end
|
|
185
182
|
|
|
186
|
-
# Headers must always be a hash or equivalent
|
|
183
|
+
# Headers must always be a hash or equivalent:
|
|
187
184
|
unless headers
|
|
188
185
|
raise ArgumentError, "Headers must not be nil!"
|
|
189
186
|
end
|
|
@@ -205,7 +202,7 @@ module Protocol
|
|
|
205
202
|
|
|
206
203
|
# Extract protocol information from the environment and response.
|
|
207
204
|
#
|
|
208
|
-
# @parameter env [Hash] The
|
|
205
|
+
# @parameter env [Hash] The Rack environment.
|
|
209
206
|
# @parameter response [Protocol::HTTP::Response] The HTTP response.
|
|
210
207
|
# @parameter headers [Hash] The response headers to modify.
|
|
211
208
|
def self.extract_protocol(env, response, headers)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2022-
|
|
4
|
+
# Copyright, 2022-2026, by Samuel Williams.
|
|
5
5
|
# Copyright, 2025, by Francisco Mejia.
|
|
6
6
|
|
|
7
7
|
require "console"
|
|
@@ -79,7 +79,7 @@ module Protocol
|
|
|
79
79
|
return env
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
-
# Build a
|
|
82
|
+
# Build a Rack `env` from the incoming request and apply it to the Rack middleware.
|
|
83
83
|
#
|
|
84
84
|
# @parameter request [Protocol::HTTP::Request] The incoming request.
|
|
85
85
|
# @returns [Protocol::HTTP::Response] The HTTP response.
|
|
@@ -105,7 +105,7 @@ module Protocol
|
|
|
105
105
|
|
|
106
106
|
headers, meta = self.wrap_headers(headers)
|
|
107
107
|
|
|
108
|
-
# Rack 2 spec does not allow only partial hijacking
|
|
108
|
+
# Rack 2 spec does not allow only partial hijacking:
|
|
109
109
|
# if hijack_body = meta[RACK_HIJACK]
|
|
110
110
|
# body = hijack_body
|
|
111
111
|
# end
|
|
@@ -115,7 +115,7 @@ module Protocol
|
|
|
115
115
|
return self.handle_error(env, status, headers, body, error)
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
-
# Process the
|
|
118
|
+
# Process the Rack response headers into a {Protocol::HTTP::Headers} instance, along with any extra `rack.` metadata.
|
|
119
119
|
# Headers with newline-separated values are split into multiple headers.
|
|
120
120
|
#
|
|
121
121
|
# @parameter fields [Hash] The raw response headers.
|
|
@@ -144,9 +144,9 @@ module Protocol
|
|
|
144
144
|
# Convert a {Protocol::HTTP::Response} into a Rack 2 response tuple.
|
|
145
145
|
# Handles protocol upgrades and streaming responses.
|
|
146
146
|
#
|
|
147
|
-
# @parameter env [Hash] The
|
|
147
|
+
# @parameter env [Hash] The Rack environment.
|
|
148
148
|
# @parameter response [Protocol::HTTP::Response] The HTTP response.
|
|
149
|
-
# @returns [Tuple(Integer, Hash, Object)] The Rack 2 response tuple [status, headers, body]
|
|
149
|
+
# @returns [Tuple(Integer, Hash, Object)] The Rack 2 response tuple `[status, headers, body]`.
|
|
150
150
|
def self.make_response(env, response)
|
|
151
151
|
# These interfaces should be largely compatible:
|
|
152
152
|
headers = response.headers.to_h
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2022-
|
|
4
|
+
# Copyright, 2022-2026, by Samuel Williams.
|
|
5
5
|
# Copyright, 2025, by Francisco Mejia.
|
|
6
6
|
|
|
7
7
|
require "console"
|
|
@@ -117,9 +117,9 @@ module Protocol
|
|
|
117
117
|
# Handles protocol upgrades and streaming responses.
|
|
118
118
|
# Unlike Rack 2, this adapter forces streaming responses by converting the body to a callable.
|
|
119
119
|
#
|
|
120
|
-
# @parameter env [Hash] The
|
|
120
|
+
# @parameter env [Hash] The Rack environment.
|
|
121
121
|
# @parameter response [Protocol::HTTP::Response] The HTTP response.
|
|
122
|
-
# @returns [Tuple(Integer, Hash, Object)] The Rack 3 response tuple [status, headers, body]
|
|
122
|
+
# @returns [Tuple(Integer, Hash, Object)] The Rack 3 response tuple `[status, headers, body]`.
|
|
123
123
|
def self.make_response(env, response)
|
|
124
124
|
# These interfaces should be largely compatible:
|
|
125
125
|
headers = response.headers.to_h
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2022-
|
|
4
|
+
# Copyright, 2022-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "rack"
|
|
7
7
|
|
|
@@ -32,25 +32,25 @@ module Protocol
|
|
|
32
32
|
|
|
33
33
|
# Creates a new adapter instance for the given Rack application.
|
|
34
34
|
#
|
|
35
|
-
# @parameter app [Interface(:call)] A Rack application that responds to
|
|
36
|
-
# @returns [Protocol::HTTP::Middleware] An adapter that can handle HTTP requests
|
|
35
|
+
# @parameter app [Interface(:call)] A Rack application that responds to `call`.
|
|
36
|
+
# @returns [Protocol::HTTP::Middleware] An adapter that can handle HTTP requests.
|
|
37
37
|
def self.new(app)
|
|
38
38
|
IMPLEMENTATION.wrap(app)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
# Converts a Rack response into a Protocol::HTTP
|
|
41
|
+
# Converts a Rack response into a {Protocol::HTTP::Response}.
|
|
42
42
|
#
|
|
43
|
-
# @parameter env [Hash] The Rack environment
|
|
44
|
-
# @parameter response [Array] The Rack response [status, headers, body]
|
|
45
|
-
# @returns [Protocol::HTTP::Response] A Protocol::HTTP response
|
|
43
|
+
# @parameter env [Hash] The Rack environment.
|
|
44
|
+
# @parameter response [Array] The Rack response tuple `[status, headers, body]`.
|
|
45
|
+
# @returns [Protocol::HTTP::Response] A Protocol::HTTP response.
|
|
46
46
|
def self.make_response(env, response)
|
|
47
47
|
IMPLEMENTATION.make_response(env, response)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
# Parses a file
|
|
50
|
+
# Parses a Rackup file and returns the application.
|
|
51
51
|
#
|
|
52
|
-
# @parameter
|
|
53
|
-
# @returns [
|
|
52
|
+
# @parameter path [String] The path to the Rackup file.
|
|
53
|
+
# @returns [Interface(:call)] The parsed Rack application.
|
|
54
54
|
def self.parse_file(...)
|
|
55
55
|
IMPLEMENTATION.parse_file(...)
|
|
56
56
|
end
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2022-
|
|
4
|
+
# Copyright, 2022-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "protocol/http/body/readable"
|
|
7
|
+
require "protocol/http/body/buffered"
|
|
7
8
|
require "protocol/http/body/file"
|
|
8
9
|
|
|
9
10
|
module Protocol
|
|
@@ -23,9 +24,9 @@ module Protocol
|
|
|
23
24
|
# @parameter length [Integer] Optional content length of the response body.
|
|
24
25
|
# @returns [Enumerable] A new enumerable body instance.
|
|
25
26
|
def self.wrap(body, length = nil)
|
|
26
|
-
if body.
|
|
27
|
-
|
|
28
|
-
return
|
|
27
|
+
if body.respond_to?(:to_ary)
|
|
28
|
+
# This avoids allocating an enumerator, which is more efficient:
|
|
29
|
+
return ::Protocol::HTTP::Body::Buffered.new(body.to_ary, length)
|
|
29
30
|
else
|
|
30
31
|
return self.new(body, length)
|
|
31
32
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2022-
|
|
4
|
+
# Copyright, 2022-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "protocol/http/body/streamable"
|
|
7
7
|
|
|
@@ -10,7 +10,6 @@ module Protocol
|
|
|
10
10
|
module Body
|
|
11
11
|
# Wraps a Rack streaming response body.
|
|
12
12
|
# The body must be callable and accept a stream argument.
|
|
13
|
-
# This is typically used for Rack hijack responses or bodies wrapped in `Rack::BodyProxy`.
|
|
14
13
|
# When closed, this class ensures the wrapped body's `close` method is called if it exists.
|
|
15
14
|
class Streaming < ::Protocol::HTTP::Body::Streamable::ResponseBody
|
|
16
15
|
# Initialize the streaming body wrapper.
|
data/lib/protocol/rack/body.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2022-
|
|
4
|
+
# Copyright, 2022-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "body/streaming"
|
|
7
7
|
require_relative "body/enumerable"
|
|
@@ -45,21 +45,21 @@ module Protocol
|
|
|
45
45
|
def self.wrap(env, status, headers, body, input = nil, head = false)
|
|
46
46
|
# In no circumstance do we want this header propagating out:
|
|
47
47
|
if length = headers.delete(CONTENT_LENGTH)
|
|
48
|
-
# We don't really trust the user to provide the right length to the transport
|
|
48
|
+
# We don't really trust the user to provide the right length to the transport:
|
|
49
49
|
length = Integer(length)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
# If we have
|
|
52
|
+
# If we have a Protocol::HTTP body, we return it directly:
|
|
53
53
|
if body.is_a?(::Protocol::HTTP::Body::Readable)
|
|
54
54
|
# Ignore.
|
|
55
55
|
elsif status == 200 and body.respond_to?(:to_path)
|
|
56
56
|
begin
|
|
57
|
-
# Don't mangle partial responses (206)
|
|
57
|
+
# Don't mangle partial responses (206):
|
|
58
58
|
body = ::Protocol::HTTP::Body::File.open(body.to_path).tap do
|
|
59
59
|
body.close if body.respond_to?(:close) # Close the original body.
|
|
60
60
|
end
|
|
61
61
|
rescue Errno::ENOENT
|
|
62
|
-
# If the file is not available, ignore
|
|
62
|
+
# If the file is not available, ignore:
|
|
63
63
|
end
|
|
64
64
|
elsif body.respond_to?(:each)
|
|
65
65
|
body = Body::Enumerable.wrap(body, length)
|
|
@@ -116,14 +116,12 @@ module Protocol
|
|
|
116
116
|
# @returns [Proc] A callback that calls all response finished handlers.
|
|
117
117
|
def self.completion_callback(response_finished, env, status, headers)
|
|
118
118
|
proc do |error|
|
|
119
|
-
#
|
|
119
|
+
# Callbacks are invoked in reverse order of registration, as required by the Rack specification:
|
|
120
120
|
response_finished.reverse_each do |callback|
|
|
121
121
|
begin
|
|
122
122
|
callback.call(env, status, headers, error)
|
|
123
123
|
rescue => callback_error
|
|
124
|
-
# If a callback raises an exception, log it but continue invoking other callbacks.
|
|
125
|
-
# The Rack specification states that callbacks should not raise exceptions, but we handle
|
|
126
|
-
# this gracefully to prevent one misbehaving callback from breaking others.
|
|
124
|
+
# If a callback raises an exception, log it but continue invoking other callbacks. The Rack specification states that callbacks should not raise exceptions, but we handle this gracefully to prevent one misbehaving callback from breaking others:
|
|
127
125
|
Console.error(self, "Error occurred during response finished callback:", callback_error)
|
|
128
126
|
end
|
|
129
127
|
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2022-
|
|
4
|
+
# Copyright, 2022-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
module Protocol
|
|
7
7
|
module Rack
|
|
8
|
-
# Used for injecting the raw request
|
|
8
|
+
# Used for injecting the raw request into the Rack environment.
|
|
9
9
|
PROTOCOL_HTTP_REQUEST = "protocol.http.request"
|
|
10
10
|
|
|
11
|
-
# CGI keys
|
|
11
|
+
# CGI environment variable keys as defined in [RFC 3875](https://tools.ietf.org/html/rfc3875#section-4.1).
|
|
12
12
|
module CGI
|
|
13
13
|
HTTP_HOST = "HTTP_HOST"
|
|
14
14
|
HTTP_UPGRADE = "HTTP_UPGRADE"
|
|
@@ -27,11 +27,11 @@ module Protocol
|
|
|
27
27
|
|
|
28
28
|
HTTP_COOKIE = "HTTP_COOKIE"
|
|
29
29
|
|
|
30
|
-
#
|
|
30
|
+
# Additional HTTP header constants.
|
|
31
31
|
HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO"
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
# Rack environment
|
|
34
|
+
# Rack environment variable keys.
|
|
35
35
|
RACK_ERRORS = "rack.errors"
|
|
36
36
|
RACK_LOGGER = "rack.logger"
|
|
37
37
|
RACK_INPUT = "rack.input"
|
|
@@ -39,7 +39,7 @@ module Protocol
|
|
|
39
39
|
RACK_PROTOCOL = "rack.protocol"
|
|
40
40
|
RACK_RESPONSE_FINISHED = "rack.response_finished"
|
|
41
41
|
|
|
42
|
-
# Rack hijack support
|
|
42
|
+
# Rack hijack support keys.
|
|
43
43
|
RACK_IS_HIJACK = "rack.hijack?"
|
|
44
44
|
RACK_HIJACK = "rack.hijack"
|
|
45
45
|
end
|
data/lib/protocol/rack/input.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2022-
|
|
4
|
+
# Copyright, 2022-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "protocol/http/request"
|
|
7
7
|
require "protocol/http/headers"
|
|
@@ -12,8 +12,8 @@ require_relative "body/input_wrapper"
|
|
|
12
12
|
module Protocol
|
|
13
13
|
module Rack
|
|
14
14
|
# A Rack-compatible HTTP request wrapper.
|
|
15
|
-
#
|
|
16
|
-
# It handles conversion of Rack environment variables to HTTP request properties.
|
|
15
|
+
#
|
|
16
|
+
# This class provides a bridge between Rack's environment hash and {Protocol::HTTP::Request}. It handles conversion of Rack environment variables to HTTP request properties.
|
|
17
17
|
class Request < ::Protocol::HTTP::Request
|
|
18
18
|
# Get or create a Request instance for the given Rack environment.
|
|
19
19
|
# The request is cached in the environment to avoid creating multiple instances.
|
|
@@ -43,7 +43,8 @@ module Protocol
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
# Extract the protocol list from the Rack environment.
|
|
46
|
-
#
|
|
46
|
+
#
|
|
47
|
+
# Checks both `rack.protocol` and {CGI::HTTP_UPGRADE} headers.
|
|
47
48
|
#
|
|
48
49
|
# @parameter env [Hash] The Rack environment hash.
|
|
49
50
|
# @returns [Array(String) | Nil] The list of protocols or `nil` if none specified.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2022-
|
|
4
|
+
# Copyright, 2022-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "body"
|
|
7
7
|
require_relative "constants"
|
|
@@ -12,9 +12,9 @@ require "protocol/http/body/head"
|
|
|
12
12
|
|
|
13
13
|
module Protocol
|
|
14
14
|
module Rack
|
|
15
|
-
# A
|
|
15
|
+
# A Rack-compatible HTTP response wrapper
|
|
16
16
|
#
|
|
17
|
-
# A Rack response consisting of `[status, headers, body]` includes various
|
|
17
|
+
# A Rack response consisting of `[status, headers, body]` includes various Rack-specific elements, including:
|
|
18
18
|
#
|
|
19
19
|
# - A `headers['rack.hijack']` callback which bypasses normal response handling.
|
|
20
20
|
# - Potentially invalid content length.
|
|
@@ -22,7 +22,7 @@ module Protocol
|
|
|
22
22
|
# - Newline-separated header values.
|
|
23
23
|
# - Other `rack.` specific header key/value pairs.
|
|
24
24
|
#
|
|
25
|
-
# This wrapper takes those issues into account and adapts the
|
|
25
|
+
# This wrapper takes those issues into account and adapts the Rack response tuple into a {Protocol::HTTP::Response}.
|
|
26
26
|
class Response < ::Protocol::HTTP::Response
|
|
27
27
|
# HTTP hop headers which *should* not be passed through the proxy.
|
|
28
28
|
HOP_HEADERS = [
|
|
@@ -34,11 +34,15 @@ module Protocol
|
|
|
34
34
|
"upgrade",
|
|
35
35
|
]
|
|
36
36
|
|
|
37
|
-
# Wrap a
|
|
38
|
-
#
|
|
39
|
-
# @parameter
|
|
40
|
-
# @parameter
|
|
41
|
-
# @parameter
|
|
37
|
+
# Wrap a Rack response into a {Response} instance.
|
|
38
|
+
#
|
|
39
|
+
# @parameter env [Hash] The Rack environment hash.
|
|
40
|
+
# @parameter status [Integer] The Rack response status code.
|
|
41
|
+
# @parameter headers [Protocol::HTTP::Headers] The response headers.
|
|
42
|
+
# @parameter meta [Hash] The Rack-specific metadata (e.g., `rack.hijack`).
|
|
43
|
+
# @parameter body [Object] The Rack response body.
|
|
44
|
+
# @parameter request [Protocol::HTTP::Request | Nil] The original request.
|
|
45
|
+
# @returns [Response] A new response instance.
|
|
42
46
|
def self.wrap(env, status, headers, meta, body, request = nil)
|
|
43
47
|
ignored = headers.extract(HOP_HEADERS)
|
|
44
48
|
|
|
@@ -64,10 +68,11 @@ module Protocol
|
|
|
64
68
|
end
|
|
65
69
|
|
|
66
70
|
# Initialize the response wrapper.
|
|
67
|
-
#
|
|
71
|
+
#
|
|
72
|
+
# @parameter status [Integer] The response status code.
|
|
68
73
|
# @parameter headers [Protocol::HTTP::Headers] The response headers.
|
|
69
74
|
# @parameter body [Protocol::HTTP::Body] The response body.
|
|
70
|
-
# @parameter protocol [String] The response protocol for upgraded requests.
|
|
75
|
+
# @parameter protocol [String | Nil] The response protocol for upgraded requests.
|
|
71
76
|
def initialize(status, headers, body, protocol = nil)
|
|
72
77
|
super(nil, status, headers, body, protocol)
|
|
73
78
|
end
|
data/readme.md
CHANGED
|
@@ -21,6 +21,10 @@ Please see the [project documentation](https://socketry.github.io/protocol-rack/
|
|
|
21
21
|
|
|
22
22
|
Please see the [project releases](https://socketry.github.io/protocol-rack/releases/index) for all releases.
|
|
23
23
|
|
|
24
|
+
### v0.22.0
|
|
25
|
+
|
|
26
|
+
- Prefer `Protocol::HTTP::Body::Buffered` where possible for enumerable bodies, mainly to avoid creating `Enumerable`s.
|
|
27
|
+
|
|
24
28
|
### v0.21.1
|
|
25
29
|
|
|
26
30
|
- Fix missing `body#close` for streaming bodies.
|
|
@@ -58,12 +62,6 @@ Please see the [project releases](https://socketry.github.io/protocol-rack/relea
|
|
|
58
62
|
|
|
59
63
|
- Handling of `HEAD` requests is now more robust.
|
|
60
64
|
|
|
61
|
-
### v0.13.0
|
|
62
|
-
|
|
63
|
-
- 100% test and documentation coverage.
|
|
64
|
-
- `Protocol::Rack::Input#rewind` now works when the entire input is already read.
|
|
65
|
-
- `Protocol::Rack::Adapter::Rack2` has stricter validation of the application response.
|
|
66
|
-
|
|
67
65
|
## Contributing
|
|
68
66
|
|
|
69
67
|
We welcome contributions to this project.
|
data/releases.md
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: protocol-rack
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.22.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -121,7 +121,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
121
121
|
requirements:
|
|
122
122
|
- - ">="
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: '3.
|
|
124
|
+
version: '3.3'
|
|
125
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
126
|
requirements:
|
|
127
127
|
- - ">="
|
metadata.gz.sig
CHANGED
|
Binary file
|