The Author Online Book Forums are Moving

The Author Online Book Forums will soon redirect to Manning's liveBook and liveVideo. All book forum content will migrate to liveBook's discussion forum and all video forum content will migrate to liveVideo. Log in to liveBook or liveVideo with your Manning credentials to join the discussion!

Thank you for your engagement in the AoF over the years! We look forward to offering you a more enhanced forum experience.

tempusfugit (144) [Avatar] Offline
#1
This section is confusing and in my opinion possibly incorrect.

I reviewed the Java(TM) Servlet API Specification Version: 2.4
SRV.8.3.1 Included Request Parameters
SRV.8.4.2 Forwarded Request Parameters

The request parameter attributes seem to fulfill very distinct roles on an included servlet and a servlet invoked through a forward.

If my interpretation is correct then the attributes for an included servlet ("javax.servlet.include.*") carry the values of the included servlet. This behaviour should only necessary if in fact the corresponding HttpRequestServlet methods (getRequestURI, getContextPath, getServletPath, getPathInfo, getQueryString) return the values of the original request for an included servlet.

For servlets being forwarded to, the attributes ("javax.servlet.forward.*") carry the values of the servlet that is first in the forwarding chain, i.e. the values of the original request. This behaviour should only necessary if in fact the corresponding HttpRequestServlet methods (getRequestURI, getContextPath, getServletPath, getPathInfo, getQueryString) return the values that correspond to the current servlet (which received the request through a forward).

The following statement in the section troubled me:

"The values of these attributes provide the same information as the HttpServletRequest methods getRequestURI, getContextPath, getServletPath, getPathInfo, and getQueryString."

'the same' almost implies that they are exchangeable within the same servlet - they aren't. Granted the statement does get tempered a little later:

"These values correspond to the parameters of the original request, without regard to further forwarding."

This is true for the "forward" attributes, but is not relevant to "include" attributes. Then:

"For example, if a forwarded servlet invokes req.getServletPath(), the result will be the same as if the java.servlet.include.servlet_path attribute had been acquired with req.getAttribute(?javax.servlet.include.servlet_path?)"

OK, the question marks that should be double quotes are just the beginning:
- a 'forwarded' servlet should be looking for 'java.servlet.forward.servlet_path', not 'java.servlet.include.servlet_path'
- req.getAttribute("javax.servlet.forward.servlet_path") will return the path to the servlet that is at the beginning calling chain, i.e. the first servlet to call 'forward'
- on a forwarded servlet req.getServletPath() will return the path of the forwarded servlet
- hence on a forwarded servlet req.getServletPath() and req.getAttribute("javax.servlet.forward.servlet_path") WILL NOT return the same result

To finally understand what is really going on I set up a test web application with six servlets that use 'forward' and 'include' under Tomcat 5.0.28 to give me some answers. The calling chain was set up like this:

TestServlet -> ForwardServlet -> NextForwardServlet <=> IncludeServlet <=> NestedIncludeServlet

-> forward
<=> include

See source code and output below

Analysis of the results:

TestServlet
Method Values: The methods return values originate from the current request and servlet.
"forward" attributes: Not set. This servlet was not forwarded to.
"include" attributes: Not set. This servlet was not included.

ForwardServlet
Method Values: The methods return values originate from the current servlet (ForwardServlet).
"forward" attributes: Originate from the original request and the servlet at the beginning of the calling chain.
"include" attributes: Not set. This servlet was not "included".

NextForwardServlet
Method Values: The methods return values originate from the current servlet (NextForwardServlet).
"forward" attributes: Originate from the original request and the servlet at the beginning of the calling chain.
"include" attributes: Not set. This servlet was not "included".

IncludeServlet
Method Values: The methods return values originate from the servlet that is actually processing the request (NextForwardServlet). It's the servlet that started the "include" calling chain.
"forward" attributes: The fact that these attributes are set is incidental. They are only set because the servlet that initiated the "include" calling chain was itself being forwarded to.
"include" attributes: These attribute values originate from the current servlet (IncludeServlet).

NestedIncludeServlet
Method Values: The methods return values originate from to the servlet that is actually processing the request (NextForwardServlet). It's the servlet that started the "include" calling chain.
"forward" attributes: The fact that these attributes are set is incidental. They are only set because the servlet that initiated the "include" calling chain was itself being forwarded to.
"include" attributes: These attribute values originate from the current servlet (NestedIncludeServlet).

