Class: Protocol::HTTP1::Body::Chunked
- Inherits:
-
HTTP::Body::Readable
- Object
- HTTP::Body::Readable
- Protocol::HTTP1::Body::Chunked
- Defined in:
- lib/protocol/http1/body/chunked.rb
Overview
Represents a chunked body, which is a series of chunks, each with a length prefix.
See tools.ietf.org/html/rfc7230#section-4.1 for more details on the chunked transfer encoding.
Constant Summary collapse
- CRLF =
"\r\n"- VALID_CHUNK_LENGTH =
/\A[0-9a-fA-F]+\z/
Instance Attribute Summary collapse
-
#count ⇒ Object
readonly
Returns the value of attribute count.
- #the length of the body if known.(lengthofthebody) ⇒ Object readonly
- #the number of chunks read so far.(numberofchunksreadsofar.) ⇒ Object readonly
Instance Method Summary collapse
- #as_json ⇒ Object
-
#close(error = nil) ⇒ Object
Close the connection and mark the body as finished.
- #empty? ⇒ Boolean
-
#initialize(connection, headers) ⇒ Chunked
constructor
Initialize the chunked body.
- #inspect ⇒ Object
- #length ⇒ Object
-
#read ⇒ Object
Read a chunk of data.
Constructor Details
#initialize(connection, headers) ⇒ Chunked
Initialize the chunked body.
22 23 24 25 26 27 28 29 30 |
# File 'lib/protocol/http1/body/chunked.rb', line 22 def initialize(connection, headers) @connection = connection @finished = false @headers = headers @length = 0 @count = 0 end |
Instance Attribute Details
#count ⇒ Object (readonly)
Returns the value of attribute count.
33 34 35 |
# File 'lib/protocol/http1/body/chunked.rb', line 33 def count @count end |
#the length of the body if known.(lengthofthebody) ⇒ Object (readonly)
36 37 38 39 40 41 |
# File 'lib/protocol/http1/body/chunked.rb', line 36 def length # We only know the length once we've read the final chunk: if @finished @length end end |
#the number of chunks read so far.(numberofchunksreadsofar.) ⇒ Object (readonly)
33 |
# File 'lib/protocol/http1/body/chunked.rb', line 33 attr :count |
Instance Method Details
#as_json ⇒ Object
123 124 125 126 127 128 129 |
# File 'lib/protocol/http1/body/chunked.rb', line 123 def as_json(...) super.merge( count: @count, finished: @finished, state: @connection ? "open" : "closed" ) end |
#close(error = nil) ⇒ Object
Close the connection and mark the body as finished.
51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/protocol/http1/body/chunked.rb', line 51 def close(error = nil) if connection = @connection @connection = nil unless @finished connection.close_read end end super end |
#empty? ⇒ Boolean
44 45 46 |
# File 'lib/protocol/http1/body/chunked.rb', line 44 def empty? @connection.nil? end |
#inspect ⇒ Object
118 119 120 |
# File 'lib/protocol/http1/body/chunked.rb', line 118 def inspect "\#<#{self.class} #{@length} bytes read in #{@count} chunks, #{@finished ? 'finished' : 'reading'}>" end |
#length ⇒ Object
36 37 38 39 40 41 |
# File 'lib/protocol/http1/body/chunked.rb', line 36 def length # We only know the length once we've read the final chunk: if @finished @length end end |
#read ⇒ Object
Read a chunk of data.
Follows the procedure outlined in tools.ietf.org/html/rfc7230#section-4.1.3
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/protocol/http1/body/chunked.rb', line 71 def read if !@finished if @connection length, _extensions = @connection.read_line.split(";", 2) unless length =~ VALID_CHUNK_LENGTH raise BadRequest, "Invalid chunk length: #{length.inspect}" end # It is possible this line contains chunk extension, so we use `to_i` to only consider the initial integral part: length = Integer(length, 16) if length == 0 read_trailer # The final chunk has been read and the connection is now closed: @connection.receive_end_stream! @connection = nil @finished = true return nil end # Read trailing CRLF: chunk = @connection.read(length + 2) if chunk.bytesize == length + 2 # ...and chomp it off: chunk.chomp!(CRLF) @length += length @count += 1 return chunk else # The connection has been closed before we have read the requested length: @connection.close_read @connection = nil end end # If the connection has been closed before we have read the final chunk, raise an error: raise EOFError, "connection closed before expected length was read!" end end |