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

Conflicts:
	jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java
	jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java
This commit is contained in:
Greg Wilkins 2013-11-01 14:45:16 +11:00
commit 852be79a3c
6 changed files with 64 additions and 55 deletions

View File

@ -26,8 +26,10 @@ import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException; import java.net.SocketException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousServerSocketChannel;
@ -389,42 +391,40 @@ public class IOTest
@Test @Test
public void testReset() throws Exception public void testReset() throws Exception
{ {
ServerSocket connector; try (ServerSocket connector = new ServerSocket(0);
Socket client; Socket client = new Socket("127.0.0.1", connector.getLocalPort());
Socket server; Socket server = connector.accept();)
{
client.setTcpNoDelay(true);
client.setSoLinger(true, 0);
server.setTcpNoDelay(true);
server.setSoLinger(true, 0);
connector = new ServerSocket(0); client.getOutputStream().write(1);
client = new Socket("127.0.0.1", connector.getLocalPort()); assertEquals(1, server.getInputStream().read());
server = connector.accept(); server.getOutputStream().write(1);
client.setTcpNoDelay(true); assertEquals(1, client.getInputStream().read());
client.setSoLinger(true, 0);
server.setTcpNoDelay(true);
server.setSoLinger(true, 0);
client.getOutputStream().write(1); // Server generator shutdowns output after non persistent sending response.
assertEquals(1, server.getInputStream().read()); server.shutdownOutput();
server.getOutputStream().write(1);
assertEquals(1, client.getInputStream().read());
// Server generator shutdowns output after non persistent sending response. // client endpoint reads EOF and shutdown input as result
server.shutdownOutput(); assertEquals(-1, client.getInputStream().read());
client.shutdownInput();
// client endpoint reads EOF and shutdown input as result // client connection see's EOF and shutsdown output as no more requests to be sent.
assertEquals(-1, client.getInputStream().read()); client.shutdownOutput();
client.shutdownInput();
// client connection see's EOF and shutsdown output as no more requests to be sent. // Since input already shutdown, client also closes socket.
client.shutdownOutput(); client.close();
// Since input already shutdown, client also closes socket. // Server reads the EOF from client oshut and shut's down it's input
client.close(); assertEquals(-1, server.getInputStream().read());
server.shutdownInput();
// Server reads the EOF from client oshut and shut's down it's input // Since output was already shutdown, server closes
assertEquals(-1, server.getInputStream().read()); server.close();
server.shutdownInput(); }
// Since output was already shutdown, server closes
server.close();
} }
@Test @Test
@ -432,10 +432,12 @@ public class IOTest
{ {
AsynchronousServerSocketChannel connector = AsynchronousServerSocketChannel.open(); AsynchronousServerSocketChannel connector = AsynchronousServerSocketChannel.open();
connector.bind(null); connector.bind(null);
InetSocketAddress addr=(InetSocketAddress)connector.getLocalAddress();
Future<AsynchronousSocketChannel> acceptor = connector.accept(); Future<AsynchronousSocketChannel> acceptor = connector.accept();
AsynchronousSocketChannel client = AsynchronousSocketChannel.open(); AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
client.connect(connector.getLocalAddress()).get(5, TimeUnit.SECONDS);
client.connect(new InetSocketAddress("127.0.0.1",addr.getPort())).get(5, TimeUnit.SECONDS);
AsynchronousSocketChannel server = acceptor.get(5, TimeUnit.SECONDS); AsynchronousSocketChannel server = acceptor.get(5, TimeUnit.SECONDS);

View File

@ -413,9 +413,12 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
{ {
try try
{ {
_request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,x);
_request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,x.getClass());
if (_state.isSuspended()) if (_state.isSuspended())
{ {
HttpFields fields = new HttpFields(); HttpFields fields = new HttpFields();
fields.add(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);
ResponseInfo info = new ResponseInfo(_request.getHttpVersion(), fields, 0, HttpStatus.INTERNAL_SERVER_ERROR_500, null, _request.isHead()); ResponseInfo info = new ResponseInfo(_request.getHttpVersion(), fields, 0, HttpStatus.INTERNAL_SERVER_ERROR_500, null, _request.isHead());
boolean committed = sendResponse(info, null, true); boolean committed = sendResponse(info, null, true);
if (!committed) if (!committed)
@ -429,8 +432,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
} }
else else
{ {
_request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,x); _response.setHeader(HttpHeader.CONNECTION.asString(),HttpHeaderValue.CLOSE.asString());
_request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,x.getClass());
_response.sendError(500, x.getMessage()); _response.sendError(500, x.getMessage());
} }
} }

View File

@ -461,7 +461,7 @@ public class HttpConnectionTest
offset=0; offset=0;
requests= requests=
"GET /R1?read=1&error=599 HTTP/1.1\n"+ "GET /R1?read=1&error=499 HTTP/1.1\n"+
"Host: localhost\n"+ "Host: localhost\n"+
"Transfer-Encoding: chunked\n"+ "Transfer-Encoding: chunked\n"+
"Content-Type: text/plain; charset=utf-8\n"+ "Content-Type: text/plain; charset=utf-8\n"+
@ -481,7 +481,7 @@ public class HttpConnectionTest
response=connector.getResponses(requests); response=connector.getResponses(requests);
offset = checkContains(response,offset,"HTTP/1.1 599"); offset = checkContains(response,offset,"HTTP/1.1 499");
offset = checkContains(response,offset,"HTTP/1.1 200"); offset = checkContains(response,offset,"HTTP/1.1 200");
offset = checkContains(response,offset,"/R2"); offset = checkContains(response,offset,"/R2");
offset = checkContains(response,offset,"encoding=UTF-8"); offset = checkContains(response,offset,"encoding=UTF-8");

View File

@ -51,6 +51,8 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.PathMap; import org.eclipse.jetty.http.PathMap;
import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.RuntimeIOException; import org.eclipse.jetty.io.RuntimeIOException;
@ -499,7 +501,7 @@ public class ServletHandler extends ScopedHandler
} }
LOG.debug("chain={}",chain); LOG.debug("chain={}",chain);
Throwable th=null;
try try
{ {
if (servlet_holder==null) if (servlet_holder==null)
@ -547,7 +549,7 @@ public class ServletHandler extends ScopedHandler
} }
// unwrap cause // unwrap cause
Throwable th=e; th=e;
if (th instanceof ServletException) if (th instanceof ServletException)
{ {
if (th instanceof QuietServletException) if (th instanceof QuietServletException)
@ -573,6 +575,7 @@ public class ServletHandler extends ScopedHandler
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,th); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,th);
if (!response.isCommitted()) if (!response.isCommitted())
{ {
baseRequest.getResponse().getHttpFields().put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);
if (th instanceof UnavailableException) if (th instanceof UnavailableException)
{ {
UnavailableException ue = (UnavailableException)th; UnavailableException ue = (UnavailableException)th;
@ -586,33 +589,34 @@ public class ServletHandler extends ScopedHandler
} }
else else
LOG.debug("Response already committed",th); LOG.debug("Response already committed",th);
// Complete async requests
if (request.isAsyncStarted())
request.getAsyncContext().complete();
} }
catch(Error e) catch(Error e)
{ {
if ("ContinuationThrowable".equals(e.getClass().getSimpleName())) if ("ContinuationThrowable".equals(e.getClass().getSimpleName()))
throw e; throw e;
th=e;
if (!(DispatcherType.REQUEST.equals(type) || DispatcherType.ASYNC.equals(type))) if (!(DispatcherType.REQUEST.equals(type) || DispatcherType.ASYNC.equals(type)))
throw e; throw e;
LOG.warn("Error for "+request.getRequestURI(),e); LOG.warn("Error for "+request.getRequestURI(),e);
if(LOG.isDebugEnabled())LOG.debug(request.toString()); if(LOG.isDebugEnabled())
LOG.debug(request.toString());
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,e.getClass()); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,e.getClass());
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,e); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
if (!response.isCommitted()) if (!response.isCommitted())
{
baseRequest.getResponse().getHttpFields().put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
else else
LOG.debug("Response already committed for handling ",e); LOG.debug("Response already committed for handling ",e);
// Complete async requests
if (request.isAsyncStarted())
request.getAsyncContext().complete();
} }
finally finally
{ {
// Complete async errored requests
if (th!=null && request.isAsyncStarted())
request.getAsyncContext().complete();
if (servlet_holder!=null) if (servlet_holder!=null)
baseRequest.setHandled(true); baseRequest.setHandled(true);
} }

