protocol-http1 0.40.0 → 0.40.2

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: ab25a92df4b7a3a47fedfb27a10b76ef768fa1472b4e8e2af5f954671212ee02
4
- data.tar.gz: 7f2c88ff5cd039ecd982e9129ee7b10441c42c65eaabd9cd70e1379e268aee29
3
+ metadata.gz: fff1a36300fb1ea0775689411e9b86a45093e6d064d10868c419e38422754bea
4
+ data.tar.gz: c5204b0d2f701c834685b84c405ae1a98da109ec8ccdaf0c6d4a99a04b489ccb
5
5
  SHA512:
6
- metadata.gz: 34d8dbeb53722ca4128e5c0ce9dc228aa231b59987feeb26bb5dde04db942e662406a2a751a637cd98629d7da46099a9b1d5731bb9d5eb19f41179ae696ae8c3
7
- data.tar.gz: 0a809c874a1a6143588025865f14681d839b6394c441731092d50cafc86bdd9ed0064890d51271015adce8bb701a1836d2c306bb9cdae8900e66b3d00809c4e6
6
+ metadata.gz: 454ec4c8703447ad07cc199d482210d40b3abd79961b456eb1d0680869e35f87b72a0f0ba7bea5739178a40130007397b3d71fe9f467c83507628c2625e0cc98
7
+ data.tar.gz: f0c33d4fb8815e1f46e447ab5c693da0baaed0cf08e288d05030157b4bdaf6e792f306efbdaa3db21b80e1d1731d624647c4b3c13e5e5b308deac7b7bbf58346
checksums.yaml.gz.sig CHANGED
Binary file
@@ -15,6 +15,9 @@ module Protocol
15
15
  class Chunked < HTTP::Body::Readable
16
16
  CRLF = "\r\n"
17
17
 
18
+ # The maximum amount of body data returned by a single read.
19
+ BLOCK_SIZE = 1024 * 64
20
+
18
21
  # Initialize the chunked body.
19
22
  #
20
23
  # @parameter connection [Protocol::HTTP1::Connection] the connection to read the body from.
@@ -27,6 +30,7 @@ module Protocol
27
30
 
28
31
  @length = 0
29
32
  @count = 0
33
+ @remaining = nil
30
34
  end
31
35
 
32
36
  # @attribute [Integer] the number of chunks read so far.
@@ -69,15 +73,39 @@ module Protocol
69
73
  # @returns [String | Nil] the next chunk of data, or `nil` if the body is finished.
70
74
  # @raises [EOFError] if the connection is closed before the expected length is read.
71
75
  def read
72
- if !@finished
73
- if @connection
76
+ while !@finished
77
+ unless @connection
78
+ raise EOFError, "Connection closed before expected length was read!"
79
+ end
80
+
81
+ if @remaining
82
+ if @remaining > 0
83
+ chunk = @connection.readpartial([@remaining, BLOCK_SIZE].min)
84
+ @remaining -= chunk.bytesize
85
+ @length += chunk.bytesize
86
+
87
+ return chunk
88
+ end
89
+
90
+ terminator = @connection.read(CRLF.bytesize)
91
+
92
+ unless terminator&.bytesize == CRLF.bytesize
93
+ raise EOFError, "Connection closed before expected length was read!"
94
+ end
95
+
96
+ unless terminator == CRLF
97
+ raise BadRequest, "Invalid chunk terminator: #{terminator.inspect}"
98
+ end
99
+
100
+ @remaining = nil
101
+ @count += 1
102
+ else
74
103
  length, _extensions = @connection.read_line.split(";", 2)
75
104
 
76
105
  unless length =~ VALID_CHUNK_LENGTH
77
106
  raise BadRequest, "Invalid chunk length: #{length.inspect}"
78
107
  end
79
108
 
80
- # It is possible this line contains chunk extension, so we use `to_i` to only consider the initial integral part:
81
109
  length = Integer(length, 16)
82
110
 
83
111
  if length == 0
@@ -91,27 +119,16 @@ module Protocol
91
119
  return nil
92
120
  end
93
121
 
94
- # Read trailing CRLF:
95
- chunk = @connection.read(length + 2)
96
-
97
- if chunk.bytesize == length + 2
98
- # ...and chomp it off:
99
- chunk.chomp!(CRLF)
100
-
101
- @length += length
102
- @count += 1
103
-
104
- return chunk
105
- else
106
- # The connection has been closed before we have read the requested length:
107
- @connection.close_read
108
- @connection = nil
109
- end
122
+ @remaining = length
110
123
  end
111
-
112
- # If the connection has been closed before we have read the final chunk, raise an error:
113
- raise EOFError, "connection closed before expected length was read!"
114
124
  end
