[Seaside] Seaside vs Streaming
mkobetic at cincom.com
Thu Aug 16 14:39:11 UTC 2007
Here's how I understand current streaming integration in Seaside. If you want the response to "stream" back to the client, the HTTP server has to set the responseStream: on the WARequest object it builds before handing it off to Seaside with the handleRequest: call. If the responseStream is set Seaside will create WAStreamingResponse (instead of WAResponse), which instead of creating an internal stream for the response contents will use the provided one. However since this is expected to be the real socket stream, it will first write complete HTTP header into it on the first access of the #stream. By the time the HTTP server gets control back from #handleRequest: the entire response has already been written into the socket.
Here's what I see as problematic with the above solution:
1) I think the decision to stream or not doesn't belong to the HTTP server. As was previously pointed out, some components must stream, some can work either way and some must not stream. It's the components that know enough to make that decision, not the server. With the current setup, the best you can get is a global flag for streaming on the server which will either force all components to stream or all components to not stream.
2) IMO having the WAStreamingResponse write the header breaks the separation of concerns between the HTTP server and Seaside. The HTTP server may want to add fields, filter others, what not. Moreover the server may want to package the response differently, multipart message rather than a simple body, etc. Nothing like that is possible with the current setup.
Here's what I'd like to have as the integration hooks in Seaside. Leave the decision about streaming to the component. If the component doesn't want to stream it can return WAResponse with the header dictionary and a body stream as before. If the component does want to stream it will return a WAStreamingResponse with header dictionary and a block. The block will take a stream to write the body into as an argument and will be invoked some time later when the time to write the body into the socket comes. If a server cannot stream it can simply invoke the block with an internal stream and then proceed as with regular WAResponse.
For backward compatibility we could still support the responseStream: mechanism. If the responseStream is set, Seaside can just write the headers into it as before and then invoke the body block with the Stream. If the response is non-streaming, we can still just make it write into the provided stream.
Now my proposal clearly goes beyond just addressing the two issues mentioned above. It's what I think I'd like to have. However here are some key points that I think are necessary.
1) Components decide about streaming, not the server. Implementing this should be pretty easy, have separate hierarchies for streaming and non-streaming components, or have a flag somewhere, etc. A component could even decide dynamically and stream in some cases and not stream in others.
2) Header fields are *always* provided separately and not written by Seaside
3) The streaming action writes just the body of the response
Does any of this sound reasonable ?
More information about the seaside