You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Juha Laiho <Ju...@iki.fi> on 2012/12/10 22:14:03 UTC

Request dispatching oddity

Hello,

I encountered an odd situation with request dispatching.

Environment:
Java platform: Oracle 1.7 (7u9)
Tomcat platform: 7.0.32, 7.0.33
Operating systems: Linux, Windows (likely irrelevant)
Browser: Firefox 17

In short, if the same request is first redirected using servlet API
RequestDispatcher.forward(), and then via JSTL c:redirect using a
relative target, the end result seems incorrect.

So, consider a web app with /WEB-INF/web.xml as:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>RedirT</display-name>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>


... and /sub/index.jsp as:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<%
RequestDispatcher rd = application.getRequestDispatcher("/");
rd.forward(request, response);
%>


... and /index.jsp as:

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<c:redirect url="sub/page.jsp"/>


(sub/page.jsp contents omitted as irrelevant for now)

Then, consider a request to http://server/context/sub/index.jsp .
Looking at the above, I would expect:
- the request to be first processed by /sub/index.jsp (this happens)
- next by /index.jsp (this happens, too)
- ending with showing http://server/context/sub/page.jsp (this doesn't happen!)

Instead, the error is "The requested resource
(/RedirT/sub/sub/page.jsp) is not available.".
Note the "sub" path component being listed twice.

So, it is as if the first redirect (using the RequestDispatcher
manually, in /sub/index.jsp) fails to reset
the "current" location for the requested component from /sub to /, and
then subsequently, the c:redirect
in /index.jsp adds another "sub" to the request path.

If, on the other hand, the latter redirect is done with an address
bound to context root (i.e. /sub/page.jsp,
instead of sub/page.jsp), the request ends up in the expected place.
Also, if the first redirect is done with
<c:redirect> rather than the RequestDispatcher, the request ends up in
the expected place.

This structure looks admittedly odd, but part of that came from
producing this SSCCE; the original context
was that the initial RequestDispatcher.forward() was located inside a
filter class (but similarly, forwarded
a request targeted to a resource in a subdirectory to /index.jsp,
which in turn contains the c:redirect to
another resource within the same subdirectory. I encountered this when
moving an application from
a WebLogic 9.2 server (where this structure had worked without issues)
to a Tomcat server (where this
"not found" error appeared.

Any comments? Did I come across a but in Tomcat, or a "lucky bug" in
the application (i.e. something
that worked by luck in the previous container)? While I can (and did)
change the application so that the
c:redirect in /index.jsp now uses a context-absolute addressing, I'd
be interested in hearing the actual
verdict. I tried to read the servlet specification, but could not find
an exact description covering this case.

Thanks,
-- 
..Juha

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Request dispatching oddity

Posted by Mark Thomas <ma...@apache.org>.
On 11/12/2012 22:00, Christopher Schultz wrote:
> Can you start a new thread with a different subject? Something
> like "Tomcat prefers TC JSTL implementation to webapp-packaged one"
> and ask about it? I know there are some folks here who can describe
> how that's supposed to work. Once you've got that hammered-out (or
> maybe in parallel), you can ask about why the <c:redirect> tag
> doesn't work.
> 
> A new thread and subject line may get others interested, which is
> why I am suggesting it.

Chances are you are using an Oracle authored tag library derived from
the ASF's JSTL implementation that (ab)uses the ASF package namespace.

The Apache Tomcat PMC asked Oracle to change the Java package name tp
avoid confusion and they refused. They did, however, agree to ensure
that JARs contained appropriate META-INF entries so it was clear where
the JAR originated.

Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Request dispatching oddity

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Juha,

On 12/11/12 3:29 PM, Juha Laiho wrote:
> first, thanks for your answers, and also for the nits, they did
> hit some good points. Then on with some answers to the further 
> questions you placed;
> 
> 
> On Tue, Dec 11, 2012 at 12:58 AM, Christopher Schultz 
> <ch...@christopherschultz.net> wrote:
>> On 12/10/12 5:40 PM, Christopher Schultz wrote:
>>> I'll take a look. You definitely want to use URLs that start
>>> with "/" in all cases to prevent this kind of ambiguity.
>> 
>> So it looks like I'm wrong and there may in fact be a bug in
>> Tomcat.
>> 
>> Servlet 3.0 has this to say about "forward" in section 9.4:
>> 
>> " The path elements of the request object exposed to the target
>> servlet must reflect the path used to obtain the
>> RequestDispatcher. "
> 
> Thanks, I did read the Servlet spec 2.5, but at least didn't come
> across this statement there.
> 
>> Your forward() code looks like this:
>> 
>>> RequestDispatcher rd = application.getRequestDispatcher("/"); 
>>> rd.forward(request, response);
>> 
>> So the path used to obtain the RequestDispatcher is "/" and URLs
>> built should be relative to that.
> 
> ... so looks like I might have encountered a minor bug.

Perhaps.

>> Are you using Tomcat's provided JSTL, or do you bundle one with
>> your own webapp?
> 
> This was good call, too - something I hadn't been paying attention
> to. In the example I seem to be using JSTL library from some
> version of Glassfish (a Maven dependency, javax.servlet:jstl:1.2,
> which gets packaged into the examle webapp). What JSTL
> implementation is used in the original place where I encountered
> this, I don't know (could check, but I think for now we can just as
> well concentrate on this example, as it exhibits the same behaviour
> as the original case).

Odd that Tomcat's JSTL implementation was used in preference to the
one supplied with the webapp.

>> Can you post a copy of the .java source generated from your JSP
>> that contains the <c:redirect>?
> 
> Certainly; and this seems to hit another point where I've been
> sloppy; this example has been run on Tomcat embedded with NetBeans,
> and thus version 7.0.27. And interesting, this seems to refer to 
> org.apache.taglibs.standard for the RegirectTag implementation,
> despite the other JSTL lib being included in the application:

There's also a Redirect class in Tomcat proper which generates Java
source instead of being an actual tag implementation. I was actually
thrown-off the by that.

Tomcat's taglibs are actually maintained under a slightly different
umbrella and it's unclear to me if they are actively maintained. There
are svn revisions, but they all seem to be deployment-related and not
actual code changes.

Can you start a new thread with a different subject? Something like
"Tomcat prefers TC JSTL implementation to webapp-packaged one" and ask
about it? I know there are some folks here who can describe how that's
supposed to work. Once you've got that hammered-out (or maybe in
parallel), you can ask about why the <c:redirect> tag doesn't work.

