Merge remote-tracking branch 'origin/master' into jetty-http2

Conflicts:
	jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java
This commit is contained in:
Greg Wilkins 2014-08-01 09:50:20 +10:00
commit b439549793
8 changed files with 84 additions and 58 deletions

View File

@ -338,18 +338,15 @@ abstract public class WriteFlusher
if (DEBUG) if (DEBUG)
LOG.debug("flushed {}", flushed); LOG.debug("flushed {}", flushed);
// Are we complete? // if we are incomplete?
for (ByteBuffer b : buffers) if (!flushed)
{ {
if (!flushed||BufferUtil.hasContent(b)) PendingState pending=new PendingState(buffers, callback);
{ if (updateState(__WRITING,pending))
PendingState pending=new PendingState(buffers, callback); onIncompleteFlushed();
if (updateState(__WRITING,pending)) else
onIncompleteFlushed(); fail(pending);
else return;
fail(pending);
return;
}
} }
// If updateState didn't succeed, we don't care as our buffers have been written // If updateState didn't succeed, we don't care as our buffers have been written
@ -403,17 +400,14 @@ abstract public class WriteFlusher
if (DEBUG) if (DEBUG)
LOG.debug("flushed {}", flushed); LOG.debug("flushed {}", flushed);
// Are we complete? // if we are incomplete?
for (ByteBuffer b : buffers) if (!flushed)
{ {
if (!flushed || BufferUtil.hasContent(b)) if (updateState(__COMPLETING,pending))
{ onIncompleteFlushed();
if (updateState(__COMPLETING,pending)) else
onIncompleteFlushed(); fail(pending);
else return;
fail(pending);
return;
}
} }
// If updateState didn't succeed, we don't care as our buffers have been written // If updateState didn't succeed, we don't care as our buffers have been written

View File

@ -85,7 +85,7 @@ public class AsyncProxyServlet extends ProxyServlet
catch (Throwable x) catch (Throwable x)
{ {
callback.failed(x); callback.failed(x);
onResponseFailure(request, response, proxyResponse, x); proxyResponse.abort(x);
} }
} }
@ -279,8 +279,7 @@ public class AsyncProxyServlet extends ProxyServlet
@Override @Override
public void onError(Throwable failure) public void onError(Throwable failure)
{ {
HttpServletResponse response = (HttpServletResponse)request.getAsyncContext().getResponse(); proxyResponse.abort(failure);
onResponseFailure(request, response, proxyResponse, failure);
} }
} }

View File

