[Bug #371635] and [Bug #371649] add missing attributes (non-optimal) and resolve async flow issue with scoping

This commit is contained in:
Jesse McConnell 2012-02-21 10:34:11 -06:00
parent af07ce4b6c
commit a90c3201e8
4 changed files with 293 additions and 10 deletions

View File

@ -370,6 +370,9 @@ public class Server extends HandlerWrapper implements Attributes
baseRequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING,baseRequest.getQueryString());
baseRequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,state.getSuspendedContext().getContextPath());
// Part of #371649 reset here since we skip it in finally
baseRequest.setServletPath(null);
final String contextPath=state.getServletContext().getContextPath();
HttpURI uri = new HttpURI(URIUtil.addPaths(contextPath,path));

View File

@ -971,6 +971,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
}
finally
{
if (old_context != _scontext)
{
// reset the classloader
@ -983,8 +984,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
baseRequest.setContext(old_context);
__context.set(old_context);
baseRequest.setContextPath(old_context_path);
baseRequest.setServletPath(old_servlet_path);
baseRequest.setPathInfo(old_path_info);
// #371649 if we have started async then we need to protect this state
if (!baseRequest.getAsyncContinuation().isAsyncStarted())
{
baseRequest.setServletPath(old_servlet_path);
baseRequest.setPathInfo(old_path_info);
}
}
}
}

View File

@ -45,6 +45,7 @@ import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.AsyncContext;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.DispatcherType;
import org.eclipse.jetty.server.Request;
@ -351,7 +352,7 @@ public class ServletHandler extends ScopedHandler
// Get the base requests
final String old_servlet_path=baseRequest.getServletPath();
final String old_path_info=baseRequest.getPathInfo();
DispatcherType type = baseRequest.getDispatcherType();
ServletHolder servlet_holder=null;
@ -376,7 +377,7 @@ public class ServletHandler extends ScopedHandler
baseRequest.setAttribute(Dispatcher.INCLUDE_PATH_INFO, path_info);
}
else
{
{
baseRequest.setServletPath(servlet_path);
baseRequest.setPathInfo(path_info);
}
@ -397,6 +398,21 @@ public class ServletHandler extends ScopedHandler
old_scope=baseRequest.getUserIdentityScope();
baseRequest.setUserIdentityScope(servlet_holder);
/*
* this is an interim solution for Bug 371635
*
* these will always be set now, when they ought to only be set on the dispatch
*/
if ( baseRequest.getAttribute(AsyncContext.ASYNC_SERVLET_PATH) == null )
{
baseRequest.setAttribute(AsyncContext.ASYNC_SERVLET_PATH,baseRequest.getServletPath());
}
if ( baseRequest.getAttribute(AsyncContext.ASYNC_PATH_INFO) == null )
{
baseRequest.setAttribute(AsyncContext.ASYNC_PATH_INFO,baseRequest.getPathInfo());
}
// start manual inline of nextScope(target,baseRequest,request,response);
if (never())
nextScope(target,baseRequest,request,response);
@ -410,13 +426,18 @@ public class ServletHandler extends ScopedHandler
}
finally
{
if (old_scope!=null)
baseRequest.setUserIdentityScope(old_scope);
if (!(DispatcherType.INCLUDE.equals(type)))
// #371649 if we have started async then we need to protect this state
if (!baseRequest.getAsyncContinuation().isAsyncStarted())
{
baseRequest.setServletPath(old_servlet_path);
baseRequest.setPathInfo(old_path_info);
if (old_scope != null)
baseRequest.setUserIdentityScope(old_scope);
if (!(DispatcherType.INCLUDE.equals(type)))
{
baseRequest.setServletPath(old_servlet_path);
baseRequest.setPathInfo(old_path_info);
}
}
}
}

View File

@ -0,0 +1,253 @@
package org.eclipse.jetty.servlet;
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.Handler;
import org.eclipse.jetty.server.LocalConnector;
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.Ignore;
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 TestServlet2()),"/servletPath2");
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[]
{ _contextHandler, new DefaultHandler() });
_server.setHandler(handlers);
_server.start();
}
@Test
//Ignore ("test fails without a patch")
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 = new BufferedReader(new StringReader(responseString));
Assert.assertEquals("HTTP/1.1 200 OK",br.readLine());
br.readLine();// connection close
br.readLine();// server
br.readLine();// empty
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:/servletPath", br.readLine());
}
@Test
//Ignore ("test fails without a patch")
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 = new BufferedReader(new StringReader(responseString));
Assert.assertEquals("HTTP/1.1 200 OK",br.readLine());
br.readLine();// connection close
br.readLine();// server
br.readLine();// empty
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("async context gets right path in async","async:run:/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
//Ignore ("test fails without a patch")
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 = new BufferedReader(new StringReader(responseString));
Assert.assertEquals("HTTP/1.1 200 OK",br.readLine());
br.readLine();// connection close
br.readLine();// server
br.readLine();// empty
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:/servletPath", br.readLine());
}
@Test
//Ignore ("test fails without a patch")
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);
System.out.println(responseString);
BufferedReader br = new BufferedReader(new StringReader(responseString));
Assert.assertEquals("HTTP/1.1 200 OK",br.readLine());
br.readLine();// connection close
br.readLine();// server
br.readLine();// empty
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("async context gets right path in async","async:run:/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());
}
@After
public void tearDown() throws Exception
{
_server.stop();
_server.join();
}
private class TestServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
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;
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:" + req.getServletPath() + "\n");
_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();
}
}
}