A new thread and subject line may get others interested, which is why
I am suggesting it.

- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with undefined - http://www.enigmail.net/

iEYEAREIAAYFAlDHrOYACgkQ9CaO5/Lv0PDrKACgiF7MJ/opHRg1rqM7ol71dWIs
AvAAnjfLlQbrKZ3kqJD0NHu7zcPoaWHL
=wP1M
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Request dispatching oddity

Posted by Juha Laiho <Ju...@iki.fi>.
Chirs,

first, thanks for your answers, and also for the nits, they did hit
some good points. Then on with some answers to the further
questions you placed;


On Tue, Dec 11, 2012 at 12:58 AM, Christopher Schultz
<ch...@christopherschultz.net> wrote:
> On 12/10/12 5:40 PM, Christopher Schultz wrote:
>> I'll take a look. You definitely want to use URLs that start with
>> "/" in all cases to prevent this kind of ambiguity.
>
> So it looks like I'm wrong and there may in fact be a bug in Tomcat.
>
> Servlet 3.0 has this to say about "forward" in section 9.4:
>
> "
> The path elements of the request object exposed to the target servlet
> must reflect the path used to obtain the RequestDispatcher.
> "

Thanks, I did read the Servlet spec 2.5, but at least didn't come across
this statement there.

> Your forward() code looks like this:
>
>> RequestDispatcher rd = application.getRequestDispatcher("/");
>> rd.forward(request, response);
>
> So the path used to obtain the RequestDispatcher is "/" and URLs built
> should be relative to that.

... so looks like I might have encountered a minor bug.

> Are you using Tomcat's provided JSTL, or do you bundle one with your
> own webapp?

This was good call, too - something I hadn't been paying attention to.
In the example I seem to be using JSTL library from some version of
Glassfish (a Maven dependency, javax.servlet:jstl:1.2, which gets
packaged into the examle webapp). What JSTL implementation is used
in the original place where I encountered this, I don't know (could check,
but I think for now we can just as well concentrate on this example, as
it exhibits the same behaviour as the original case).

> Can you post a copy of the .java source generated from your JSP that
> contains the <c:redirect>?

Certainly; and this seems to hit another point where I've been sloppy; this
example has been run on Tomcat embedded with NetBeans, and thus
version 7.0.27. And interesting, this seems to refer to
org.apache.taglibs.standard
for the RegirectTag implementation, despite the other JSTL lib being
included in the application:


