Skip to content

Commit b263f89

Browse files
committed
100% documentation coverage.
1 parent a6bbc4c commit b263f89

File tree

8 files changed

+322
-27
lines changed

8 files changed

+322
-27
lines changed

lib/protocol/http1.rb

+7
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,10 @@
55

66
require_relative "http1/version"
77
require_relative "http1/connection"
8+
9+
# @namespace
10+
module Protocol
11+
# @namespace
12+
module HTTP1
13+
end
14+
end

lib/protocol/http1/body.rb

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2025, by Samuel Williams.
5+
6+
require_relative "body/chunked"
7+
require_relative "body/fixed"
8+
require_relative "body/remainder"
9+
10+
module Protocol
11+
module HTTP1
12+
# A collection of classes for handling HTTP/1.1 request and response bodies.
13+
module Body
14+
end
15+
end
16+
end

lib/protocol/http1/body/chunked.rb

+21-1
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,16 @@
99
module Protocol
1010
module HTTP1
1111
module Body
12+
# Represents a chunked body, which is a series of chunks, each with a length prefix.
13+
#
14+
# See https://tools.ietf.org/html/rfc7230#section-4.1 for more details on the chunked transfer encoding.
1215
class Chunked < HTTP::Body::Readable
1316
CRLF = "\r\n"
1417

18+
# Initialize the chunked body.
19+
#
20+
# @parameter connection [Protocol::HTTP1::Connection] the connection to read the body from.
21+
# @parameter headers [Protocol::HTTP::Headers] the headers to read the trailer into, if any.
1522
def initialize(connection, headers)
1623
@connection = connection
1724
@finished = false
@@ -22,19 +29,25 @@ def initialize(connection, headers)
2229
@count = 0
2330
end
2431

32+
# @attribute [Integer] the number of chunks read so far.
2533
attr :count
2634

35+
# @attribute [Integer] the length of the body if known.
2736
def length
28-
# We only know the length once we've read everything. This is because the length is not known until the final chunk is read.
37+
# We only know the length once we've read the final chunk:
2938
if @finished
3039
@length
3140
end
3241
end
3342

43+
# @returns [Boolean] true if the body is empty, in other words {read} will return `nil`.
3444
def empty?
3545
@connection.nil?
3646
end
3747

48+
# Close the connection and mark the body as finished.
49+
#
50+
# @parameter error [Exception | Nil] the error that caused the body to be closed, if any.
3851
def close(error = nil)
3952
if connection = @connection
4053
@connection = nil
@@ -49,7 +62,12 @@ def close(error = nil)
4962

5063
VALID_CHUNK_LENGTH = /\A[0-9a-fA-F]+\z/
5164

65+
# Read a chunk of data.
66+
#
5267
# Follows the procedure outlined in https://tools.ietf.org/html/rfc7230#section-4.1.3
68+
#
69+
# @returns [String | Nil] the next chunk of data, or `nil` if the body is finished.
70+
# @raises [EOFError] if the connection is closed before the expected length is read.
5371
def read
5472
if !@finished
5573
if @connection
@@ -96,12 +114,14 @@ def read
96114
end
97115
end
98116

117+
# @returns [String] a human-readable representation of the body.
99118
def inspect
100119
"\#<#{self.class} #{@length} bytes read in #{@count} chunks>"
101120
end
102121

103122
private
104123

124+
# Read the trailer from the connection, and add any headers to the trailer.
105125
def read_trailer
106126
while line = @connection.read_line?
107127
# Empty line indicates end of trailer:

lib/protocol/http1/body/fixed.rb

+17-1
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,33 @@
88
module Protocol
99
module HTTP1
1010
module Body
11+
# Represents a fixed length body.
1112
class Fixed < HTTP::Body::Readable
13+
# Initialize the body with the given connection and length.
14+
#
15+
# @parameter connection [Protocol::HTTP1::Connection] the connection to read the body from.
16+
# @parameter length [Integer] the length of the body.
1217
def initialize(connection, length)
1318
@connection = connection
1419

1520
@length = length
1621
@remaining = length
1722
end
1823

24+
# @attribute [Integer] the length of the body.
1925
attr :length
26+
27+
# @attribute [Integer] the remaining bytes to read.
2028
attr :remaining
2129

30+
# @returns [Boolean] true if the body is empty.
2231
def empty?
2332
@connection.nil? or @remaining == 0
2433
end
2534

35+
# Close the connection.
36+
#
37+
# @parameter error [Exception | Nil] the error that caused the connection to be closed, if any.
2638
def close(error = nil)
2739
if connection = @connection
2840
@connection = nil
@@ -35,7 +47,10 @@ def close(error = nil)
3547
super
3648
end
3749

38-
# @raises EOFError if the connection is closed before the expected length is read.
50+
# Read a chunk of data.
51+
#
52+
# @returns [String | Nil] the next chunk of data.
53+
# @raises [EOFError] if the connection is closed before the expected length is read.
3954
def read
4055
if @remaining > 0
4156
if @connection
@@ -57,6 +72,7 @@ def read
5772
end
5873
end
5974

75+
# @returns [String] a human-readable representation of the body.
6076
def inspect
6177
"\#<#{self.class} length=#{@length} remaining=#{@remaining} state=#{@connection ? 'open' : 'closed'}>"
6278
end

lib/protocol/http1/body/remainder.rb

+16-4
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,24 @@
88
module Protocol
99
module HTTP1
1010
module Body
11-
# A body that reads all remaining data from the connection.
11+
# Represents the remainder of the body, which reads all the data from the connection until it is finished.
1212
class Remainder < HTTP::Body::Readable
1313
BLOCK_SIZE = 1024 * 64
1414

15-
# block_size may be removed in the future. It is better managed by connection.
16-
def initialize(connection)
15+
# Initialize the body with the given connection.
16+
#
17+
# @parameter connection [Protocol::HTTP1::Connection] the connection to read the body from.
18+
def initialize(connection, block_size: BLOCK_SIZE)
1719
@connection = connection
20+
@block_size = block_size
1821
end
1922

23+
# @returns [Boolean] true if the body is empty.
2024
def empty?
2125
@connection.nil?
2226
end
2327

28+
# Discard the body, which will close the connection and prevent further reads.
2429
def discard
2530
if connection = @connection
2631
@connection = nil
@@ -30,14 +35,20 @@ def discard
3035
end
3136
end
3237

38+
# Close the connection.
39+
#
40+
# @parameter error [Exception | Nil] the error that caused the connection to be closed, if any.
3341
def close(error = nil)
3442
self.discard
3543

3644
super
3745
end
3846

47+
# Read a chunk of data.
48+
#
49+
# @returns [String | Nil] the next chunk of data.
3950
def read
40-
@connection&.readpartial(BLOCK_SIZE)
51+
@connection&.readpartial(@block_size)
4152
rescue EOFError
4253
if connection = @connection
4354
@connection = nil
@@ -47,6 +58,7 @@ def read
4758
return nil
4859
end
4960

61+
# @returns [String] a human-readable representation of the body.
5062
def inspect
5163
"\#<#{self.class} state=#{@connection ? 'open' : 'closed'}>"
5264
end

0 commit comments

Comments
 (0)