package org.eclipse.jetty.servlet;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import junit.framework.Assert;
import org.eclipse.jetty.continuation.ContinuationSupport;
import org.eclipse.jetty.server.AsyncContext;
import org.eclipse.jetty.server.AsyncContinuation;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.DispatcherType;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* This tests the correct functioning of the AsyncContext
*
* tests for #371649 and #371635
*/
public class AsyncContextTest
{
private Server _server = new Server();
private ServletContextHandler _contextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
private LocalConnector _connector = new LocalConnector();
@Before
public void setUp() throws Exception
{
_connector.setMaxIdleTime(30000);
_server.setConnectors(new Connector[]
{ _connector });
_contextHandler.setContextPath("/");
_contextHandler.addServlet(new ServletHolder(new TestServlet()),"/servletPath");
_contextHandler.addServlet(new ServletHolder(new TestServlet()),"/path with spaces/servletPath");
_contextHandler.addServlet(new ServletHolder(new TestServlet2()),"/servletPath2");
_contextHandler.addServlet(new ServletHolder(new ForwardingServlet()),"/forward");
_contextHandler.addServlet(new ServletHolder(new AsyncDispatchingServlet()),"/dispatchingServlet");
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[]
{ _contextHandler, new DefaultHandler() });
_server.setHandler(handlers);
_server.start();
}
@Test
public void testSimpleAsyncContext() throws Exception
{
String request = "GET /servletPath HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
+ "Connection: close\r\n" + "\r\n";
String responseString = _connector.getResponses(request);
BufferedReader br = parseHeader(responseString);
Assert.assertEquals("servlet gets right path","doGet:getServletPath:/servletPath",br.readLine());
Assert.assertEquals("async context gets right path in get","doGet:async:getServletPath:/servletPath",br.readLine());
Assert.assertEquals("async context gets right path in async","async:run:attr:servletPath:/servletPath",br.readLine());
}
@Test
public void testDispatchAsyncContext() throws Exception
{
String request = "GET /servletPath?dispatch=true HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
+ "Connection: close\r\n" + "\r\n";
String responseString = _connector.getResponses(request);
BufferedReader br = parseHeader(responseString);
Assert.assertEquals("servlet gets right path","doGet:getServletPath:/servletPath2",br.readLine());
Assert.assertEquals("async context gets right path in get","doGet:async:getServletPath:/servletPath2",br.readLine());
Assert.assertEquals("servlet path attr is original","async:run:attr:servletPath:/servletPath",br.readLine());
Assert.assertEquals("path info attr is correct","async:run:attr:pathInfo:null",br.readLine());
Assert.assertEquals("query string attr is correct","async:run:attr:queryString:dispatch=true",br.readLine());
Assert.assertEquals("context path attr is correct","async:run:attr:contextPath:",br.readLine());
Assert.assertEquals("request uri attr is correct","async:run:attr:requestURI:/servletPath",br.readLine());
}
@Test
public void testDispatchAsyncContextEncodedPathAndQueryString() throws Exception
{
String request = "GET /path%20with%20spaces/servletPath?dispatch=true&queryStringWithEncoding=space%20space HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
+ "Connection: close\r\n" + "\r\n";
String responseString = _connector.getResponses(request);
BufferedReader br = parseHeader(responseString);
assertThat("servlet gets right path",br.readLine(),equalTo("doGet:getServletPath:/servletPath2"));
assertThat("async context gets right path in get",br.readLine(), equalTo("doGet:async:getServletPath:/servletPath2"));
assertThat("servlet path attr is original",br.readLine(),equalTo("async:run:attr:servletPath:/path with spaces/servletPath"));
assertThat("path info attr is correct",br.readLine(),equalTo("async:run:attr:pathInfo:null"));
assertThat("query string attr is correct",br.readLine(),equalTo("async:run:attr:queryString:dispatch=true&queryStringWithEncoding=space%20space"));
assertThat("context path attr is correct",br.readLine(),equalTo("async:run:attr:contextPath:"));
assertThat("request uri attr is correct",br.readLine(),equalTo("async:run:attr:requestURI:/path%20with%20spaces/servletPath"));
}
@Test
public void testSimpleWithContextAsyncContext() throws Exception
{
_contextHandler.setContextPath("/foo");
String request = "GET /foo/servletPath HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
+ "Connection: close\r\n" + "\r\n";
String responseString = _connector.getResponses(request);
BufferedReader br = parseHeader(responseString);
Assert.assertEquals("servlet gets right path","doGet:getServletPath:/servletPath",br.readLine());
Assert.assertEquals("async context gets right path in get","doGet:async:getServletPath:/servletPath",br.readLine());
Assert.assertEquals("async context gets right path in async","async:run:attr:servletPath:/servletPath",br.readLine());
}
@Test
public void testDispatchWithContextAsyncContext() throws Exception
{
_contextHandler.setContextPath("/foo");
String request = "GET /foo/servletPath?dispatch=true HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
+ "Connection: close\r\n" + "\r\n";
String responseString = _connector.getResponses(request);
BufferedReader br = parseHeader(responseString);
Assert.assertEquals("servlet gets right path","doGet:getServletPath:/servletPath2",br.readLine());
Assert.assertEquals("async context gets right path in get","doGet:async:getServletPath:/servletPath2",br.readLine());
Assert.assertEquals("servlet path attr is original","async:run:attr:servletPath:/servletPath",br.readLine());
Assert.assertEquals("path info attr is correct","async:run:attr:pathInfo:null",br.readLine());
Assert.assertEquals("query string attr is correct","async:run:attr:queryString:dispatch=true",br.readLine());
Assert.assertEquals("context path attr is correct","async:run:attr:contextPath:/foo",br.readLine());
Assert.assertEquals("request uri attr is correct","async:run:attr:requestURI:/foo/servletPath",br.readLine());
}
@Test
public void testDispatch() throws Exception
{
String request = "GET /forward HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Connection: close\r\n"
+ "\r\n";
String responseString = _connector.getResponses(request);
BufferedReader br = parseHeader(responseString);
assertThat("!ForwardingServlet",br.readLine(),equalTo("Dispatched back to ForwardingServlet"));
}
@Test
public void testDispatchRequestResponse() throws Exception
{
String request = "GET /forward?dispatchRequestResponse=true HTTP/1.1\r\n" + "Host: localhost\r\n"
+ "Content-Type: application/x-www-form-urlencoded\r\n" + "Connection: close\r\n" + "\r\n";
String responseString = _connector.getResponses(request);
BufferedReader br = parseHeader(responseString);
assertThat("!AsyncDispatchingServlet",br.readLine(),equalTo("Dispatched back to AsyncDispatchingServlet"));
}
private BufferedReader parseHeader(String responseString) throws IOException
{
BufferedReader br = new BufferedReader(new StringReader(responseString));
assertEquals("HTTP/1.1 200 OK",br.readLine());
br.readLine();// connection close
br.readLine();// server
br.readLine();// empty
return br;
}
private class ForwardingServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
@Override
protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
{
if (((Request)request).getDispatcherType() == DispatcherType.ASYNC)
{
response.getOutputStream().print("Dispatched back to ForwardingServlet");
}
else
{
request.getRequestDispatcher("/dispatchingServlet").forward(request,response);
}
}
}
private class AsyncDispatchingServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, final HttpServletResponse response) throws ServletException, IOException
{
Request request = (Request)req;
if (request.getDispatcherType() == DispatcherType.ASYNC)
{
response.getOutputStream().print("Dispatched back to AsyncDispatchingServlet");
}
else
{
final AsyncContext asyncContext;
if (request.getParameter("dispatchRequestResponse") != null)
{
asyncContext = request.startAsync(request,response);
}
else
{
asyncContext = request.startAsync();
}
new Thread(new DispatchingRunnable(asyncContext)).start();
}
}
}
private class DispatchingRunnable implements Runnable
{
private AsyncContext asyncContext;
public DispatchingRunnable(AsyncContext asyncContext)
{
this.asyncContext = asyncContext;
}
public void run()
{
asyncContext.dispatch();
}
}
@After
public void tearDown() throws Exception
{
_server.stop();
_server.join();
}
private class TestServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
AsyncContinuation continuation = (AsyncContinuation)ContinuationSupport.getContinuation(request);
if (request.getParameter("dispatch") != null)
{
continuation.suspend();
continuation.dispatch("/servletPath2");
// AsyncContext asyncContext = request.startAsync(request,response);
}
else
{
response.getOutputStream().print("doGet:getServletPath:" + request.getServletPath() + "\n");
continuation.suspend();
// AsyncContext asyncContext = request.startAsync(request,response);
response.getOutputStream().print("doGet:async:getServletPath:" + ((HttpServletRequest)continuation.getRequest()).getServletPath() + "\n");
Runnable runable = new AsyncRunnable(continuation);
new Thread(runable).start();
// asyncContext.start(new AsyncRunnable(asyncContext));
}
return;
}
}
private class TestServlet2 extends HttpServlet
{
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
AsyncContinuation continuation = (AsyncContinuation)ContinuationSupport.getContinuation(request);
response.getOutputStream().print("doGet:getServletPath:" + request.getServletPath() + "\n");
continuation.suspend();
// AsyncContext asyncContext = request.startAsync(request, response);
response.getOutputStream().print("doGet:async:getServletPath:" + ((HttpServletRequest)continuation.getRequest()).getServletPath() + "\n");
Runnable runable = new AsyncRunnable(continuation);
new Thread(runable).start();
// asyncContext.start(new AsyncRunnable(asyncContext));
return;
}
}
private class AsyncRunnable implements Runnable
{
private AsyncContinuation _continuation;
public AsyncRunnable(AsyncContinuation continuation)
{
_continuation = continuation;
}
public void run()
{
HttpServletRequest req = (HttpServletRequest)_continuation.getRequest();
try
{
_continuation.getResponse().getOutputStream().print("async:run:attr:servletPath:" + req.getAttribute(AsyncContext.ASYNC_SERVLET_PATH) + "\n");
_continuation.getResponse().getOutputStream().print("async:run:attr:pathInfo:" + req.getAttribute(AsyncContext.ASYNC_PATH_INFO) + "\n");
_continuation.getResponse().getOutputStream().print("async:run:attr:queryString:" + req.getAttribute(AsyncContext.ASYNC_QUERY_STRING) + "\n");
_continuation.getResponse().getOutputStream().print("async:run:attr:contextPath:" + req.getAttribute(AsyncContext.ASYNC_CONTEXT_PATH) + "\n");
_continuation.getResponse().getOutputStream().print("async:run:attr:requestURI:" + req.getAttribute(AsyncContext.ASYNC_REQUEST_URI) + "\n");
}
catch (IOException e)
{
e.printStackTrace();
}
_continuation.complete();
}
}
}