/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/7.0.27
 * Generated at: 2012-12-10 20:52:07 UTC
 * Note: The last modified time of this file was set to
 *       the last modified time of the source file after
 *       generation to assist with modification tracking.
 */
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent {

  private static final javax.servlet.jsp.JspFactory _jspxFactory =
          javax.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map<java.lang.String,java.lang.Long>
_jspx_dependants;

  private org.apache.jasper.runtime.TagHandlerPool
_005fjspx_005ftagPool_005fc_005fredirect_0026_005furl_005fnobody;

  private javax.el.ExpressionFactory _el_expressionfactory;
  private org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
    return _jspx_dependants;
  }

  public void _jspInit() {
    _005fjspx_005ftagPool_005fc_005fredirect_0026_005furl_005fnobody =
org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
    _el_expressionfactory =
_jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    _jsp_instancemanager =
org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
  }

  public void _jspDestroy() {
    _005fjspx_005ftagPool_005fc_005fredirect_0026_005furl_005fnobody.release();
  }

  public void _jspService(final javax.servlet.http.HttpServletRequest
request, final javax.servlet.http.HttpServletResponse response)
        throws java.io.IOException, javax.servlet.ServletException {

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html;charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\r\n");
      out.write("\r\n");
      out.write("<!DOCTYPE html>\r\n");
      out.write("\r\n");
      if (_jspx_meth_c_005fredirect_005f0(_jspx_page_context))
        return;
      out.write('\r');
      out.write('\n');
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try { out.clearBuffer(); } catch (java.io.IOException e) {}
        if (_jspx_page_context != null)
_jspx_page_context.handlePageException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }

  private boolean
_jspx_meth_c_005fredirect_005f0(javax.servlet.jsp.PageContext
_jspx_page_context)
          throws java.lang.Throwable {
    javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
    javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
    //  c:redirect
    org.apache.taglibs.standard.tag.rt.core.RedirectTag
_jspx_th_c_005fredirect_005f0 =
(org.apache.taglibs.standard.tag.rt.core.RedirectTag)
_005fjspx_005ftagPool_005fc_005fredirect_0026_005furl_005fnobody.get(org.apache.taglibs.standard.tag.rt.core.RedirectTag.class);
    _jspx_th_c_005fredirect_005f0.setPageContext(_jspx_page_context);
    _jspx_th_c_005fredirect_005f0.setParent(null);
    // /index.jsp(5,0) name = url type = null reqTime = true required
= false fragment = false deferredValue = false expectedTypeName = null
deferredMethod = false methodSignature = null
    _jspx_th_c_005fredirect_005f0.setUrl("sub/page.jsp");
    int _jspx_eval_c_005fredirect_005f0 =
_jspx_th_c_005fredirect_005f0.doStartTag();
    if (_jspx_th_c_005fredirect_005f0.doEndTag() ==
javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
      _005fjspx_005ftagPool_005fc_005fredirect_0026_005furl_005fnobody.reuse(_jspx_th_c_005fredirect_005f0);
      return true;
    }
    _005fjspx_005ftagPool_005fc_005fredirect_0026_005furl_005fnobody.reuse(_jspx_th_c_005fredirect_005f0);
    return false;
  }
}


-- 
..Juha

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Request dispatching oddity

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Juha,

