You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by "Hammon, Randy" <RH...@Evolve.com> on 2000/06/29 00:19:58 UTC

jsp:include: the bug and the fix

Hello,
this is my first message to the list. Hope I'm going about this in the right
way.

Here at Evolve we've encountered a jsp:include bug (we think it's a bug) in
the Tomcat 3.1 release.
Vance Maverick and myself downloaded the source code, did some debugging,
and Vance
found what we believe is the bug and the fix.

Scenario
------------
Given the following 2 jsp files and servlet( putting all three in a
directory
named /test and doing what you need so that Tomcat can find it) to invoke
them:

Outer.jsp
----------
html>
<head>
<title>Include test</title>
</head>
<body>
This is a test of forwarding and inclusion.  For some reason, it's not
working right for us with Tomcat.

<p>
<jsp:include page="/test/Inner.jsp" flush="true" />
</body>
</html>
----------

Inner.jsp
-----------
This is an inner file included via &lt;jsp:include&gt;.
----------

and the servlet to invoke them.

test.Test.java
----------------
package test;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
/**
 *  Simplest possible test of problem configuration:
 *  servlet forwards request to JSP, JSP includes another.
 */
public class Test
    extends HttpServlet
{
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
        throws ServletException, IOException
    {
        RequestDispatcher rd =
 
this.getServletContext().getRequestDispatcher("/test/Outer.jsp");
        rd.forward(request, response);
    }

}
----------------

If you run this scenario in the 3.1 Tomcat release, Outer.jsp will blow up
on the jsp:include line.
What appears to be happening is that the ContextManager creates a context
for Outer.jsp, then when it creates a context for
inner.jsp, it finds it already has a context from Outer.jsp and a context
path, /test, so it uses it, and some code thinks it's supposed to prepend
/test to the /test/Inner.jsp url in the jsp:include statement. We think that
it should NOT do this, since /test/Inner.jsp is an absolute 
path. Here's the code in class org.apache.tomcat.core.ContextManager, in the
method createRequest(Context ctx, String urlPath).  
The implementation looks like this:  

    Request createRequest( Context ctx, String urlPath ) {
	// assert urlPath!=null

	// deal with paths with parameters in it
	String contextPath=ctx.getPath();
	String origPath=urlPath;

	// BEGIN DEBUG STUFF
	System.err.println("contextPath = " + contextPath +
	                   ", origPath = " + origPath);
	// END DEBUG STUFF

	// append context path
	if( !"".equals(contextPath) && !"/".equals(contextPath)) {

	// BEGIN HERE IS THE CODE WE THINK IS WRONG
	    if( urlPath.startsWith("/" ) )
		urlPath=contextPath + urlPath;
	    else
		urlPath=contextPath + "/" + urlPath;
	// END HERE IS THE CODE WE THINK IS WRONG

	} else {
	    // root context
	    if( !urlPath.startsWith("/" ) )
		urlPath= "/" + urlPath;
	}

	if( debug >4 ) log("createRequest " + origPath + " " + urlPath  );
	return createRequest( urlPath );
    }

The code surrounded by //HERE IS THE CODE WE THINK IS WRONG 
is our debug code.  For Outer.jsp, we see
	contextPath = , origPath = /test/Outer.jsp
and for Inner.jsp, we see
	contextPath = /test, origPath = /test/Inner.jsp