===========================================
SOURCE
===========================================
-------------------------------------------
TestServlet.java
-------------------------------------------
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class TestServlet extends HttpServlet {

public void doGet(
HttpServletRequest req,
HttpServletResponse res
) throws
ServletException,
IOException
{
Util.logAttributes( req, this.getClass().getName() );

RequestDispatcher rd = req.getRequestDispatcher( "/ForwardServlet" );
rd.forward( req, res );
}
}

-------------------------------------------
ForwardServlet.java
-------------------------------------------
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class ForwardServlet extends HttpServlet {

public void doGet(
HttpServletRequest req,
HttpServletResponse res
) throws
ServletException,
IOException
{
Util.logAttributes( req, this.getClass().getName() );

RequestDispatcher rd = req.getRequestDispatcher( "/NextForwardServlet" );
rd.forward( req, res );
}
}

-------------------------------------------
NextForwardServlet.java
-------------------------------------------
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class NextForwardServlet extends HttpServlet {

public void doGet(
HttpServletRequest req,
HttpServletResponse res
) throws
ServletException,
IOException
{
Util.logAttributes( req, this.getClass().getName() );

PrintWriter pw = res.getWriter();
pw.println( "<html>" );
pw.println( "<head>" );
pw.println( "</head>" );
pw.println( "<body>" );

RequestDispatcher rd = req.getRequestDispatcher( "/IncludeServlet" );
rd.include( req, res );

pw.print( Util.getResult(req) );

pw.println( "</body>" );
pw.println( "</html>" );
}
}

-------------------------------------------
IncludeServlet.java
-------------------------------------------
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class IncludeServlet extends HttpServlet {

public void doGet(
HttpServletRequest req,
HttpServletResponse res
) throws
ServletException,
IOException
{
Util.logAttributes( req, this.getClass().getName() );

RequestDispatcher rd = req.getRequestDispatcher( "/NestedIncludeServlet" );
rd.include( req, res );
}
}

-------------------------------------------
NestedIncludeServlet.java
-------------------------------------------
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class NestedIncludeServlet extends HttpServlet {

public void doGet(
HttpServletRequest req,
HttpServletResponse res
) throws
ServletException,
IOException
{
Util.logAttributes( req, this.getClass().getName() );
}
}

-------------------------------------------
Util.java
-------------------------------------------
import javax.servlet.http.*;

