Personal sketch of HTTP Streaming techniques While HTTP version 1.1 [1] [2] defines a chunked encoding for streaming, there's a far simpler solution that has been at work since first generation HTTP (1.0) [1] [2] servers and proxies. In my own experience, I independently rediscovered this technique on behalf of the Datek Streamer project in 1996. Datek was a retail brokerage specialized to professional and semi professional day traders that was acquired by Ameritrade in 2002 [1][2]. For the Streamer project, an ability to deliver continuous real-time stock quotes (last trade prices) to internet clients behind firewalls was required. The ability to use HTTP for streaming across existing proxies and firewalls (without any reported exceptions) was a fairly stupendous gift from the authors HTTP and its Proxies. Less is More Not including the "Content Length" header in an HTTP Response from the Server will cause a Proxy to tunnel the TCP stream from the Server to the Client. As the HTTP Client is the participatory initiator, the Content Type is expected to be irrelevant. A Transfer Encoding is not employed. This Streaming Response must employ protocol version "1.0" [1]. It is illegal under protocol version "1.1" [1]. This feature of HTTP/1.0 will permit the Server and Client to hold an open TCP stream for Server writing and Client reading. Hence Streaming HTTP. Its limitations include the Server to Client unidirectionality, and the server host kernel limit boundary on the number of open TCP streams (file descriptors, etc). Java Servlet Unfortunately, most Java Servlet Containers [1] [2] don't permit such streaming. In my own implementations of the Java Servlet specification I've implemented streaming capabilities using this Servlet 2.2 superset API javax.servlet.http.HttpServletResponse public void setBufferSize(int size); Initialize output buffering with buffer size (limit) greater than zero. Disable output buffering with a buffer size less than one. The implementor should accept very large numbers without attempting to allocate a very large buffer. public int getBufferSize(); Return zero if output buffering has not been initialized. Otherwise return the response entity body buffer size (limit). public void flushBuffer() throws java.io.IOException; Write any buffered data to output. Will commit the HTTP response as required. public void resetBuffer(); Initialize dynamic buffering, drop any existing buffer contents. If the implementor is not buffering by default, start buffering as if set buffer size was called with the argument integer max value. public void send() throws java.io.IOException; Commit HTTP response. Dynamic buffering accepts all content for the automated production of a Content Length value. The Servlet Container (effectively) calls "flush buffer" on the normal return of the Servlet "service" method. This API is compatible with Java Servlet Specification. In version 2.1 [1] buffering was undefined. The 2.2 version of the Specification introduced response buffering, and states in section 6.2 that the Container is not required to perform Response Buffering. Optimization In my experience a really nice end to end Content Delivery over HTTP performance is achieved with 512 byte block size for writing payload (Entity Body) to HTTP streams. This works for Flash and QuickTime content in particular, which are among the most sensitive formats for their streaming content. In my estimation (from the perspective of platform independence) this works well for two reasons. First, the application block size is likely to be less than or equal to the TCP/IP packet (block) size. Second, the application write operation will return quickly and permit the network layer access to the CPU when it needs it for Transmission Control. Monday December 10, 2007 |