lib/protocol/http/body/readable.rb in protocol-http-0.33.0 vs lib/protocol/http/body/readable.rb in protocol-http-0.34.0
- old
+ new
@@ -15,11 +15,15 @@
#
# Reading can also fail, for example if the body represents a streaming upload, and the connection is lost. In this case, the body will raise some kind of error.
#
# If you don't want to read from a stream, and instead want to close it immediately, you can call `close` on the body. If the body is already completely consumed, `close` will do nothing, but if there is still data to be read, it will cause the underlying stream to be reset (and possibly closed).
class Readable
- # Close the stream immediately.
+ # 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.
+ #
+ # Invoking `#read` after `#close` will return `nil`.
def close(error = nil)
end
# Optimistically determine whether read (may) return any data.
# If this returns true, then calling read will definitely return nil.
@@ -66,17 +70,19 @@
# @yields {|chunk| ...} The block to call with each chunk of data.
# @parameter chunk [String | Nil] The chunk of data, or `nil` if the stream has finished.
def each
return to_enum unless block_given?
- while chunk = self.read
- yield chunk
+ begin
+ while chunk = self.read
+ yield chunk
+ end
+ rescue => error
+ raise
+ ensure
+ self.close(error)
end
- rescue => error
- raise
- ensure
- self.close(error)
end
# Read all remaining chunks into a single binary string using `#each`.
#
# @returns [String | Nil] The binary string containing all chunks of data, or `nil` if the stream has finished (or did not contain any data).
@@ -96,24 +102,28 @@
def stream?
false
end
- # Write the body to the given stream.
+ # Invoke the body with the given stream.
#
- # In some cases, the stream may also be readable, such as when hijacking an HTTP/1 connection. In that case, it may be acceptable to read and write to the stream directly.
+ # 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.
#
- # If the stream 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.
#
+ # @parameter stream [IO | Object] An `IO`-like object that responds to `#read`, `#write` and `#flush`.
+ # @returns [Boolean] Whether the ownership of the stream was transferred.
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
+ stream.close
end
# Read all remaining chunks into a buffered body and close the underlying input.
#
# @returns [Buffered] The buffered body.