public class Util {

private static final String sbName = "UtilStringBuffer";

public static String getResult(
HttpServletRequest req
){
return getBuffer( req ).toString();
}

public static void logAttributes(
HttpServletRequest req,
String title
){

StringBuffer sb = getBuffer( req );

if(title != null && title.length() > 0)
sb.append( "<h3>" + title + "</h3>
" );

logMethodValue( sb, "getRequestURI", req.getRequestURI() );
logMethodValue( sb, "getContextPath", req.getContextPath());
logMethodValue( sb, "getServletPath", req.getServletPath());
logMethodValue( sb, "getPathInfo", req.getPathInfo() );
logMethodValue( sb, "getQueryString", req.getQueryString());

sb.append("

");

logAttribute( sb, req, "javax.servlet.forward.request_uri" );
logAttribute( sb, req, "javax.servlet.forward.context_path" );
logAttribute( sb, req, "javax.servlet.forward.servlet_path" );
logAttribute( sb, req, "javax.servlet.forward.path_info" );
logAttribute( sb, req, "javax.servlet.forward.query_string" );

sb.append("

");

logAttribute( sb, req, "javax.servlet.include.request_uri" );
logAttribute( sb, req, "javax.servlet.include.context_path" );
logAttribute( sb, req, "javax.servlet.include.servlet_path" );
logAttribute( sb, req, "javax.servlet.include.path_info" );
logAttribute( sb, req, "javax.servlet.include.query_string" );

sb.append("


");
}

private static void logAttribute(
StringBuffer sb,
HttpServletRequest req,
String attributeName
){
sb.append( "Attribute " + attributeName + ": " );
sb.append( req.getAttribute( attributeName ) + "

" );
}

private static void logMethodValue(
StringBuffer sb,
String methodName,
String methodValue
){
sb.append( "Method HttpServletRequest."
+ methodName + "()
: "
+ methodValue + "

" );
}

private static StringBuffer getBuffer(
HttpServletRequest req
){
StringBuffer sb;
Object o = req.getAttribute( sbName );

if (o instanceof StringBuffer) {
sb = (StringBuffer)o;

} else {
sb = new StringBuffer();
req.setAttribute( sbName, sb );
}
return sb;
}

}

========================================================
OUTPUT with
http://localhost:8080/fwdinc/TestServlet?test=testvalue
on Tomcat 5.0.28
========================================================

TestServlet
Method HttpServletRequest.getRequestURI(): /fwdinc/TestServlet
Method HttpServletRequest.getContextPath(): /fwdinc
Method HttpServletRequest.getServletPath(): /TestServlet
Method HttpServletRequest.getPathInfo(): null
Method HttpServletRequest.getQueryString(): test=testvalue

Attribute javax.servlet.forward.request_uri: null
Attribute javax.servlet.forward.context_path: null
Attribute javax.servlet.forward.servlet_path: null
Attribute javax.servlet.forward.path_info: null
Attribute javax.servlet.forward.query_string: null

Attribute javax.servlet.include.request_uri: null
Attribute javax.servlet.include.context_path: null
Attribute javax.servlet.include.servlet_path: null
Attribute javax.servlet.include.path_info: null
Attribute javax.servlet.include.query_string: null


ForwardServlet
Method HttpServletRequest.getRequestURI(): /fwdinc/ForwardServlet
Method HttpServletRequest.getContextPath(): /fwdinc
Method HttpServletRequest.getServletPath(): /ForwardServlet
Method HttpServletRequest.getPathInfo(): null
Method HttpServletRequest.getQueryString(): test=testvalue

Attribute javax.servlet.forward.request_uri: /fwdinc/TestServlet
Attribute javax.servlet.forward.context_path: /fwdinc
Attribute javax.servlet.forward.servlet_path: /TestServlet
Attribute javax.servlet.forward.path_info: null
Attribute javax.servlet.forward.query_string: test=testvalue

Attribute javax.servlet.include.request_uri: null
Attribute javax.servlet.include.context_path: null
Attribute javax.servlet.include.servlet_path: null
Attribute javax.servlet.include.path_info: null
Attribute javax.servlet.include.query_string: null


NextForwardServlet
Method HttpServletRequest.getRequestURI(): /fwdinc/NextForwardServlet
Method HttpServletRequest.getContextPath(): /fwdinc
Method HttpServletRequest.getServletPath(): /NextForwardServlet
Method HttpServletRequest.getPathInfo(): null
Method HttpServletRequest.getQueryString(): test=testvalue

Attribute javax.servlet.forward.request_uri: /fwdinc/TestServlet
Attribute javax.servlet.forward.context_path: /fwdinc
Attribute javax.servlet.forward.servlet_path: /TestServlet
Attribute javax.servlet.forward.path_info: null
Attribute javax.servlet.forward.query_string: test=testvalue

Attribute javax.servlet.include.request_uri: null
Attribute javax.servlet.include.context_path: null
Attribute javax.servlet.include.servlet_path: null
Attribute javax.servlet.include.path_info: null
Attribute javax.servlet.include.query_string: null


IncludeServlet
Method HttpServletRequest.getRequestURI(): /fwdinc/NextForwardServlet
Method HttpServletRequest.getContextPath(): /fwdinc
Method HttpServletRequest.getServletPath(): /NextForwardServlet
Method HttpServletRequest.getPathInfo(): null
Method HttpServletRequest.getQueryString(): test=testvalue

Attribute javax.servlet.forward.request_uri: /fwdinc/TestServlet
Attribute javax.servlet.forward.context_path: /fwdinc
Attribute javax.servlet.forward.servlet_path: /TestServlet
Attribute javax.servlet.forward.path_info: null
Attribute javax.servlet.forward.query_string: test=testvalue

Attribute javax.servlet.include.request_uri: /fwdinc/IncludeServlet
Attribute javax.servlet.include.context_path: /fwdinc
Attribute javax.servlet.include.servlet_path: /IncludeServlet
Attribute javax.servlet.include.path_info: null
Attribute javax.servlet.include.query_string: null


NestedIncludeServlet
Method HttpServletRequest.getRequestURI(): /fwdinc/NextForwardServlet
Method HttpServletRequest.getContextPath(): /fwdinc
Method HttpServletRequest.getServletPath(): /NextForwardServlet
Method HttpServletRequest.getPathInfo(): null
Method HttpServletRequest.getQueryString(): test=testvalue

Attribute javax.servlet.forward.request_uri: /fwdinc/TestServlet
Attribute javax.servlet.forward.context_path: /fwdinc
Attribute javax.servlet.forward.servlet_path: /TestServlet
Attribute javax.servlet.forward.path_info: null
Attribute javax.servlet.forward.query_string: test=testvalue

Attribute javax.servlet.include.request_uri: /fwdinc/NestedIncludeServlet
Attribute javax.servlet.include.context_path: /fwdinc
Attribute javax.servlet.include.servlet_path: /NestedIncludeServlet
Attribute javax.servlet.include.path_info: null
Attribute javax.servlet.include.query_string: null


Message was edited by: tempusfugit