protocol-http1 0.40.0 → 0.40.1

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: f9a61dc65b4fee0a9cca3509493160ae14b9b3268ae3134fb8e39ee8afe126df
4
+ data.tar.gz: 3e04a81cdf3d40a6a95b2cdda1d44d32521d68885a48e35592b498ec61779551
5
5
  SHA512:
6
- metadata.gz: 34d8dbeb53722ca4128e5c0ce9dc228aa231b59987feeb26bb5dde04db942e662406a2a751a637cd98629d7da46099a9b1d5731bb9d5eb19f41179ae696ae8c3
7
- data.tar.gz: 0a809c874a1a6143588025865f14681d839b6394c441731092d50cafc86bdd9ed0064890d51271015adce8bb701a1836d2c306bb9cdae8900e66b3d00809c4e6
6
+ metadata.gz: bf4886e4fba31c3d001ee1edfbb6ca68390969153441a253e251d8f8ab116d28ff4b089adb82a6ec79a97465a0c190887d64dd025d090879f591ef8c90a73c3b
7
+ data.tar.gz: 37eb313331d6f6af51eab12400118662fa408200456fbaa54cd9908c63b598e95f97304f559e72c4a0459239c06938e2e5261da6ff6a39a379920f844886a3cf
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 EOFError, "Connection closed before expected length was read!"
115
132
  end
116
133
 
117
134
  # @returns [String] a human-readable representation of the body.
@@ -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.1"
9
9
  end
10
10
  end
data/readme.md CHANGED
@@ -30,6 +30,10 @@ 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.1
34
+
35
+ - Bound fixed-length and chunked body reads, and validate chunk terminators.
36
+
33
37
  ### v0.40.0
34
38
 
35
39
  - Use `Protocol::HTTP::Status` for standard HTTP status descriptions and remove the duplicate `Protocol::HTTP1::Reason` table.
@@ -68,10 +72,6 @@ Please see the [project releases](https://socketry.github.io/protocol-http1/rele
68
72
  - Fix connection state handling to allow idempotent response body closing.
69
73
  - Add `kisaten` fuzzing integration for improved security testing.
70
74
 
71
- ### v0.34.0
72
-
73
- - Support empty header values in HTTP parsing for better compatibility.
74
-
75
75
  ## Contributing
76
76
 
77
77
  We welcome contributions to this project.
@@ -82,6 +82,22 @@ We welcome contributions to this project.
82
82
  4. Push to the branch (`git push origin my-new-feature`).
83
83
  5. Create new Pull Request.
84
84
 
85
+ ### Running Tests
86
+
87
+ To run the test suite:
88
+
89
+ ``` shell
90
+ bundle exec sus
91
+ ```
92
+
93
+ ### Making Releases
94
+
95
+ To make a new release:
96
+
97
+ ``` shell
98
+ bundle exec bake gem:release:patch # or minor or major
99
+ ```
100
+
85
101
  ### Developer Certificate of Origin
86
102
 
87
103
  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,9 @@
1
1
  # Releases
2
2
 
3
+ ## v0.40.1
4
+
5
+ - Bound fixed-length and chunked body reads, and validate chunk terminators.
6
+
3
7
  ## v0.40.0
4
8
 
5
9
  - 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.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
metadata.gz.sig CHANGED
Binary file