461452 Double release of buffer by HttpReceiverOverHTTP

This commit is just a tidy up of the code to reduce the size of the race causing this problem.  It is not a fix.
This commit is contained in:
Greg Wilkins 2015-03-05 11:05:35 +11:00
parent 40ad8dc608
commit 8cbab09527
1 changed files with 30 additions and 24 deletions

View File

@ -64,27 +64,29 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
public void receive() public void receive()
{ {
buffer = acquireBuffer(); if (buffer==null)
process(buffer); acquireBuffer();
process();
} }
private ByteBuffer acquireBuffer() private void acquireBuffer()
{ {
HttpClient client = getHttpDestination().getHttpClient(); HttpClient client = getHttpDestination().getHttpClient();
ByteBufferPool bufferPool = client.getByteBufferPool(); ByteBufferPool bufferPool = client.getByteBufferPool();
return bufferPool.acquire(client.getResponseBufferSize(), true); buffer = bufferPool.acquire(client.getResponseBufferSize(), true);
} }
private void releaseBuffer(ByteBuffer buffer) private void releaseBuffer()
{ {
assert this.buffer == buffer; if (buffer==null)
throw new IllegalStateException();
HttpClient client = getHttpDestination().getHttpClient(); HttpClient client = getHttpDestination().getHttpClient();
ByteBufferPool bufferPool = client.getByteBufferPool(); ByteBufferPool bufferPool = client.getByteBufferPool();
bufferPool.release(buffer); bufferPool.release(buffer);
this.buffer = null; buffer = null;
} }
private void process(ByteBuffer buffer) private void process()
{ {
try try
{ {
@ -97,11 +99,11 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("{} closed", connection); LOG.debug("{} closed", connection);
releaseBuffer(buffer); releaseBuffer();
return; return;
} }
if (!parse(buffer)) if (parse())
return; return;
int read = endPoint.fill(buffer); int read = endPoint.fill(buffer);
@ -110,18 +112,18 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
if (read > 0) if (read > 0)
{ {
if (!parse(buffer)) if (parse())
return; return;
} }
else if (read == 0) else if (read == 0)
{ {
releaseBuffer(buffer); releaseBuffer();
fillInterested(); fillInterested();
return; return;
} }
else else
{ {
releaseBuffer(buffer); releaseBuffer();
shutdown(); shutdown();
return; return;
} }
@ -131,7 +133,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug(x); LOG.debug(x);
releaseBuffer(buffer); releaseBuffer();
failAndClose(x); failAndClose(x);
} }
} }
@ -140,10 +142,9 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
* Parses a HTTP response from the given {@code buffer}. * Parses a HTTP response from the given {@code buffer}.
* *
* @param buffer the response bytes * @param buffer the response bytes
* @return true to indicate that the parsing may proceed (for example with another response), * @return true to indicate that parsing should be interrupted (and will be resumed by another thread).
* false to indicate that the parsing should be interrupted (and will be resumed by another thread).
*/ */
private boolean parse(ByteBuffer buffer) private boolean parse()
{ {
// Must parse even if the buffer is fully consumed, to allow the // Must parse even if the buffer is fully consumed, to allow the
// parser to advance from asynchronous content to response complete. // parser to advance from asynchronous content to response complete.
@ -151,13 +152,18 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Parsed {}, remaining {} {}", handle, buffer.remaining(), parser); LOG.debug("Parsed {}, remaining {} {}", handle, buffer.remaining(), parser);
if (!handle) if (handle)
return true; {
// There are several cases here:
// a) the content is being handled asynchronously and resume will eventually call process(). Return false.
// b) the content has already been handled asynchronously, resume called process and processing is ongoing. Return false.
// c) the content has already been handled asynchronously, resume called process which completed the response. Return false.
// d) This call to parse called parseNext, which completed the response. Return true
// If the parser returns true, we need to differentiate two cases: return !parser.isStart(); // TODO this is insufficient to distinguish the last to cases above
// A) the response is completed, so the parser is in START state; }
// B) the content is handled asynchronously, so the parser is in CONTENT state.
return parser.isStart(); return false;
} }
protected void fillInterested() protected void fillInterested()
@ -244,7 +250,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Content consumed asynchronously, resuming processing"); LOG.debug("Content consumed asynchronously, resuming processing");
process(getResponseBuffer()); process();
} }
public void abort(Throwable x) public void abort(Throwable x)