99module 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:
0 commit comments