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:
commit
b439549793
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue