Class: Protocol::HTTP::Body::Readable
- Inherits:
-
Object
- Object
- Protocol::HTTP::Body::Readable
- Defined in:
- lib/protocol/http/body/readable.rb
Overview
Represents a readable input streams.
There are two major modes of operation:
- Reading chunks using #read (or #each/#join), until the body is empty, or
- Streaming chunks using #call, which writes chunks to a provided output stream.
In both cases, reading can fail, for example if the body represents a streaming upload, and the connection is lost. In this case, #read will raise some kind of error, or the stream will be closed with an error.
At any point, you can use #close to close the stream and release any resources, or #discard to read all remaining data without processing it which may allow the underlying connection to be reused (but can be slower).
Instance Method Summary collapse
-
#as_json ⇒ Object
Convert the body to a hash suitable for serialization.
-
#buffered ⇒ Object
Return a buffered representation of this body.
-
#call(stream) ⇒ Object
Invoke the body with the given stream.
-
#close(error = nil) ⇒ Object
Close the stream immediately.
-
#discard ⇒ Object
Discard the body as efficiently as possible.
-
#each ⇒ Object
Enumerate all chunks until finished, then invoke #close.
-
#empty? ⇒ Boolean
Optimistically determine whether read (may) return any data.
-
#finish ⇒ Object
Read all remaining chunks into a buffered body and close the underlying input.
-
#join ⇒ Object
Read all remaining chunks into a single binary string using
#each. -
#length ⇒ Object
The total length of the body, if known.
-
#read ⇒ Object
Read the next available chunk.
-
#ready? ⇒ Boolean
Whether calling read will return a chunk of data without blocking.
-
#rewind ⇒ Object
Rewind the stream to the beginning.
-
#rewindable? ⇒ Boolean
Whether the stream can be rewound using #rewind.
- #stream? ⇒ Boolean
-
#to_io ⇒ Object
Return an IO-compatible stream for reading this body.
-
#to_json ⇒ Object
Convert the body to JSON.
Instance Method Details
#as_json ⇒ Object
Convert the body to a hash suitable for serialization. This won't include the contents of the body, but will include metadata such as the length, streamability, and readiness, etc.
179 180 181 182 183 184 185 186 187 |
# File 'lib/protocol/http/body/readable.rb', line 179 def as_json(...) { class: self.class.name, length: self.length, stream: self.stream?, ready: self.ready?, empty: self.empty? } end |
#buffered ⇒ Object
Return a buffered representation of this body.
This method must return a buffered body if #rewindable?.
73 74 75 |
# File 'lib/protocol/http/body/readable.rb', line 73 def buffered nil end |
#call(stream) ⇒ Object
Invoke the body with the given stream.
The default implementation simply writes each chunk to the stream. If the body is not ready, it will be flushed after each chunk. Closes the stream when finished or if an error occurs.
Write the body to the given stream.
144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/protocol/http/body/readable.rb', line 144 def call(stream) self.each do |chunk| stream.write(chunk) # Flush the stream unless we are immediately expecting more data: unless self.ready? stream.flush end end ensure # TODO Should this invoke close_write(error) instead? stream.close end |
#close(error = nil) ⇒ Object
Close the stream immediately. After invoking this method, the stream should be considered closed, and all internal resources should be released.
Closing the stream before it reaches end-of-file abandons any remaining input. The protocol implementation must account for that unread data before the associated exchange or connection can be reused. Depending on the protocol, it may discard the remaining data, terminate the exchange, or make the connection non-reusable. Use #discard when preserving the exchange or connection is preferred.
When closing before end-of-file, omitting the error represents deliberate application-level abandonment, not a protocol failure.
If an error occurred while handling the output, it can be passed as an argument. This may be propagated to the client, for example the client may be informed that the stream was not fully read correctly.
34 35 |
# File 'lib/protocol/http/body/readable.rb', line 34 def close(error = nil) end |
#discard ⇒ Object
Discard the body as efficiently as possible.
The default implementation simply reads all chunks until the body is empty.
Useful for discarding the body when it is not needed, but preserving the underlying connection.
171 172 173 174 |
# File 'lib/protocol/http/body/readable.rb', line 171 def discard while chunk = self.read end end |
#each ⇒ Object
Enumerate all chunks until finished, then invoke #close.
Closes the stream when finished or if an error occurs.
98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/protocol/http/body/readable.rb', line 98 def each return to_enum unless block_given? begin while chunk = self.read yield chunk end rescue => error raise ensure self.close(error) end end |
#empty? ⇒ Boolean
Optimistically determine whether read (may) return any data.
- If this returns true, then calling read will definitely return nil.
- If this returns false, then calling read may return nil.
43 44 45 |
# File 'lib/protocol/http/body/readable.rb', line 43 def empty? false end |
#finish ⇒ Object
Read all remaining chunks into a buffered body and close the underlying input.
161 162 163 164 |
# File 'lib/protocol/http/body/readable.rb', line 161 def finish # Internally, this invokes `self.each` which then invokes `self.close`. Buffered.read(self) end |
#join ⇒ Object
Read all remaining chunks into a single binary string using #each.
115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/protocol/http/body/readable.rb', line 115 def join buffer = String.new.force_encoding(Encoding::BINARY) self.each do |chunk| buffer << chunk end if buffer.empty? return nil else return buffer end end |
#length ⇒ Object
The total length of the body, if known.
80 81 82 |
# File 'lib/protocol/http/body/readable.rb', line 80 def length nil end |
#read ⇒ Object
Read the next available chunk.
88 89 90 |
# File 'lib/protocol/http/body/readable.rb', line 88 def read nil end |
#ready? ⇒ Boolean
Whether calling read will return a chunk of data without blocking. We prefer pessimistic implementation, and thus default to false.
50 51 52 |
# File 'lib/protocol/http/body/readable.rb', line 50 def ready? false end |
#rewind ⇒ Object
Rewind the stream to the beginning.
64 65 66 |
# File 'lib/protocol/http/body/readable.rb', line 64 def rewind false end |
#rewindable? ⇒ Boolean
Whether the stream can be rewound using #rewind.
57 58 59 |
# File 'lib/protocol/http/body/readable.rb', line 57 def rewindable? false end |
#stream? ⇒ Boolean
132 133 134 |
# File 'lib/protocol/http/body/readable.rb', line 132 def stream? false end |
#to_io ⇒ Object
Return an IO-compatible stream for reading this body.
198 199 200 |
# File 'lib/protocol/http/body/readable.rb', line 198 def to_io return Stream.new(self) end |
#to_json ⇒ Object
Convert the body to JSON.
192 193 194 |
# File 'lib/protocol/http/body/readable.rb', line 192 def to_json(...) as_json.to_json(...) end |