On 12/10/12 5:40 PM, Christopher Schultz wrote:
> On 12/10/12 4:14 PM, Juha Laiho wrote:
> 
>> Any comments? Did I come across a but in Tomcat, or a "lucky
>> bug" in the application (i.e. something that worked by luck in
>> the previous container)?
> 
> Yeah, I think this probably should not have worked in WebLogic,
> but it's possible that there is room for interpretation in the spec
> (it certainly wouldn't be the first time).
> 
>> While I can (and did) change the application so that the
>> c:redirect in /index.jsp now uses a context-absolute addressing,
>> I'd be interested in hearing the actual verdict. I tried to read
>> the servlet specification, but could not find an exact
>> description covering this case.
> 
> I'll take a look. You definitely want to use URLs that start with
> "/" in all cases to prevent this kind of ambiguity.

So it looks like I'm wrong and there may in fact be a bug in Tomcat.

Servlet 3.0 has this to say about "forward" in section 9.4:

"
The path elements of the request object exposed to the target servlet
must reflect the path used to obtain the RequestDispatcher.
"

Your forward() code looks like this:

> RequestDispatcher rd = application.getRequestDispatcher("/"); 
> rd.forward(request, response);

So the path used to obtain the RequestDispatcher is "/" and URLs built
should be relative to that.

Are you using Tomcat's provided JSTL, or do you bundle one with your
own webapp?

Can you post a copy of the .java source generated from your JSP that
contains the <c:redirect>?

- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with undefined - http://www.enigmail.net/

iEYEAREIAAYFAlDGaQ8ACgkQ9CaO5/Lv0PD7bwCgk0mSZ2Pl61gS1ksZyjf4zgG6
04EAoLDuvvL//lYuscLwKOZM0fjtaWeg
=7H7K
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Request dispatching oddity

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Juha,

On 12/10/12 4:14 PM, Juha Laiho wrote:
> I encountered an odd situation with request dispatching.
> 
> In short, if the same request is first redirected using servlet
> API RequestDispatcher.forward(), and then via JSTL c:redirect using
> a relative target, the end result seems incorrect.

Small nit: requests are not redirected when you call
RequestDispatcher.forward().

> So, consider a web app with /WEB-INF/web.xml as:
> 
> <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5"
> xmlns="http://java.sun.com/xml/ns/javaee" 
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
> xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
> http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 
> <display-name>RedirT</display-name> <welcome-file-list> 
> <welcome-file>index.jsp</welcome-file> </welcome-file-list> 
> </web-app>
> 
> 
> ... and /sub/index.jsp as:
> 
> <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE
> html> <% RequestDispatcher rd =
> application.getRequestDispatcher("/"); rd.forward(request,
> response); %>

I realize that this is probably a contrived example, but the above JSP
technically produces output. That can interfere with any container's
ability to forward a request to another resource. The response buffer
is probably big enough to avoid any such problems, but I felt it was
worth mentioning.

> ... and /index.jsp as:
> 
> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 
> <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE
> html> <c:redirect url="sub/page.jsp"/>
> 
> (sub/page.jsp contents omitted as irrelevant for now)
> 
> Then, consider a request to http://server/context/sub/index.jsp . 
> Looking at the above, I would expect: - the request to be first
> processed by /sub/index.jsp (this happens) - next by /index.jsp
> (this happens, too) - ending with showing
> http://server/context/sub/page.jsp (this doesn't happen!)
> 
> Instead, the error is "The requested resource 
> (/RedirT/sub/sub/page.jsp) is not available.". Note the "sub" path
> component being listed twice.

You need to fully-qualify the url you use in your <c:redirect> tag.
Since you didn't start the URL with "/", you are getting this URL build:

http://host/context/sub/index.jsp - "index.jsp" + "sub/page.jsp"
=
http://host/context/sub/sub/page.jsp

> So, it is as if the first redirect (using the RequestDispatcher 
> manually, in /sub/index.jsp) fails to reset the "current" location
> for the requested component from /sub to /, and then subsequently,
> the c:redirect in /index.jsp adds another "sub" to the request
> path.

URLs are typically based upon the currently-executing request.
Performing a forward() does not change the context of the original
request (for better or worse) and thus is the problem, here.

You pretty much need to use fully-qualified URLs for *everything* /all
the time/.

Try:

<c:redirect url="/sub/page.jsp"/>

Note that the default "context" attribute for the <c:redirect> tag (I
assume you are using JSTL) is the current webapp. So, starting your
URL with "/" means that the URL will be relative to the current
context (webapp), not relative to the current host.

> If, on the other hand, the latter redirect is done with an address 
> bound to context root (i.e. /sub/page.jsp, instead of
> sub/page.jsp), the request ends up in the expected place. Also, if
> the first redirect is done with <c:redirect> rather than the
> RequestDispatcher, the request ends up in the expected place.

A redirect involves the client, and changes the URL context of the
request, so it will work.

> Any comments? Did I come across a but in Tomcat, or a "lucky bug"
> in the application (i.e. something that worked by luck in the
> previous container)?

Yeah, I think this probably should not have worked in WebLogic, but
it's possible that there is room for interpretation in the spec (it
certainly wouldn't be the first time).

> While I can (and did) change the application so that the c:redirect
> in /index.jsp now uses a context-absolute addressing, I'd be
> interested in hearing the actual verdict. I tried to read the
> servlet specification, but could not find an exact description
> covering this case.

I'll take a look. You definitely want to use URLs that start with "/"
in all cases to prevent this kind of ambiguity.

- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with undefined - http://www.enigmail.net/

iEYEAREIAAYFAlDGZOUACgkQ9CaO5/Lv0PDLHQCeOcR41slZ3Td92W/KIkkvTD7q
djEAoMN4lBVe0uLdz70tRcXhKRmQA0ue
=Pm2d
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org