@ -45,6 +45,7 @@ import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.server.HttpChannelState.Action; import org.eclipse.jetty.server.HttpChannelState.Action;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.SharedBlockingCallback.Blocker; import org.eclipse.jetty.util.SharedBlockingCallback.Blocker;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
@ -440,10 +441,11 @@ public class HttpChannel implements Runnable
@Override @Override
public String toString() public String toString()
{ {
return String.format("%s@%x{r=%s,a=%s,uri=%s}", return String.format("%s@%x{r=%s,c=%b,a=%s,uri=%s}",
getClass().getSimpleName(), getClass().getSimpleName(),
hashCode(), hashCode(),
_requests, _requests,
_committed.get(),
_state.getState(), _state.getState(),
_state.getState()==HttpChannelState.State.IDLE?"-":_request.getRequestURI() _state.getState()==HttpChannelState.State.IDLE?"-":_request.getRequestURI()
); );
@ -516,7 +518,6 @@ public class HttpChannel implements Runnable
protected boolean sendResponse(ResponseInfo info, ByteBuffer content, boolean complete, final Callback callback) protected boolean sendResponse(ResponseInfo info, ByteBuffer content, boolean complete, final Callback callback)
{ {
// TODO check that complete only set true once by changing _committed to AtomicRef<Enum>
boolean committing = _committed.compareAndSet(false, true); boolean committing = _committed.compareAndSet(false, true);
if (committing) if (committing)
{ {
@ -524,7 +525,7 @@ public class HttpChannel implements Runnable
if (info==null) if (info==null)
info = _response.newResponseInfo(); info = _response.newResponseInfo();
// wrap callback to process 100 or 500 responses // wrap callback to process 100 responses
final int status=info.getStatus(); final int status=info.getStatus();
final Callback committed = (status<200&&status>=100)?new Commit100Callback(callback):new CommitCallback(callback); final Callback committed = (status<200&&status>=100)?new Commit100Callback(callback):new CommitCallback(callback);
@ -656,8 +657,10 @@ public class HttpChannel implements Runnable
@Override @Override
public void succeeded() public void succeeded()
{ {
_committed.set(false); if (_committed.compareAndSet(true, false))
super.succeeded(); super.succeeded();
else
super.failed(new IllegalStateException());
} }
} }

View File

@ -438,9 +438,9 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
if (info!=null && _channel.isExpecting100Continue()) if (info!=null && _channel.isExpecting100Continue())
// then we can't be persistent // then we can't be persistent
_generator.setPersistent(false); _generator.setPersistent(false);
if (info==null&&!lastContent&&BufferUtil.isEmpty(content))XXXXX else
_sendCallback.reset(info,content,lastContent,callback); if(_sendCallback.reset(info,content,lastContent,callback))
_sendCallback.iterate(); _sendCallback.iterate();
} }
private class SendCallback extends IteratingCallback private class SendCallback extends IteratingCallback
@ -457,7 +457,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
super(true); super(true);
} }
private void reset(ResponseInfo info, ByteBuffer content, boolean last, Callback callback) private boolean reset(ResponseInfo info, ByteBuffer content, boolean last, Callback callback)
{ {
if (reset()) if (reset())
{ {
@ -467,15 +467,14 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
_callback = callback; _callback = callback;
_header = null; _header = null;
_shutdownOut = false; _shutdownOut = false;
return true;
} }
else if (isClosed())
{ if (isClosed())
callback.failed(new EofException()); callback.failed(new EofException());
}
else else
{
callback.failed(new WritePendingException()); callback.failed(new WritePendingException());
} return false;
} }
@Override @Override
@ -561,7 +560,9 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
getEndPoint().write(this, _content); getEndPoint().write(this, _content);
} }
else else
continue; {
succeeded(); // nothing to write
}
return Action.SCHEDULED; return Action.SCHEDULED;
} }
case SHUTDOWN_OUT: case SHUTDOWN_OUT:
@ -571,7 +572,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
} }
case DONE: case DONE:
{ {
releaseHeader();
return Action.SUCCEEDED; return Action.SUCCEEDED;
} }
case CONTINUE: case CONTINUE:

View File

