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.
175 176 177 178 179 180 181 182 183 |
# File 'lib/protocol/http/body/readable.rb', line 175 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?.
69 70 71 |
# File 'lib/protocol/http/body/readable.rb', line 69 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.
140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/protocol/http/body/readable.rb', line 140 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.
If an error occured 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.
30 31 |
# File 'lib/protocol/http/body/readable.rb', line 30 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.
167 168 169 170 |
# File 'lib/protocol/http/body/readable.rb', line 167 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.
94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/protocol/http/body/readable.rb', line 94 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.
39 40 41 |
# File 'lib/protocol/http/body/readable.rb', line 39 def empty? false end |
#finish ⇒ Object
Read all remaining chunks into a buffered body and close the underlying input.
157 158 159 160 |
# File 'lib/protocol/http/body/readable.rb', line 157 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.
111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/protocol/http/body/readable.rb', line 111 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.
76 77 78 |
# File 'lib/protocol/http/body/readable.rb', line 76 def length nil end |
#read ⇒ Object
Read the next available chunk.
84 85 86 |
# File 'lib/protocol/http/body/readable.rb', line 84 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.
46 47 48 |
# File 'lib/protocol/http/body/readable.rb', line 46 def ready? false end |
#rewind ⇒ Object
Rewind the stream to the beginning.
60 61 62 |
# File 'lib/protocol/http/body/readable.rb', line 60 def rewind false end |
#rewindable? ⇒ Boolean
Whether the stream can be rewound using #rewind.
53 54 55 |
# File 'lib/protocol/http/body/readable.rb', line 53 def rewindable? false end |
#stream? ⇒ Boolean
128 129 130 |
# File 'lib/protocol/http/body/readable.rb', line 128 def stream? false end |
#to_io ⇒ Object
Return an IO-compatible stream for reading this body.
194 195 196 |
# File 'lib/protocol/http/body/readable.rb', line 194 def to_io return Stream.new(self) end |
#to_json ⇒ Object
Convert the body to JSON.
188 189 190 |
# File 'lib/protocol/http/body/readable.rb', line 188 def to_json(...) as_json.to_json(...) end |