Bug 28222 - getRequestURL() in forwarded jsp/servlet doesn't return new url
Summary: getRequestURL() in forwarded jsp/servlet doesn't return new url
Status: RESOLVED INVALID
Alias: None
Product: Tomcat 4
Classification: Unclassified
Component: Servlet & JSP API (show other bugs)
Version: 4.1.30
Hardware: All All
: P3 normal (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
: 35425 (view as bug list)
Depends on:
Blocks:
 
Reported: 2004-04-06 02:36 UTC by Hugh J. Lee
Modified: 2006-09-28 04:30 UTC (History)
4 users (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Hugh J. Lee 2004-04-06 02:36:35 UTC
1.jsp:
<%getServletContext().getRequestDispatcher("/2.jsp").forward(request, 
response);%>
2.jsp:
<%out.print(request.getRequestURL());%>

The output of 2.jsp is "http://.../1.jsp" but NOT "http://...2.jsp". According 
to SRV8.4, "The path elements of the request object exposed to the target 
servlet must reflect the path used to obtain the RequestDispatcher." In this 
test case, "path used to obtain the RequestDispatcher" is "/2.jsp", so 
getRequestURL() in 2.jsp should return "http://...2.jsp".
Comment 1 Mark Thomas 2005-01-15 21:31:51 UTC
Fixed in CVS for TC4.1.x and TC5.5.x
Comment 2 J Leertouwer 2005-03-03 09:28:54 UTC
This fix gives many problems when using frameworks like struts and spring 
together with templating (i.e. Tiles).

It will now always return the JSP of the template, which makes it impossible to 
find out what the actual request uri was.
Comment 3 Remy Maucherat 2005-03-03 11:02:22 UTC
I cannot say if the fix is invalid or not. Actually, it seems valid to me, and
as a result, it's here to stay. You obviously can retrieve any of the original
request paths (you have all the RD request attributes at your disposal for this).

Please do not reopen the report.
Comment 4 Flavio 2005-04-28 19:49:05 UTC
IMHO this conflicts with the specification of HttpServletRequest.getRequestURL():

"Reconstructs the URL the client used to make the request"

It says "the client" but after a forward the returned URL is not the client URL
anymore.

btw I'm posting this because the "fix" breaks my applications :(
Comment 5 Peter English 2005-05-01 00:51:16 UTC
This bug also affects web pages protected by the web.xml constraint:

<security-constraint>
    . . .
  <user-data-constraint>
    <transport-guarantee>CONFIDENTIAL</transport-guarantee>
  </user-data-constraint> 
</security-constraint>

What happens is if the user access the page via an unsecure URL like:

http://localhost:8080/MyAccount

Tomcat will redirect to an SSL enable port if the redirectPort pramater is 
specified for the connector.

In my case, the secure port where SSL is enabled is port 8443

The resulting req.getRequestURL() call returns:

  https://localhost:8080/MyAccount

which is incorrect.

Tomcat should have returned:

  https://localhost:8443/MyAccount

Comment 6 Remy Maucherat 2005-06-10 21:52:12 UTC
*** Bug 35317 has been marked as a duplicate of this bug. ***
Comment 7 Remy Maucherat 2005-06-20 10:45:26 UTC
*** Bug 35425 has been marked as a duplicate of this bug. ***
Comment 8 Mark Thomas 2005-07-01 21:43:55 UTC
*** Bug 35425 has been marked as a duplicate of this bug. ***
Comment 9 Bruno Grossmann 2005-10-21 21:14:45 UTC
As mentioned in some of the previous comments, this fix seems to have broken
what was working for me in 5.0. For a demo of what happens, see

http://fdis.etg.gc.ca:8080/cdua3

for the Tomcat 5.0 version, and 

http://fdis.etg.gc.ca:8081/cdua3.3

for the Tomcat 5.5 version.

To see the difference in behaviour, click multiple times on the "English" and
"Français" hyperlinks at the top left of the screen. You will find out the 5.0
version works, but the 5.5 does not because it uses the jsp URL instead of the
Struts action. The code can be downloaded from the same website for inspection
(cdua3.tags.LinkTranslateURLTag.java).

As far as I am concerned, the only question to ask is: was the behavior of the
getRequestURL function broken in 5.0 - i.e., it was being used in the wrong way
by my application and I was lucky to get it to work-, or is it broken now?

Thank you for your attention on this matter.
Comment 10 Mark Thomas 2005-10-22 00:04:34 UTC
5.0 is broken and you were lucky

5.5 has the correct (as required by SRV.8.4) behaviour

The fix for your app should be simple, SRV.8.4 explains where you can get the
info you require.
Comment 11 Radoslaw Grzanka 2005-10-24 09:13:48 UTC
The problem is also that tomcat servlet's javadocs were (are still??) misleading
and sugesting behaviour of 5.0 tomcat.
Comment 12 Mark Thomas 2005-10-25 16:29:50 UTC
The servlet JavaDocs are defined by the servlet spec team and we can't change them.
Comment 13 Radoslaw Grzanka 2005-10-26 09:55:01 UTC
Sorry for that "tomcat's" thing then. 

Anyway I am pretty confused right now. If these javadocs are driven by servlet
spec then HttpServletRequest.getRequest() states:

"Reconstructs the URL the client used to make the request. The returned URL
contains a protocol, server name, port number, and server path, but it does not
include query string parameters."
(
http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpServletRequest.html#getRequestURL()
)

This really stands in the way of specs themselfs.
But I guess you can't do anything about it and I should bother someone else
about it.

Cheers,
  Radek.
Comment 14 Mark Thomas 2005-10-26 15:51:26 UTC
Yep, the JavaDocs are confusing here. The JavaDocs make no mention of the
requirements of SRV.8.4. However, SRV.8.4 is very clear on how this should work.

The place to send your comments is servletapi-feedback@eng.sun.com

In my view, the Javadocs should at least refer to the requirements of SRV.8.4
and shoudl really include the full requirement here.
Comment 15 Jan Luehe 2005-11-03 02:41:34 UTC
I just filed Issue 26 ("[javadocs] HttpServletRequest.getRequestURL()
does not consider RD.forward() scenario") with the Servlet EG, see

  https://servlet-spec-eg.dev.java.net/issues/show_bug.cgi?id=26,

with the following description:

======================================================================
The javadocs of javax.servlet.http.HttpServletRequest.getRequestURL()
have been misleading and causing confusion among developers.

See http://issues.apache.org/bugzilla/show_bug.cgi?id=28222,
Synopsis: "getRequestURL() in forwarded jsp/servlet doesn't return new url",
for details.

I am proposing the following clarification to the javadocs of
javax.servlet.http.HttpServletRequest.getRequestURL():

Index: HttpServletRequest.java
===================================================================
RCS file:
/cvs/glassfish/servlet-api/src/jakarta-servletapi-5/jsr154/src/share/javax/servlet/http/HttpServletRequest.java,v
retrieving revision 1.2
diff -u -r1.2 HttpServletRequest.java
--- HttpServletRequest.java	16 Aug 2005 02:02:08 -0000	1.2
+++ HttpServletRequest.java	1 Nov 2005 18:31:11 -0000
@@ -535,6 +535,11 @@
      * number, and server path, but it does not include query
      * string parameters.
      *
+     * <p>If this request has been forwarded using
+     * {@link javax.servlet.RequestDispatcher#forward}, the server path in the
+     * reconstructed URL must reflect the path used to obtain the
+     * RequestDispatcher, and not the server path specified by the client.
+     *
      * <p>Because this method returns a <code>StringBuffer</code>,
      * not a string, you can modify the URL easily, for example,
      * to append query parameters.
===================================================================

We still have a small window of opportunity where clarifications of this kind
may be added to the Servlet 2.5 spec.
Comment 16 Larry Karnowski 2006-09-22 15:54:35 UTC
For those of you affected by this bug, here is a simple utility method for
recreating the URL of the current request:

/** 
 * Recreates the full URL that originally got the web client to the given 
 * request.  This takes into account changes to the request due to request 
 * dispatching.
 *
 * <p>Note that if the protocol is HTTP and the port number is 80 or if the
 * protocol is HTTPS and the port number is 443, then the port number is not 
 * added to the return string as a convenience.</p>
 */
public final static String getReturnURL(HttpServletRequest request)
{
    if (request == null)
    {
        throw new IllegalArgumentException("Cannot take null parameters.");
    }
    
    String scheme = request.getScheme();
    String serverName = request.getServerName();
    int serverPort = request.getServerPort();
    
    //try to get the forwarder value first, only if it's empty fall back to the
current value
    String requestUri =
(String)request.getAttribute("javax.servlet.forward.request_uri");
    requestUri = (requestUri == null) ? request.getRequestURI() : requestUri;
 
    //try to get the forwarder value first, only if it's empty fall back to the
current value 
    String queryString =
(String)request.getAttribute("javax.servlet.forward.query_string");
    queryString = (queryString == null) ? request.getQueryString() : qs;

    StringBuffer buffer = new StringBuffer();
    buffer.append(scheme);
    buffer.append("://");
    buffer.append(serverName);
    
    //if not http:80 or https:443, then add the port number
    if(
        !(scheme.equalsIgnoreCase("http") && serverPort == 80) &&
        !(scheme.equalsIgnoreCase("https") && serverPort == 443)
    )
    {
        buffer.append(String.valueOf(serverPort));
    }
    
    buffer.append(requestUri);
    
    if (queryString != null)
    {
        buffer.append("?");
        buffer.append(queryString);
    }
    
    return buffer.toString();
}