@ -30,6 +30,7 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -41,6 +42,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpParser;
import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
@ -49,6 +51,7 @@ import org.hamcrest.Matchers;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
/** /**
@ -69,7 +72,7 @@ public class HttpConnectionTest
http.getHttpConfiguration().setResponseHeaderSize(1024); http.getHttpConfiguration().setResponseHeaderSize(1024);
connector = new LocalConnector(server,http,null); connector = new LocalConnector(server,http,null);
connector.setIdleTimeout(500); connector.setIdleTimeout(5000);
server.addConnector(connector); server.addConnector(connector);
server.setHandler(new DumpHandler()); server.setHandler(new DumpHandler());
ErrorHandler eh=new ErrorHandler(); ErrorHandler eh=new ErrorHandler();
@ -324,6 +327,31 @@ public class HttpConnectionTest
offset = checkContains(response,offset,"/R1"); offset = checkContains(response,offset,"/R1");
offset = checkContains(response,offset,"12345"); offset = checkContains(response,offset,"12345");
} }
@Test
public void testEmptyFlush() throws Exception
{
server.stop();
server.setHandler(new AbstractHandler()
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
response.setStatus(200);
OutputStream out =response.getOutputStream();
out.flush();
out.flush();
}
});
server.start();
String response=connector.getResponses("GET / HTTP/1.1\n"+
"Host: localhost\n"+
"Connection: close\n"+
"\n");
assertThat(response, Matchers.containsString("200 OK"));
}
@Test @Test
public void testCharset() throws Exception public void testCharset() throws Exception
@ -431,6 +459,7 @@ public class HttpConnectionTest
@Test @Test
public void testUnconsumedTimeout() throws Exception public void testUnconsumedTimeout() throws Exception
{ {
connector.setIdleTimeout(500);
String response=null; String response=null;
String requests=null; String requests=null;
int offset=0; int offset=0;

View File

@ -136,7 +136,7 @@ public class AsyncGzipFilter extends UserAgentFilter implements GzipFactory
protected ServletContext _context; protected ServletContext _context;
protected final Set<String> _mimeTypes=new HashSet<>(); protected final Set<String> _mimeTypes=new HashSet<>();
protected boolean _excludeMimeTypes; protected boolean _excludeMimeTypes;
protected int _bufferSize=8192; protected int _bufferSize=32*1024;
protected int _minGzipSize=DEFAULT_MIN_GZIP_SIZE; protected int _minGzipSize=DEFAULT_MIN_GZIP_SIZE;
protected int _deflateCompressionLevel=Deflater.DEFAULT_COMPRESSION; protected int _deflateCompressionLevel=Deflater.DEFAULT_COMPRESSION;
protected boolean _deflateNoWrap = true; protected boolean _deflateNoWrap = true;

View File

@ -78,14 +78,16 @@ public class GzipHttpOutput extends HttpOutput
break; break;
case COMMITTING: case COMMITTING:
throw new WritePendingException(); callback.failed(new WritePendingException());
break;
case COMPRESSING: case COMPRESSING:
gzip(content,complete,callback); gzip(content,complete,callback);
break; break;
case FINISHED: default:
throw new IllegalStateException(); callback.failed(new IllegalStateException("state="+_state.get()));
break;
} }
} }
@ -122,6 +124,8 @@ public class GzipHttpOutput extends HttpOutput
else else
new GzipBufferCB(content,complete,callback).iterate(); new GzipBufferCB(content,complete,callback).iterate();
} }
else
callback.succeeded();
} }
protected void commit(ByteBuffer content, boolean complete, Callback callback) protected void commit(ByteBuffer content, boolean complete, Callback callback)
@ -198,7 +202,8 @@ public class GzipHttpOutput extends HttpOutput
gzip(content,complete,callback); gzip(content,complete,callback);
} }
// TODO else ? else
callback.failed(new WritePendingException());
} }
public void noCompression() public void noCompression()

View File

@ -186,16 +186,7 @@ public class SharedBlockingCallback
try try
{ {
while (_state == null) while (_state == null)
{ _complete.await();
// TODO remove this debug timout!
// This is here to help debug 435322,
if (!_complete.await(10,TimeUnit.MINUTES))
{
IOException x = new IOException("DEBUG timeout");
LOG.warn("Blocked too long (please report!!!) "+this, x);
_state=x;
}
}
if (_state == SUCCEEDED) if (_state == SUCCEEDED)
return; return;
@ -241,7 +232,11 @@ public class SharedBlockingCallback
if (_state == IDLE) if (_state == IDLE)
throw new IllegalStateException("IDLE"); throw new IllegalStateException("IDLE");
if (_state == null) if (_state == null)
LOG.debug("Blocker not complete",new Throwable()); {
LOG.warn("Blocker not complete {}",this);
if (LOG.isDebugEnabled())
LOG.debug(new Throwable());
}
} }
finally finally
{ {
@ -249,6 +244,7 @@ public class SharedBlockingCallback
{ {
_state = IDLE; _state = IDLE;
_idle.signalAll(); _idle.signalAll();
_complete.signalAll();
} }
finally finally
{ {
@ -263,7 +259,7 @@ public class SharedBlockingCallback
_lock.lock(); _lock.lock();
try try
{ {
return String.format("%s@%x{%s}",SharedBlockingCallback.class.getSimpleName(),hashCode(),_state); return String.format("%s@%x{%s}",Blocker.class.getSimpleName(),hashCode(),_state);
} }
finally finally
{ {