View File

@ -239,9 +239,8 @@ public abstract class ContinuationBase
int port=_port; int port=_port;
String response=null; String response=null;
try try (Socket socket = new Socket("localhost",port);)
{ {
Socket socket = new Socket("localhost",port);
socket.setSoTimeout(10000); socket.setSoTimeout(10000);
socket.getOutputStream().write(request.getBytes("UTF-8")); socket.getOutputStream().write(request.getBytes("UTF-8"));
socket.getOutputStream().flush(); socket.getOutputStream().flush();
@ -269,6 +268,7 @@ public abstract class ContinuationBase
{} {}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@Override
protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
{ {
final Continuation continuation = ContinuationSupport.getContinuation(request); final Continuation continuation = ContinuationSupport.getContinuation(request);
@ -306,7 +306,7 @@ public abstract class ContinuationBase
if (continuation.isInitial()) if (continuation.isInitial())
{ {
((HttpServletResponse)response).addHeader("history","initial"); response.addHeader("history","initial");
if (read_before>0) if (read_before>0)
{ {
byte[] buf=new byte[read_before]; byte[] buf=new byte[read_before];
@ -325,7 +325,7 @@ public abstract class ContinuationBase
if (suspend_for>0) if (suspend_for>0)
continuation.setTimeout(suspend_for); continuation.setTimeout(suspend_for);
continuation.addContinuationListener(__listener); continuation.addContinuationListener(__listener);
((HttpServletResponse)response).addHeader("history","suspend"); response.addHeader("history","suspend");
continuation.suspend(response); continuation.suspend(response);
if (complete_after>0) if (complete_after>0)
@ -404,7 +404,7 @@ public abstract class ContinuationBase
} }
else else
{ {
((HttpServletResponse)response).addHeader("history","!initial"); response.addHeader("history","!initial");
if (suspend2_for>=0 && request.getAttribute("2nd")==null) if (suspend2_for>=0 && request.getAttribute("2nd")==null)
{ {
request.setAttribute("2nd","cycle"); request.setAttribute("2nd","cycle");
@ -412,7 +412,7 @@ public abstract class ContinuationBase
if (suspend2_for>0) if (suspend2_for>0)
continuation.setTimeout(suspend2_for); continuation.setTimeout(suspend2_for);
// continuation.addContinuationListener(__listener); // continuation.addContinuationListener(__listener);
((HttpServletResponse)response).addHeader("history","suspend"); response.addHeader("history","suspend");
continuation.suspend(response); continuation.suspend(response);
if (complete2_after>0) if (complete2_after>0)
@ -452,7 +452,7 @@ public abstract class ContinuationBase
@Override @Override
public void run() public void run()
{ {
((HttpServletResponse)response).addHeader("history","resume"); response.addHeader("history","resume");
continuation.resume(); continuation.resume();
} }
}; };
@ -463,7 +463,7 @@ public abstract class ContinuationBase
} }
else if (resume2_after==0) else if (resume2_after==0)
{ {
((HttpServletResponse)response).addHeader("history","resume"); response.addHeader("history","resume");
continuation.resume(); continuation.resume();
} }
if (undispatch) if (undispatch)

View File

@ -23,7 +23,7 @@ import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import junit.framework.Assert; import org.junit.Assert;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
@ -194,6 +194,7 @@ public class ContinuationTest extends ContinuationBase
class Log extends AbstractLifeCycle implements RequestLog class Log extends AbstractLifeCycle implements RequestLog
{ {
@Override
public void log(Request request, Response response) public void log(Request request, Response response)
{ {
_log.add(response.getStatus()+" "+response.getContentCount()+" "+request.getRequestURI()); _log.add(response.getStatus()+" "+response.getContentCount()+" "+request.getRequestURI());