125
+ rescue EOFError
126
+ if connection = @connection
127
+ @connection = nil
128
+ connection.close_read
129
+ end
130
+
131
+ raise
115
132
  end
116
133
 
117
134
  # @returns [String] a human-readable representation of the body.
@@ -132,7 +149,7 @@ module Protocol
132
149
 
133
150
  # Read the trailer from the connection, and add any headers to the trailer.
134
151
  def read_trailer
135
- while line = @connection.read_line?
152
+ while line = @connection.read_line
136
153
  # Empty line indicates end of trailer:
137
154
  break if line.empty?
138
155
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2025, by Samuel Williams.
4
+ # Copyright, 2019-2026, by Samuel Williams.
5
5
 
6
6
  require "protocol/http/body/readable"
7
7
 
@@ -10,6 +10,9 @@ module Protocol
10
10
  module Body
11
11
  # Represents a fixed length body.
12
12
  class Fixed < HTTP::Body::Readable
13
+ # The maximum amount of body data returned by a single read.
14
+ BLOCK_SIZE = 1024 * 64
15
+
13
16
  # Initialize the body with the given connection and length.
14
17
  #
15
18
  # @parameter connection [Protocol::HTTP1::Connection] the connection to read the body from.
@@ -55,7 +58,7 @@ module Protocol
55
58
  if @remaining > 0
56
59
  if @connection
57
60
  # `readpartial` will raise `EOFError` if the connection is finished, or `IOError` if the connection is closed.
58
- chunk = @connection.readpartial(@remaining)
61
+ chunk = @connection.readpartial([@remaining, BLOCK_SIZE].min)
59
62
 
60
63
  @remaining -= chunk.bytesize
61
64
 
@@ -68,7 +71,7 @@ module Protocol
68
71
  end
69
72
 
70
73
  # If the connection has been closed before we have read the expected length, raise an error:
71
- raise EOFError, "connection closed before expected length was read!"
74
+ raise EOFError, "Connection closed before expected length was read!"
72
75
  end
73
76
  end
74
77
 
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Protocol
7
7
  module HTTP1
8
- VERSION = "0.40.0"
8
+ VERSION = "0.40.2"
9
9
  end
10
10
  end
data/readme.md CHANGED
@@ -30,6 +30,14 @@ Please see the [project documentation](https://socketry.github.io/protocol-http1
30
30
 
31
31
  Please see the [project releases](https://socketry.github.io/protocol-http1/releases/index) for all releases.
32
32
 
33
+ ### v0.40.2
34
+
35
+ - Handle unexpected EOF while reading chunked trailers.
36
+
37
+ ### v0.40.1
38
+
39
+ - Bound fixed-length and chunked body reads, and validate chunk terminators.
40
+
33
41
  ### v0.40.0
34
42
 
35
43
  - Use `Protocol::HTTP::Status` for standard HTTP status descriptions and remove the duplicate `Protocol::HTTP1::Reason` table.
@@ -63,15 +71,6 @@ Please see the [project releases](https://socketry.github.io/protocol-http1/rele
63
71
 
64
72
  - Add traces provider for `Protocol::HTTP1::Connection`.
65
73
 
66
- ### v0.34.1
67
-
68
- - Fix connection state handling to allow idempotent response body closing.
69
- - Add `kisaten` fuzzing integration for improved security testing.
70
-
71
- ### v0.34.0
72
-
73
- - Support empty header values in HTTP parsing for better compatibility.
74
-
75
74
  ## Contributing
76
75
 
77
76
  We welcome contributions to this project.
@@ -82,6 +81,22 @@ We welcome contributions to this project.
82
81
  4. Push to the branch (`git push origin my-new-feature`).
83
82
  5. Create new Pull Request.
84
83
 
84
+ ### Running Tests
85
+
86
+ To run the test suite:
87
+
88
+ ``` shell
89
+ bundle exec sus
90
+ ```
91
+
92
+ ### Making Releases
93
+
94
+ To make a new release:
95
+
96
+ ``` shell
97
+ bundle exec bake gem:release:patch # or minor or major
98
+ ```
99
+
85
100
  ### Developer Certificate of Origin
86
101
 
87
102
  In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
data/releases.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Releases
2
2
 
3
+ ## v0.40.2
4
+
5
+ - Handle unexpected EOF while reading chunked trailers.
6
+
7
+ ## v0.40.1
8
+
9
+ - Bound fixed-length and chunked body reads, and validate chunk terminators.
10
+
3
11
  ## v0.40.0
4
12
 
5
13
  - Use `Protocol::HTTP::Status` for standard HTTP status descriptions and remove the duplicate `Protocol::HTTP1::Reason` table.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protocol-http1
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.40.0
4
+ version: 0.40.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
metadata.gz.sig CHANGED
Binary file