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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: febab259d00ab223310ce97b93c2833a3a17e4593c5072d34fa06d502c16a928
4
- data.tar.gz: 75bc5e802779efd48411d87f0261dd57e8ae9a3061efc85351102614816af17c
3
+ metadata.gz: b6af833f22e0c72b843fb6abd8497a49177d41f964087c7dea8b7c5f4c9e7036
4
+ data.tar.gz: 9dd305e81599e12dce90c2a4f8f268f78e438c8268016914a373c22db15202ec
5
5
  SHA512:
6
- metadata.gz: 3e6c9abca60e25c7d31c7ddc08a98036f77f27ef73e9c1fd2d415712a2615e79c2bb3272a0e6f74afdd94c06968e8482640545f9f0f18836ec744a941bc672ba
7
- data.tar.gz: 49c0b5eed90e4afe2eb60903264080963cb70bde3932004e806abf0fcc0e9e15516df3cdb2ef29fa59e439bb666326a4b644d4db989fadb0e762d07f16821f80
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 rack adaptor middleware.
37
+ # Initialize the Rack adapter middleware.
38
38
  #
39
- # @parameter app [Interface(:call)] The rack middleware.
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 rack `env`.
54
+ # Unwrap HTTP headers into the CGI-style expected by Rack middleware, and add them to the Rack `env`.
55
55
  #
56
- # e.g. `accept-encoding` becomes `HTTP_ACCEPT_ENCODING`.
56
+ # For example, `accept-encoding` becomes `HTTP_ACCEPT_ENCODING`.
57
57
  #
58
- # Headers keys with underscores will generate the same CGI-style header key as headers with dashes.
58
+ # Header keys with underscores will generate the same CGI-style header key as headers with dashes.
59
59
  #
60
- # e.g `accept_encoding` becomes `HTTP_ACCEPT_ENCODING` too.
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 rack request `env`.
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 rack `env`.
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 adress.
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 rack `env` from the incoming request and apply it to the rack middleware.
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 rack environment.
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-2025, by Samuel Williams.
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 rack `env` from the incoming request and apply it to the rack middleware.
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 rack response headers into a {Protocol::HTTP::Headers} instance, along with any extra `rack.` metadata.
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 rack environment.
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-2025, by Samuel Williams.
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 rack environment.
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-2025, by Samuel Williams.
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 #call
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 response.
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 path from the Rack environment.
50
+ # Parses a Rackup file and returns the application.
51
51
  #
52
- # @parameter env [Hash] The Rack environment
53
- # @returns [String | Nil] The parsed file path or nil if not found
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-2025, by Samuel Williams.
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.is_a?(Array)
27
- length ||= body.sum(&:bytesize)
28
- return self.new(body, length)
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-2024, by Samuel Williams.
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.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2025, by Samuel Williams.
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 an Async::HTTP body, we return it directly:
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
- # Invoke callbacks in reverse order of registration, as specified by the Rack specification.
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-2024, by Samuel Williams.
4
+ # Copyright, 2022-2026, by Samuel Williams.
5
5
 
6
6
  module Protocol
7
7
  module Rack
8
- # Used for injecting the raw request in the the rack environment.
8
+ # Used for injecting the raw request into the Rack environment.
9
9
  PROTOCOL_HTTP_REQUEST = "protocol.http.request"
10
10
 
11
- # CGI keys <https://tools.ietf.org/html/rfc3875#section-4.1>:
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
- # Header constants:
30
+ # Additional HTTP header constants.
31
31
  HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO"
32
32
  end
33
33
 
34
- # Rack environment variables:
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
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2025, by Samuel Williams.
4
+ # Copyright, 2022-2026, by Samuel Williams.
5
5
  # Copyright, 2023, by Genki Takiuchi.
6
6
 
7
7
  require "io/stream/readable"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2025, by Samuel Williams.
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
- # This class provides a bridge between Rack's environment hash and Protocol::HTTP::Request.
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
- # Checks both `rack.protocol` and `HTTP_UPGRADE` headers.
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-2025, by Samuel Williams.
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 wrapper for a `Rack` response.
15
+ # A Rack-compatible HTTP response wrapper
16
16
  #
17
- # A Rack response consisting of `[status, headers, body]` includes various rack-specific elements, including:
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 rack response tuple into a {Protocol::HTTP::Response}.
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 rack response.
38
- # @parameter status [Integer] The rack response status.
39
- # @parameter headers [Duck(:each)] The rack response headers.
40
- # @parameter body [Duck(:each, :close) | Nil] The rack response body.
41
- # @parameter request [Protocol::HTTP::Request] The original request.
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
- # @parameter status [Integer] The response status.
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
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2025, by Samuel Williams.
4
+ # Copyright, 2022-2026, by Samuel Williams.
5
5
 
6
6
  module Protocol
7
7
  module Rack
8
- VERSION = "0.21.1"
8
+ VERSION = "0.22.0"
9
9
  end
10
10
  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
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v0.22.0
4
+
5
+ - Prefer `Protocol::HTTP::Body::Buffered` where possible for enumerable bodies, mainly to avoid creating `Enumerable`s.
6
+
3
7
  ## v0.21.1
4
8
 
5
9
  - Fix missing `body#close` for streaming bodies.
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.21.1
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.2'
124
+ version: '3.3'
125
125
  required_rubygems_version: !ruby/object:Gem::Requirement
126
126
  requirements:
127
127
  - - ">="
metadata.gz.sig CHANGED
Binary file