In themselves, we think these values are fine.  The context really is
different: in one case we're coming from the servlet, in the other from
/test/Outer.jsp.  However, the logic surrounded by
//HERE IS THE CODE WE THINK IS WRONG means that an origPath beginning with a
slash, such as /test/Inner.jsp, won't be interpreted as absolute: no urlPath
will ever cause this method to throw away the contextPath and start from
"root". When we replaced the logic with

	// END DEBUG STUFF
	// append context path
	if( !"".equals(contextPath) && !"/".equals(contextPath)) {

	// BEGIN HERE IS THE FIX
	    if( urlPath.startsWith("/" ) )
		{} // leave it alone, it's absolute
	    else
		urlPath=contextPath + "/" + urlPath;
	// BEGIN HERE IS THE FIX

It then worked in our application as we think it should.

If this is a correct fix, what is the procedure for getting into Tomcat?
Also, are there any regression tests for us to run (it works for our
product which uses lots of dynamic jsp includes (jsp:include)? Finally, what
are the rules about using our fix with Tomcat?


Thanks,
-Randy Hammon
Engineer and TranceMaster

Evolve Software
615 Battery St.
San Francisco, CA 94111
415-445-5116

Re: jsp:include: the bug and the fix

Posted by Costin Manolache <co...@eng.sun.com>.
"Hammon, Randy" wrote:

> Hello,
> this is my first message to the list. Hope I'm going about this in the right
> way.

Hi,

Thanks for the patch, it's great to see bug reports _with_ code to fix !

I do have few questions:

In your test, you have  2 files: Outer.jsp and Inner.jsp.

In Outer.jsp you include "/test/Inner.jsp".

Now, if you use the root context ( i.e. you don't have a "/test"
context ) - everything is fine.

If you do have a /test context and the 2 files are part of the
/test context, then include should not use the /test prefix for
the include - all absolute paths are relative to the context.

Costin


> Scenario
> ------------
> Given the following 2 jsp files and servlet( putting all three in a
> directory
> named /test and doing what you need so that Tomcat can find it) to invoke
> them:
>
> Outer.jsp
> ----------
> html>
> <head>
> <title>Include test</title>
> </head>
> <body>
> This is a test of forwarding and inclusion.  For some reason, it's not
> working right for us with Tomcat.
>
> <p>
> <jsp:include page="/test/Inner.jsp" flush="true" />
> </body>
> </html>
> ----------
>
> Inner.jsp
> -----------
> This is an inner file included via &lt;jsp:include&gt;.
> ----------
>
> and the servlet to invoke them.
>
> test.Test.java
> ----------------
> package test;
> import java.io.IOException;
> import javax.servlet.*;
> import javax.servlet.http.*;
> /**
>  *  Simplest possible test of problem configuration:
>  *  servlet forwards request to JSP, JSP includes another.
>  */
> public class Test
>     extends HttpServlet
> {
>     public void doGet(HttpServletRequest request,
>                       HttpServletResponse response)
>         throws ServletException, IOException
>     {
>         RequestDispatcher rd =
>
> this.getServletContext().getRequestDispatcher("/test/Outer.jsp");
>         rd.forward(request, response);
>     }
>
> }
> ----------------
>
> If you run this scenario in the 3.1 Tomcat release, Outer.jsp will blow up
> on the jsp:include line.
> What appears to be happening is that the ContextManager creates a context
> for Outer.jsp, then when it creates a context for
> inner.jsp, it finds it already has a context from Outer.jsp and a context
> path, /test, so it uses it, and some code thinks it's supposed to prepend
> /test to the /test/Inner.jsp url in the jsp:include statement. We think that
> it should NOT do this, since /test/Inner.jsp is an absolute
> path. Here's the code in class org.apache.tomcat.core.ContextManager, in the
> method createRequest(Context ctx, String urlPath).
> The implementation looks like this:
>
>     Request createRequest( Context ctx, String urlPath ) {
>         // assert urlPath!=null
>
>         // deal with paths with parameters in it
>         String contextPath=ctx.getPath();
>         String origPath=urlPath;
>
>         // BEGIN DEBUG STUFF
>         System.err.println("contextPath = " + contextPath +
>                            ", origPath = " + origPath);
>         // END DEBUG STUFF
>
>         // append context path
>         if( !"".equals(contextPath) && !"/".equals(contextPath)) {
>
>         // BEGIN HERE IS THE CODE WE THINK IS WRONG
>             if( urlPath.startsWith("/" ) )
>                 urlPath=contextPath + urlPath;
>             else
>                 urlPath=contextPath + "/" + urlPath;
>         // END HERE IS THE CODE WE THINK IS WRONG
>
>         } else {
>             // root context
>             if( !urlPath.startsWith("/" ) )
>                 urlPath= "/" + urlPath;
>         }
>
>         if( debug >4 ) log("createRequest " + origPath + " " + urlPath  );
>         return createRequest( urlPath );
>     }
>
> The code surrounded by //HERE IS THE CODE WE THINK IS WRONG
> is our debug code.  For Outer.jsp, we see
>         contextPath = , origPath = /test/Outer.jsp
> and for Inner.jsp, we see
>         contextPath = /test, origPath = /test/Inner.jsp
> In themselves, we think these values are fine.  The context really is
> different: in one case we're coming from the servlet, in the other from
> /test/Outer.jsp.  However, the logic surrounded by
> //HERE IS THE CODE WE THINK IS WRONG means that an origPath beginning with a
> slash, such as /test/Inner.jsp, won't be interpreted as absolute: no urlPath
> will ever cause this method to throw away the contextPath and start from
> "root". When we replaced the logic with
>
>         // END DEBUG STUFF
>         // append context path
>         if( !"".equals(contextPath) && !"/".equals(contextPath)) {
>
>         // BEGIN HERE IS THE FIX
>             if( urlPath.startsWith("/" ) )
>                 {} // leave it alone, it's absolute
>             else
>                 urlPath=contextPath + "/" + urlPath;
>         // BEGIN HERE IS THE FIX
>
> It then worked in our application as we think it should.
>
> If this is a correct fix, what is the procedure for getting into Tomcat?
> Also, are there any regression tests for us to run (it works for our
> product which uses lots of dynamic jsp includes (jsp:include)? Finally, what
> are the rules about using our fix with Tomcat?
>
> Thanks,
> -Randy Hammon
> Engineer and TranceMaster
>
> Evolve Software
> 615 Battery St.
> San Francisco, CA 94111
> 415-445-5116
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tomcat-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tomcat-dev-help@jakarta.apache.org