Fixed bugs in web server's handling of streamed content (logic was incorrectly handling non-blocking IO in the stream - interpreting it as a stream closed). Modified StreamedContent to use blocking IO instead of non-blocking since it was wasting CPU cycles (non-blocking IO done properly would require removing the write flag from the client socket and listening to the StreamedContent for the availablity of content before re-flagging the socket for writing). Using non-blocking IO here really isn't that useful since the content source should be trusted and timely, and multiple threads service clients (a few threads blocking for a few milliseconds is no big deal), and implementing it properly would significantly increase code complexity.

This commit is contained in:
wcrisman
2014-07-13 12:19:30 -07:00
parent 837fdced57
commit 11b75d567f
2 changed files with 135 additions and 134 deletions

View File

@@ -11,10 +11,15 @@ import com.foundation.web.interfaces.IContent;
import com.foundation.web.interfaces.IMimeType;
import com.foundation.web.interfaces.IMimeTypeProvider;
/**
* Allows the request handler (Webapp code) to specify content that will be streamed (retrieved) as it is sent to the client, versus loaded into memory or on disk (file). This allows dynamic content to be processed as it is being sent to the client, and it allows for wrappering a stream of data being sent by an external process.
* <p>Note: Since the stream is considered a trusted source, non-blocking IO is currently prevented. That is to say that the thread trying to send the next packet of data to the client will wait for the content to become available rather than cycle back into a write waiting state. Write waiting is waiting upon the socket to the client to be available for writing, which it already is (or it wouldn't be asking for content to send), therefor it would just waste a lot of CPU cycles checking constantly for more content. Either we must be able to release the thread until content becomes available (we'd need to clear the socket listener flags until content is available, then set the write flag again), or we must block until content is available. Blocking shouldn't be a problem because the content source is trusted (won't keep us blocked an unreasonable amount of time) and because the WebServer allows for a fair number of threads servicing requests and responses at once (a couple blocking threads won't kill us).</p>
*/
public class StreamedContent implements IContent {
private SocketChannel channel = null;
private Runnable releaseChannelHandler = null;
private ByteBuffer buffer = null;
/** The size of the content if known. Will be -1 if the size is not known (0 size indicates no remaining bytes to be read). */
private int size = 0;
private int chunkSize = 0;
/**
@@ -47,7 +52,8 @@ public StreamedContent(SocketChannel channel, ByteBuffer buffer, Runnable releas
this.buffer = buffer;
this.releaseChannelHandler = releaseChannelHandler;
this.size = -1;
channel.configureBlocking(false);
//TODO: This could be false, but we'd have to find a way to un-flag the socket for writing, and re-flag it once content is available. For now (due to the trusted and timely nature of streamed content) this isn't worth all the code complexity that would result.
channel.configureBlocking(true);
}//StreamedContent()//
public long getStart() {
return 0;
@@ -85,8 +91,10 @@ public int get(ByteBuffer buffer) {
int result = CONTENT_END;
try {
//Handle known size streams differently than streams with an unknown size.//
if(size != -1) {
if(size != 0) {
//Use already buffered data first, then read from the stream.//
if(this.buffer != null && this.buffer.hasRemaining()) {
//Copy the data from our source buffer to the destination buffer.//
result = put(buffer, this.buffer);
@@ -97,7 +105,7 @@ public int get(ByteBuffer buffer) {
int count = channel.read(buffer);
if(count == -1) result = CONTENT_END;
else if(count == 0) result = CONTENT_PENDING;
else if(count == 0) result = CONTENT_PENDING; //Note: Shouldn't occur since the stream is set to blocking.//
else {
result = count;
size -= count;