Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify on closing response before returning from dispatch forward() #426

Open
pmd1nh opened this issue Oct 13, 2021 · 7 comments
Open

Clarify on closing response before returning from dispatch forward() #426

pmd1nh opened this issue Oct 13, 2021 · 7 comments
Labels
Candidate4NextRelease This issues should be consider for inclusion in the next release project. Question Further information is requested

Comments

@pmd1nh
Copy link

pmd1nh commented Oct 13, 2021

Servlet Spec. section 9.4. The Forward Method states:

Before the forward method of the RequestDispatcher interface returns without exception, the response content must be sent and committed, and closed by the servlet container, unless the request was put into the asynchronous mode.

When a wrapped response is used in the dispatch forward, which response object should be closed:

  1. The wrapped response
  2. The underlying/base response
@pmd1nh pmd1nh added the Question Further information is requested label Oct 13, 2021
@joakime
Copy link

joakime commented Oct 15, 2021

My expectations ...

The wrapped response interface is used during the dispatch.
The underlying/base response is used once dispatch is done to ensure commit + close before returning to caller of RequestDispatch.forward().

IMO, the wrapped response should not be allowed to subvert or generally muck around with this rule. (such as preventing flush, or doing in-wrapper buffering, etc)

@gregw
Copy link
Contributor

gregw commented Oct 16, 2021

Current Jetty implementation is:

                // If we are not async and not closed already, then close via the possibly wrapped response.
                if (!baseRequest.getHttpChannelState().isAsync() && !baseResponse.getHttpOutput().isClosed())
                {
                    try
                    {
                        response.getOutputStream().close();
                    }
                    catch (IllegalStateException e)
                    {
                        response.getWriter().close();
                    }
                }

So the close is done via the wrapper. Note this does open the possibility that @joakime alludes to that a wrapper may subvert the intention to commit. But note also that the dispatching servlet may itself already be a target of a wrappers that does such subversion. I guess you could look at this as the include method is really just the "official way" to do such subversion (with a whole bunch of other confusing stuff thrown in).

I also think that being put into async mode during a forward is rather suspect... but not as much as being put into async mode during and include!

Either way, I think it may be worthwhile clarifying the language... assuming other containers agree with our interpretation.

@volosied
Copy link

volosied commented Oct 20, 2021

Hello,

Phu brought up this question because of a change we made which caused JSF TCK failures.

MyFaces (and Mojarra, I believe) wrap the response when handing a jsp page before dispatching. However, at the end of the forward, our change closed the underlying response. This caused any further text not to be written out, therefore the TCK failed due to missing elements on the page.

https://github.com/apache/myfaces/blob/2.3.x/impl/src/main/java/org/apache/myfaces/view/jsp/JspViewDeclarationLanguage.java#L110-L115

Basically, per the TCK, it appears to indication option 1. However, the language is not exactly clear.

Peeking at the Tomcat code, it appears to close the wrapped response, too:

https://github.com/apache/tomcat/blob/main/java/org/apache/catalina/core/ApplicationDispatcher.java#L383-L395

I'm still a bit confused by the previous comments. Is the consensus so far for option 1 or option 2?

Thank you

EDIT: Here's the Faces 3.0 Spec regarding the RequestDispatcher.forward() for JSPs:

2.2.6. Render Response:
Jakarta Faces implementations must provide a default ViewHandler implementation that is capable of handling views written in Jakarta Server Pages as well as views written in the Faces View Declaration Language (VDL). In the case of Jakarta Server Pages, the ViewHandler must perform a RequestDispatcher.forward() call to a web application resource whose context-relative path is equal to the view identifier of the component tree.

@pmd1nh
Copy link
Author

pmd1nh commented Oct 20, 2021

Additional information from spec and doc:

Chapter 9. Dispatching Requests
When building a web application, it is often useful to **forward processing of a request to another servlet**, or **to include the output of another servlet in the response.** The RequestDispatcher interface provides a mechanism to accomplish this.

https://javadoc.io/static/jakarta.servlet/jakarta.servlet-api/5.0.0/jakarta/servlet/RequestDispatcher.html#forward-jakarta.servlet.ServletRequest-jakarta.servlet.ServletResponse-

Forwards a request from a servlet to another resource (servlet, JSP file, or HTML file) on the server. This method allows one servlet to do preliminary processing of a request and **another resource to generate the response.**

All the above data point to the base response object in this context. The response content can not be generated from two (or more) resources in the forward case.

@pmd1nh pmd1nh added the Candidate4NextRelease This issues should be consider for inclusion in the next release project. label Oct 27, 2021
@pmd1nh
Copy link
Author

pmd1nh commented Jul 18, 2023

Check back on this clarification - what is response object (base vs wrapped) that should be closed in the forward case ?

@pmd1nh
Copy link
Author

pmd1nh commented Mar 22, 2024

@markt-asf Can you please give this one last review and see if it can make into Servlet-6.1 or close it out. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Candidate4NextRelease This issues should be consider for inclusion in the next release project. Question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants