Permalink
Browse files

Got rid of ChunkedStreamingAPI -- moved the methods into Env#chunked_…

…stream_send and Env#chunked_stream_close. Added helpers 'streaming_response' and 'chunked_streaming_response' to API, so that instead of [200, {gook}, Goliath::Response::Streaming] you may return streaming_response(200) or streaming_response(200, 'X-My-Happy-Header' => 'HELLO'). Note that the default status_code for both streaming_response and chunked_streaming_response is 200, not 202... I'm not l337 enough to know the proper subtleties there, though I believe for chunked streaming 200 is appropriate.
  • Loading branch information...
1 parent e1d0b23 commit 11a967c484383cf5610400bbbbf215fd095df264 Philip (flip) Kromer committed Apr 23, 2011
Showing with 70 additions and 53 deletions.
  1. +5 −6 examples/chunked_streaming.rb
  2. +30 −0 lib/goliath/api.rb
  3. +0 −47 lib/goliath/chunked_streaming_api.rb
  4. +33 −0 lib/goliath/env.rb
  5. +2 −0 lib/goliath/response.rb
@@ -11,28 +11,27 @@
#
require 'goliath'
-require 'goliath/chunked_streaming_api'
-class ChunkedStreaming < Goliath::ChunkedStreamingAPI
+class ChunkedStreaming < Goliath::API
def on_close(env)
env.logger.info "Connection closed."
end
def response(env)
i = 0
pt = EM.add_periodic_timer(1) do
- send_chunk(env, "#{i}\n")
+ env.chunked_stream_send("#{i}\n")
i += 1
end
EM.add_timer(10) do
pt.cancel
- send_chunk(env, "!! BOOM !!\n")
- close_stream(env)
+ env.chunked_stream_send("!! BOOM !!\n")
+ env.chunked_stream_close
end
headers = { 'Content-Type' => 'text/plain', 'X-Stream' => 'Goliath' }
- [200, STREAMING_HEADERS.merge(headers), Goliath::Response::STREAMING]
+ chunked_streaming_response(200, headers)
end
end
View
@@ -174,5 +174,35 @@ def response(env)
env.logger.error('You need to implement response')
[400, {}, {:error => 'No response implemented'}]
end
+
+ # Helper method for streaming response apis.
+ #
+ # @param [Integer] status_code The status code to return. 200 by default,
+ # though there is an argument for 202 ('Accepted')
+ # @param [Hash] headers Headers to return.
+ def streaming_response status_code=200, headers={}
+ [status_code, headers, Goliath::Response::STREAMING]
+ end
+
+ # Helper method for chunked transfer streaming response apis
+ #
+ # Chunked transfer streaming is transparent to all clients (it's just as
+ # good as a normal response), but allows an aware client to begin consuming
+ # the stream even as it's produced.
+ #
+ # * http://en.wikipedia.org/wiki/Chunked_transfer_encoding
+ # * http://developers.sun.com/mobility/midp/questions/chunking/
+ # * http://blog.port80software.com/2006/11/08/
+ #
+ # @param [Integer] status_code The status code to return.
+ # @param [Hash] headers Headers to return. The Transfer-Encoding=chunked
+ # header is set for you.
+ #
+ # If you are using chunked streaming, you must use
+ # env.chunked_stream_send and env.chunked_stream_close
+ def chunked_streaming_response status_code=200, headers={}
+ streaming_response status_code, headers.merge(Goliath::Response::CHUNKED_STREAM_HEADERS)
+ end
+
end
end
@@ -1,47 +0,0 @@
-#
-# Provides HTTP streaming using chunked transfer encoding
-#
-# http://en.wikipedia.org/wiki/Chunked_transfer_encoding
-# http://developers.sun.com/mobility/midp/questions/chunking/
-# http://blog.port80software.com/2006/11/08/
-#
-module Goliath
- class ChunkedStreamingAPI < Goliath::API
- CRLF = "\r\n"
- STREAMING_HEADERS = { 'Transfer-Encoding' => 'chunked' }
-
- # Sends a chunk in a Chunked transfer encoding stream.
- #
- # Each chunk starts with the number of octets of the data it embeds expressed
- # in hexadecimal followed by optional parameters (chunk extension) and a
- # terminating CRLF (carriage return and line feed) sequence, followed by the
- # chunk data. The chunk is terminated by CRLF. If chunk extensions are
- # provided, the chunk size is terminated by a semicolon followed with the
- # extension name and an optional equal sign and value
- # (Note: chunk extensions aren't provided yet)
- #
- def send_chunk(env, chunk)
- chunk_len_in_hex = chunk.bytesize.to_s(16)
- body = [chunk_len_in_hex, CRLF, chunk, CRLF].join
- env.stream_send(body)
- end
-
- # Sends the terminating chunk in a chunked transfer encoding stream, and
- # closes the stream.
- #
- # The last chunk is a zero-length chunk, with the chunk size coded as 0, but
- # without any chunk data section. The final chunk may be followed by an
- # optional trailer of additional entity header fields that are normally
- # delivered in the HTTP header to allow the delivery of data that can only
- # be computed after all chunk data has been generated. The sender may
- # indicate in a Trailer header field which additional fields it will send
- # in the trailer after the chunks.
- # (Note: trailer headers aren't provided yet
- #
- def close_stream(env)
- env.stream_send([0, CRLF, CRLF].join)
- env.stream_close
- end
-
- end
-end
View
@@ -67,6 +67,39 @@ def stream_close
self[STREAM_CLOSE].call
end
+ # Sends a chunk in a Chunked transfer encoding stream.
+ #
+ # Each chunk starts with the number of octets of the data it embeds expressed
+ # in hexadecimal followed by optional parameters (chunk extension) and a
+ # terminating CRLF (carriage return and line feed) sequence, followed by the
+ # chunk data. The chunk is terminated by CRLF. If chunk extensions are
+ # provided, the chunk size is terminated by a semicolon followed with the
+ # extension name and an optional equal sign and value
+ # (Note: chunk extensions aren't provided yet)
+ #
+ def chunked_stream_send(chunk)
+ chunk_len_in_hex = chunk.bytesize.to_s(16)
+ body = [chunk_len_in_hex, "\r\n", chunk, "\r\n"].join
+ stream_send(body)
+ end
+
+ # Sends the terminating chunk in a chunked transfer encoding stream, and
+ # closes the stream.
+ #
+ # The last chunk is a zero-length chunk, with the chunk size coded as 0, but
+ # without any chunk data section. The final chunk may be followed by an
+ # optional trailer of additional entity header fields that are normally
+ # delivered in the HTTP header to allow the delivery of data that can only
+ # be computed after all chunk data has been generated. The sender may
+ # indicate in a Trailer header field which additional fields it will send
+ # in the trailer after the chunks.
+ # (Note: trailer headers aren't provided yet
+ #
+ def chunked_stream_close
+ stream_send([0, "\r\n", "\r\n"].join)
+ stream_close
+ end
+
# Convenience method for accessing the rack.logger item in the environment.
#
# @return [Logger] The logger object
View
@@ -23,6 +23,8 @@ class Response
# Used to signal that a response is a streaming response
STREAMING = :goliath_stream_response
+ CHUNKED_STREAM_HEADERS = { 'Transfer-Encoding' => 'chunked' }
+
def initialize
@headers = Goliath::Headers.new

0 comments on commit 11a967c

Please sign in to comment.