394370 correctly handle last content and responses with no content

This commit is contained in:
Greg Wilkins 2012-11-16 12:42:52 +11:00
parent 62e033fcd0
commit 139de22bc0
3 changed files with 56 additions and 8 deletions

View File

@ -584,6 +584,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
// TODO is it worthwhile sending if we are at EoF?
// "application" info failed to commit, commit with a failsafe 500 info
_transport.send(HttpGenerator.RESPONSE_500_INFO,null,true);
complete=true;
throw e;
}
catch (Exception e)
@ -591,8 +592,15 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
LOG.warn(e);
// "application" info failed to commit, commit with a failsafe 500 info
_transport.send(HttpGenerator.RESPONSE_500_INFO,null,true);
complete=true;
throw e;
}
finally
{
// TODO this indicates the relationship with HttpOutput is not exactly correct
if (complete)
_response.getHttpOutput().closed();
}
}
return committed;
}

View File

@ -82,6 +82,19 @@ public class HttpOutput extends ServletOutputStream
{
_closed = false;
}
/** Called by the HttpChannel if the output was closed
* externally (eg by a 500 exception handling).
*/
void closed()
{
_closed = true;
if (_aggregate != null)
{
_channel.getConnector().getByteBufferPool().release(_aggregate);
_aggregate = null;
}
}
@Override
public void close()
@ -259,7 +272,8 @@ public class HttpOutput extends ServletOutputStream
// Process content.
if (content instanceof ByteBuffer)
{
_channel.write((ByteBuffer)content, true); // TODO: we have written all content ?
_channel.write((ByteBuffer)content, true);
_closed=true;
}
else if (content instanceof ReadableByteChannel)
{
@ -301,7 +315,6 @@ public class HttpOutput extends ServletOutputStream
buffer.limit(len);
_channel.write(buffer,false);
}
_channel.write(BufferUtil.EMPTY_BUFFER,true);
}
finally
{

View File

@ -70,6 +70,16 @@ public class HttpTransportOverSPDY implements HttpTransport
@Override
public <C> void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, C context, Callback<C> callback)
{
if (LOG.isDebugEnabled())
LOG.debug("send {} {} {} {} last={}%n",this,stream,info,BufferUtil.toDetailString(content),lastContent);
if (stream.isClosed() || stream.isReset() )
{
callback.failed(context,new EofException("stream closed"));
return;
}
// new Throwable().printStackTrace();
// info==null content==null lastContent==false should not happen
// info==null content==null lastContent==true signals no more content - complete
// info==null content!=null lastContent==false send data on committed response
@ -114,17 +124,34 @@ public class HttpTransportOverSPDY implements HttpTransport
}
boolean close = !hasContent && lastContent;
reply(stream, new ReplyInfo(headers, close));
ReplyInfo reply = new ReplyInfo(headers,close);
reply(stream, reply);
}
if ((hasContent || lastContent ) && !stream.isClosed() )
// Do we have some content to send as well
if (hasContent)
{
if (content==null)
content=BufferUtil.EMPTY_BUFFER;
stream.data(new ByteBufferDataInfo(content, lastContent),endPoint.getIdleTimeout(),TimeUnit.MILLISECONDS,context,callback);
// Is the stream still open?
if (stream.isClosed()|| stream.isReset())
// tell the callback about the EOF
callback.failed(context,new EofException("stream closed"));
else
// send the data and let it call the callback
stream.data(new ByteBufferDataInfo(content, lastContent),endPoint.getIdleTimeout(),TimeUnit.MILLISECONDS,context,callback);
}
// else do we need to close
else if (lastContent)
{
// Are we closed ?
if (stream.isClosed()|| stream.isReset())
// already closed by reply, so just tell callback we are complete
callback.completed(context);
else
// send empty data to close and let the send call the callback
stream.data(new ByteBufferDataInfo(BufferUtil.EMPTY_BUFFER, lastContent),endPoint.getIdleTimeout(),TimeUnit.MILLISECONDS,context,callback);
}
else
// No data and no close so tell callback we are completed
callback.completed(context);
}