vmassol 01/07/04 02:17:48 Modified: cactus/src/framework/servlet22/org/apache/commons/cactus/server HttpServletRequestWrapper.java cactus/src/framework/servlet23/org/apache/commons/cactus/server HttpServletRequestWrapper.java cactus/src/framework/share/org/apache/commons/cactus ServletURL.java cactus/src/sample/share/org/apache/commons/cactus/sample/unit TestServletTestCase2.java TestServletTestCase4.java Log: Really corrected the bug with HttpServletRequestWrapper.getRequestDispatcher() in order to handle relative paths and take into account the simulation URL (if any used). Also done a bit of refactoring in the ServletURL class. Revision Changes Path 1.3 +153 -19 jakarta-commons/cactus/src/framework/servlet22/org/apache/commons/cactus/server/HttpServletRequestWrapper.java Index: HttpServletRequestWrapper.java =================================================================== RCS file: /home/cvs/jakarta-commons/cactus/src/framework/servlet22/org/apache/commons/cactus/server/HttpServletRequestWrapper.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- HttpServletRequestWrapper.java 2001/07/03 12:12:58 1.2 +++ HttpServletRequestWrapper.java 2001/07/04 09:17:21 1.3 @@ -62,6 +62,7 @@ import javax.servlet.http.*; import org.apache.commons.cactus.*; +import org.apache.commons.cactus.util.log.*; /** * Encapsulation class for the Servlet 2.2 API <code>HttpServletRequest</code>. @@ -89,6 +90,12 @@ private ServletURL m_URL; /** + * The logger + */ + private static Log m_Logger = + LogService.getInstance().getLog(HttpServletRequestWrapper.class.getName()); + + /** * Construct an <code>HttpServletRequest</code> instance that delegates * it's method calls to the request object passed as parameter and that * uses the URL passed as parameter to simulate a URL from which the request @@ -129,10 +136,19 @@ */ public String getContextPath() { + m_Logger.entry("getContextPath()"); + + String result = m_Request.getContextPath(); + if (m_URL != null) { - return m_URL.getContextPath(); + if (m_URL.getContextPath() != null) { + result = m_URL.getContextPath(); + m_Logger.debug("Using simulated context : [" + result + "]"); + } } - return m_Request.getContextPath(); + + m_Logger.exit("getContextPath"); + return result; } public String getScheme() @@ -146,10 +162,17 @@ */ public String getPathInfo() { + m_Logger.entry("getPathInfo()"); + + String result = m_Request.getPathInfo(); + if (m_URL != null) { - return m_URL.getPathInfo(); + result = m_URL.getPathInfo(); + m_Logger.debug("Using simulated PathInfo : [" + result + "]"); } - return m_Request.getPathInfo(); + + m_Logger.exit("getPathInfo"); + return result; } public String getAuthType() @@ -163,10 +186,19 @@ */ public String getServerName() { + m_Logger.entry("getServerName()"); + + String result = m_Request.getServerName(); + if (m_URL != null) { - return m_URL.getURL().getHost(); + if (m_URL.getServerName() != null) { + result = m_URL.getHost(); + m_Logger.debug("Using simulated server name : [" + result + "]"); + } } - return m_Request.getServerName(); + + m_Logger.exit("getServerName"); + return result; } public String getRealPath(String thePath) @@ -206,13 +238,17 @@ */ public int getServerPort() { + m_Logger.entry("getServerPort()"); + + int result = m_Request.getServerPort(); + if (m_URL != null) { - if (m_URL.getURL().getPort() == -1) { - return 80; - } - return m_URL.getURL().getPort(); + result = (m_URL.getPort() == -1) ? 80 : m_URL.getPort(); + m_Logger.debug("Using simulated server port : [" + result + "]"); } - return m_Request.getServerPort(); + + m_Logger.exit("getServerPort"); + return result; } public BufferedReader getReader() throws IOException @@ -231,10 +267,21 @@ */ public String getRequestURI() { + m_Logger.entry("getRequestURI()"); + + String result = m_Request.getRequestURI(); + if (m_URL != null) { - return m_URL.getURL().getFile(); + + result = getContextPath() + + ((getServletPath() == null) ? "" : getServletPath()) + + ((getPathInfo() == null) ? "" : getPathInfo()); + + m_Logger.debug("Using simulated request URI : [" + result + "]"); } - return m_Request.getRequestURI(); + + m_Logger.exit("getRequestURI"); + return result; } public String[] getParameterValues(String theName) @@ -273,10 +320,17 @@ */ public String getServletPath() { + m_Logger.entry("getServletPath()"); + + String result = m_Request.getServletPath(); + if (m_URL != null) { - return m_URL.getServletPath(); + result = m_URL.getServletPath(); + m_Logger.debug("Using simulated servlet path : [" + result + "]"); } - return m_Request.getServletPath(); + + m_Logger.exit("getServletPath"); + return result; } public boolean isRequestedSessionIdFromCookie() @@ -350,10 +404,17 @@ */ public String getQueryString() { + m_Logger.entry("getQueryString()"); + + String result = m_Request.getQueryString(); + if (m_URL != null) { - return m_URL.getQueryString(); + result = m_URL.getQueryString(); + m_Logger.debug("Using simulated query string : [" + result + "]"); } - return m_Request.getQueryString(); + + m_Logger.exit("getQueryString"); + return result; } public long getDateHeader(String theName) @@ -394,9 +455,82 @@ * mechanism introduced by Servlet 2.3 Filters]. */ public RequestDispatcher getRequestDispatcher(String thePath) + { + m_Logger.entry("getRequestDispatcher([" + thePath + "])"); + + // I hate it, but we have to write some logic here ! Ideally we + // shouldn't have to do this as it is supposed to be done by the servlet + // engine. However as we are simulating the request URL, we have to + // provide it ... This is where we can see the limitation of Cactus + // (it has to mock some parts of the servlet engine) ! + + if (thePath == null) { + m_Logger.exit("getRequestDispatcher"); + return null; + } + + RequestDispatcher dispatcher = null; + String fullPath; + + // The spec says that the path can be relative, in which case it will + // be relative to the request. So for relative paths, we need to take + // into account the simulated URL (ServletURL). + if (thePath.startsWith("/")) { + + fullPath = thePath; + + } else { + + String pI = getPathInfo(); + if (pI == null) { + fullPath = catPath(getServletPath(), thePath); + } else { + fullPath = catPath(getServletPath() + pI, thePath); + } + + if (fullPath == null) { + m_Logger.exit("getRequestDispatcher"); + return null; + } + } + + m_Logger.debug("Computed full path : [" + fullPath + "]"); + + dispatcher = new RequestDispatcherWrapper( + m_Request.getRequestDispatcher(fullPath)); + + m_Logger.exit("getRequestDispatcher"); + return dispatcher; + } + + /** + * Will concatenate 2 paths, dealing with .. + * ( /a/b/c + d = /a/b/d, /a/b/c + ../d = /a/d ). Code borrowed from + * Tomcat 3.2.2 ! + * + * @return null if error occurs + */ + private String catPath(String lookupPath, String path) { - return new RequestDispatcherWrapper( - m_Request.getRequestDispatcher(thePath)); + // Cut off the last slash and everything beyond + int index = lookupPath.lastIndexOf("/"); + lookupPath = lookupPath.substring(0, index); + + // Deal with .. by chopping dirs off the lookup path + while (path.startsWith("../")) { + if (lookupPath.length() > 0) { + index = lookupPath.lastIndexOf("/"); + lookupPath = lookupPath.substring(0, index); + } else { + // More ..'s than dirs, return null + return null; + } + + index = path.indexOf("../") + 3; + path = path.substring(index); + } + + return lookupPath + "/" + path; } public Cookie[] getCookies() 1.3 +114 -19 jakarta-commons/cactus/src/framework/servlet23/org/apache/commons/cactus/server/HttpServletRequestWrapper.java Index: HttpServletRequestWrapper.java =================================================================== RCS file: /home/cvs/jakarta-commons/cactus/src/framework/servlet23/org/apache/commons/cactus/server/HttpServletRequestWrapper.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- HttpServletRequestWrapper.java 2001/07/03 12:13:05 1.2 +++ HttpServletRequestWrapper.java 2001/07/04 09:17:30 1.3 @@ -62,6 +62,7 @@ import javax.servlet.http.*; import org.apache.commons.cactus.*; +import org.apache.commons.cactus.util.log.*; /** * Encapsulation class for the Servlet 2.3 API <code>HttpServletRequest</code>. @@ -88,6 +89,12 @@ private ServletURL m_URL; /** + * The logger + */ + private static Log m_Logger = + LogService.getInstance().getLog(HttpServletRequestWrapper.class.getName()); + + /** * Construct an <code>HttpServletRequest</code> instance that delegates * it's method calls to the request object passed as parameter and that * uses the URL passed as parameter to simulate a URL from which the request @@ -152,10 +159,17 @@ */ public String getServletPath() { + m_Logger.entry("getServletPath()"); + + String result = m_Request.getServletPath(); + if (m_URL != null) { - return m_URL.getServletPath(); + result = m_URL.getServletPath(); + m_Logger.debug("Using simulated servlet path : [" + result + "]"); } - return m_Request.getServletPath(); + + m_Logger.exit("getServletPath"); + return result; } public String getRequestedSessionId() @@ -174,10 +188,21 @@ */ public String getRequestURI() { + m_Logger.entry("getRequestURI()"); + + String result = m_Request.getRequestURI(); + if (m_URL != null) { - return m_URL.getURL().getFile(); + + result = getContextPath() + + ((getServletPath() == null) ? "" : getServletPath()) + + ((getPathInfo() == null) ? "" : getPathInfo()); + + m_Logger.debug("Using simulated request URI : [" + result + "]"); } - return m_Request.getRequestURI(); + + m_Logger.exit("getRequestURI"); + return result; } public String getRemoteUser() @@ -191,10 +216,17 @@ */ public String getQueryString() { + m_Logger.entry("getQueryString()"); + + String result = m_Request.getQueryString(); + if (m_URL != null) { - return m_URL.getQueryString(); + result = m_URL.getQueryString(); + m_Logger.debug("Using simulated query string : [" + result + "]"); } - return m_Request.getQueryString(); + + m_Logger.exit("getQueryString"); + return result; } public String getPathTranslated() @@ -208,10 +240,17 @@ */ public String getPathInfo() { + m_Logger.entry("getPathInfo()"); + + String result = m_Request.getPathInfo(); + if (m_URL != null) { - return m_URL.getPathInfo(); + result = m_URL.getPathInfo(); + m_Logger.debug("Using simulated PathInfo : [" + result + "]"); } - return m_Request.getPathInfo(); + + m_Logger.exit("getPathInfo"); + return result; } public String getMethod() @@ -255,10 +294,19 @@ */ public String getContextPath() { + m_Logger.entry("getContextPath()"); + + String result = m_Request.getContextPath(); + if (m_URL != null) { - return m_URL.getContextPath(); + if (m_URL.getContextPath() != null) { + result = m_URL.getContextPath(); + m_Logger.debug("Using simulated context : [" + result + "]"); + } } - return m_Request.getContextPath(); + + m_Logger.exit("getContextPath"); + return result; } public String getAuthType() @@ -293,13 +341,17 @@ */ public int getServerPort() { + m_Logger.entry("getServerPort()"); + + int result = m_Request.getServerPort(); + if (m_URL != null) { - if (m_URL.getURL().getPort() == -1) { - return 80; - } - return m_URL.getURL().getPort(); + result = (m_URL.getPort() == -1) ? 80 : m_URL.getPort(); + m_Logger.debug("Using simulated server port : [" + result + "]"); } - return m_Request.getServerPort(); + + m_Logger.exit("getServerPort"); + return result; } /** @@ -308,10 +360,19 @@ */ public String getServerName() { + m_Logger.entry("getServerName()"); + + String result = m_Request.getServerName(); + if (m_URL != null) { - return m_URL.getURL().getHost(); + if (m_URL.getServerName() != null) { + result = m_URL.getHost(); + m_Logger.debug("Using simulated server name : [" + result + "]"); + } } - return m_Request.getServerName(); + + m_Logger.exit("getServerName"); + return result; } public String getScheme() @@ -328,8 +389,42 @@ */ public RequestDispatcher getRequestDispatcher(String thePath) { - return new RequestDispatcherWrapper( - m_Request.getRequestDispatcher(thePath)); + m_Logger.entry("getRequestDispatcher([" + thePath + "])"); + + // I hate it, but we have to write some logic here ! Ideally we + // shouldn't have to do this as it is supposed to be done by the servlet + // engine. However as we are simulating the request URL, we have to + // provide it ... This is where we can see the limitation of Cactus + // (it has to mock some parts of the servlet engine) ! + + if (thePath == null) { + m_Logger.exit("getRequestDispatcher"); + return null; + } + + RequestDispatcher dispatcher = null; + String fullPath; + + // The spec says that the path can be relative, in which case it will + // be relative to the request. So for relative paths, we need to take + // into account the simulated URL (ServletURL). + if (thePath.startsWith("/")) { + + fullPath = thePath; + + } else { + + fullPath = getServletPath() + "/../" + thePath; + + } + + m_Logger.debug("Computed full path : [" + fullPath + "]"); + + dispatcher = new RequestDispatcherWrapper( + m_Request.getRequestDispatcher(fullPath)); + + m_Logger.exit("getRequestDispatcher"); + return dispatcher; } public String getRemoteHost() 1.2 +58 -38 jakarta-commons/cactus/src/framework/share/org/apache/commons/cactus/ServletURL.java Index: ServletURL.java =================================================================== RCS file: /home/cvs/jakarta-commons/cactus/src/framework/share/org/apache/commons/cactus/ServletURL.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ServletURL.java 2001/04/09 11:52:36 1.1 +++ ServletURL.java 2001/07/04 09:17:37 1.2 @@ -62,6 +62,7 @@ import javax.servlet.http.*; import junit.framework.*; +import org.apache.commons.cactus.util.log.*; /** * Simulate an HTTP URL by breaking it into its different parts :<br> @@ -145,10 +146,10 @@ private String m_URL_QueryString; /** - * The full URL (useful later because we can benefit from the all - * methods of the <code>URL</code> class. + * The logger */ - private URL m_FullURL; + private static Log m_Logger = + LogService.getInstance().getLog(ServletURL.class.getName()); /** * Creates the URL to simulate. @@ -156,11 +157,15 @@ * @param theServerName the server name (and port) in the URL to simulate, * i.e. this is the name that will be returned by the * <code>HttpServletRequest.getServerName()</code> and - * <code>HttpServletRequest.getServerPort()</code>. + * <code>HttpServletRequest.getServerPort()</code>. Can + * be null. If null, then the server name and port from + * the Servlet Redirector will be returned. * @param theContextPath the webapp context path in the URL to simulate, * i.e. this is the name that will be returned by the * <code>HttpServletRequest.getContextPath()</code>. - * Can be null. Format: "/" + name or an empty string + * Can be null. If null, then the context from the + * Servlet Redirector will be returned. + * Format: "/" + name or an empty string * for the default context. * @param theServletPath the servlet path in the URL to simulate, * i.e. this is the name that will be returned by the @@ -178,53 +183,57 @@ public ServletURL(String theServerName, String theContextPath, String theServletPath, String thePathInfo, String theQueryString) { - if (theServerName == null) { - throw new AssertionFailedError("Bad URL. The server name cannot be null"); - } - m_URL_ServerName = theServerName; - m_URL_ContextPath = (theContextPath == null) ? "" : theContextPath; + m_URL_ContextPath = theContextPath; m_URL_ServletPath = theServletPath; m_URL_PathInfo = thePathInfo; m_URL_QueryString = theQueryString; - - // create a full URL - String fullURL = "http://" + m_URL_ServerName; - if (m_URL_ContextPath.length() != 0) { - fullURL = fullURL + m_URL_ContextPath; - } - if ((m_URL_ServletPath != null) && (m_URL_ServletPath.length() != 0)) { - fullURL = fullURL + m_URL_ServletPath; - } - if ((m_URL_PathInfo != null) && (m_URL_PathInfo.length() != 0)) { - fullURL = fullURL + m_URL_PathInfo; - } - - try { - m_FullURL = new URL(fullURL); - } catch (MalformedURLException e) { - throw new AssertionFailedError("Bad URL [" + fullURL + "]"); - } - } /** - * @return the full URL as a <code>URL</code> object. + * @return the simulated URL server name (including the port number) */ - public URL getURL() + public String getServerName() { - return m_FullURL; + return m_URL_ServerName; } /** - * @return the simulated URL server name (including the port number) + * @return the simulated URL server name (excluding the port number) */ - public String getServerName() + public String getHost() { + int pos = m_URL_ServerName.indexOf(":"); + if (pos > 0) { + return m_URL_ServerName.substring(0, pos + 1); + } + return m_URL_ServerName; } /** + * @return the port number or -1 if none has been defined or it is a bad + * port + */ + public int getPort() + { + int pos = m_URL_ServerName.indexOf(":"); + int result; + + if (pos < 0) { + return -1; + } + + try { + result = Integer.parseInt(m_URL_ServerName.substring(pos + 1)); + } catch (NumberFormatException e) { + return -1; + } + + return result; + } + + /** * @return the simulated URL context path */ public String getContextPath() @@ -288,17 +297,28 @@ */ public static ServletURL loadFromRequest(HttpServletRequest theRequest) { + m_Logger.entry("loadFromRequest(...)"); + String serverName = theRequest.getParameter(URL_SERVER_NAME_PARAM); + m_Logger.debug("serverName = [" + serverName + "]"); + String contextPath = theRequest.getParameter(URL_CONTEXT_PATH_PARAM); + m_Logger.debug("contextPath = [" + contextPath + "]"); + String servletPath = theRequest.getParameter(URL_SERVLET_PATH_PARAM); + m_Logger.debug("servletPath = [" + servletPath + "]"); + String pathInfo = theRequest.getParameter(URL_PATH_INFO_PARAM); + m_Logger.debug("pathInfo = [" + pathInfo + "]"); + String queryString = theRequest.getParameter(URL_QUERY_STRING_PARAM); + m_Logger.debug("queryString = [" + queryString + "]"); - if (serverName != null) { - return new ServletURL(serverName, contextPath, servletPath, pathInfo, queryString); - } + ServletURL url = new ServletURL(serverName, contextPath, + servletPath, pathInfo, queryString); - return null; + m_Logger.entry("loadFromRequest(...)"); + return url; } } 1.6 +55 -3 jakarta-commons/cactus/src/sample/share/org/apache/commons/cactus/sample/unit/TestServletTestCase2.java Index: TestServletTestCase2.java =================================================================== RCS file: /home/cvs/jakarta-commons/cactus/src/sample/share/org/apache/commons/cactus/sample/unit/TestServletTestCase2.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- TestServletTestCase2.java 2001/07/03 12:13:12 1.5 +++ TestServletTestCase2.java 2001/07/04 09:17:42 1.6 @@ -395,13 +395,65 @@ //------------------------------------------------------------------------- /** - * Verify that request.getRequestDispatcher() works properly and can include - * another page. + * Verify that request.getRequestDispatcher() works properly with an + * absolute path */ - public void testGetRequestDispatcherFromRequest() throws ServletException, IOException + public void testGetRequestDispatcherFromRequest1() throws ServletException, IOException { RequestDispatcher rd = request.getRequestDispatcher("/test/test.jsp"); rd.include(request, response); + } + + /** + * Verify that request.getRequestDispatcher() works properly with an + * absolute path + * + * @param theConnection the HTTP connection that was used to call the + * server redirector. It contains the returned HTTP + * response. + */ + public void endGetRequestDispatcherFromRequest1(HttpURLConnection theConnection) throws IOException + { + String result = AssertUtils.getResponseAsString(theConnection); + assert("Page not found, got [" + result + "]", result.indexOf("Hello !") > 0); + } + + //------------------------------------------------------------------------- + + /** + * Verify that request.getRequestDispatcher() works properly with a + * relative path. + * + * @param theRequest the request object that serves to initialize the + * HTTP connection to the server redirector. + */ + public void beginGetRequestDispatcherFromRequest2(ServletTestRequest theRequest) + { + theRequest.setURL(null, "/test", "/anything.jsp", null, null); + } + + /** + * Verify that request.getRequestDispatcher() works properly with a + * relative path. + */ + public void testGetRequestDispatcherFromRequest2() throws ServletException, IOException + { + RequestDispatcher rd = request.getRequestDispatcher("test/test.jsp"); + rd.include(request, response); + } + + /** + * Verify that request.getRequestDispatcher() works properly with a + * relative path. + * + * @param theConnection the HTTP connection that was used to call the + * server redirector. It contains the returned HTTP + * response. + */ + public void endGetRequestDispatcherFromRequest2(HttpURLConnection theConnection) throws IOException + { + String result = AssertUtils.getResponseAsString(theConnection); + assert("Page not found, got [" + result + "]", result.indexOf("Hello !") > 0); } } 1.3 +2 -2 jakarta-commons/cactus/src/sample/share/org/apache/commons/cactus/sample/unit/TestServletTestCase4.java Index: TestServletTestCase4.java =================================================================== RCS file: /home/cvs/jakarta-commons/cactus/src/sample/share/org/apache/commons/cactus/sample/unit/TestServletTestCase4.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- TestServletTestCase4.java 2001/06/28 21:27:00 1.2 +++ TestServletTestCase4.java 2001/07/04 09:17:43 1.3 @@ -111,14 +111,14 @@ /** * Verify that we can simulate the basic parts of the URL : server name, - * default server port of 80, no servlet context, URI. + * default server port of 80, root servlet context, URI. * * @param theRequest the request object that serves to initialize the * HTTP connection to the server redirector. */ public void beginSimulatedURLBasics(ServletTestRequest theRequest) { - theRequest.setURL("jakarta.apache.org", null, "/test/test.jsp", null, null); + theRequest.setURL("jakarta.apache.org", "", "/test/test.jsp", null, null); } /**