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

Async Request parameters & Parts #31

Open
glassfishrobot opened this issue Feb 27, 2012 · 8 comments
Open

Async Request parameters & Parts #31

glassfishrobot opened this issue Feb 27, 2012 · 8 comments
Assignees
Labels
Enhancement New feature or request

Comments

@glassfishrobot
Copy link

Section 9.7.2 describes a set of request attributes that contain the path values of the original request, so that they may be accessed by a servlet called as a result of a AsyncContext.dispatch(...)

However, this implies that these attributes are only set after a AsyncContext.dispatch(...), which means that they are not available to a thread that might be acting as part of a startAsync().... AsyncContext.complete() pattern.

Note that a thread cannot access the original request paths via AsyncContext.getRequest().getServletPath() because the value returned from that can be affected by forwards that happen before and/or after the startAsync call, or even a forward after an async dispatch. The path methods are inherently volatile.

I think that the ASYNC request parameters should be set when startAsync is called, so that those values are available for the entire async life cycle and not only during async dispatch.

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
Reported by gregwilkins

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
gregwilkins said:
Note also that the language used in this section could be improved, where it says:

The values of these attributes must be equal to the return values of the
HttpServletRequest methods getRequestURI, getContextPath, getServletPath,
getPathInfo, getQueryString respectively, invoked on the request object passed to
the first servlet object in the call chain that received the request from the client.

A request might never be passed to a servlet as it might be handled entirely by filters, or the first servlet object might be changed by a filter doing a dispatch.

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
rstoyanchev said:

can be affected by forwards that happen before and/or after the startAsync call

Greg, the impression I got from #41 is that forwards cannot happen after a call to startAsync or are you referring to a different scenario?

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
gregwilkins said:
very late response.

I don't see why a request can't be forwarded after async is started. It would be strange way to handle a request, but I see no reason for it to be prohibited.

But even if it can't be forwarded, it can be return from previous forwards after startAsync, so the values returned by the request.getXxx() methods will be volatile if access from an asynchronous thread.

Hence I believe the request attributes are the best way to obtain path information as they are immutable once set and thus thread safe.

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
This issue was imported from java.net JIRA SERVLET_SPEC-31

@glassfishrobot
Copy link
Author

@glassfishrobot glassfishrobot self-assigned this Jun 6, 2018
@gregw gregw changed the title Async Request parameters Async Request parameters & Parts Dec 12, 2019
@gregw
Copy link
Contributor

gregw commented Dec 12, 2019

@gregw
Copy link
Contributor

gregw commented Dec 12, 2019

Here are the proposals from the first thread:

/**
 * <p>
 * This class represents a call-back mechanism that will notify implementations
 * as HTTP body parameters becomes available to be read without blocking.
 * </p>
 * <p>
 * A typical usage pattern is:
 * <pre>
 *    class MyParameterListener implements ParameterListener
 *    {
 *      public void onParameterAvailable(Stream stream) throws IOException
 *      {
 *        while(stream.isReady())
 *          process(stream.getParameter());
 *      }
 *    }
 *  </pre>
 */
public interface ParameterListener
{
    /**
     * When an instance of the <code>ParameterListener</code> is registered with a {@link ServletInputStream},
     * this method will be invoked by the container the first time when it is possible
     * to read a Parameter. Subsequently the container will invoke this method if and only
     * if {@link Stream#isReady()} method has been called and has returned <code>false</code>.
     *
     * @throws IOException if an I/O related error has occurred during processing
     */
    void onParameterAvailable(ParameterListener.Stream stream) throws IOException;

    /**
     * Invoked when all data for the current request has been read.
     *
     * @throws IOException if an I/O related error has occurred during processing
     */

    public default void onAllDataRead() throws IOException {};

    /**
     * Invoked when an error occurs processing the request.
     */
    public default void onError(Throwable t) {};
    
    public interface Stream
    {
        /**
         * @return True if a Parameter is available to be returned from getParameter();
         */
        boolean isReady();
        
        /**
         * @return A Parameter that has been read from the request body.  The Parameter will be fully
         * constituted either in memory or as a file, so that any calls on the {@link Parameter#getInputStream()}
         * will not block on the remote connection.
         * @throws IllegalStateException if {@link #isReady()} has not been call or has been
         * called and returned false.
         */
        Map.Entry<String, String> getParameter();
    }
}
/**
 * <p>
 * This class represents a call-back mechanism that will notify implementations
 * as HTTP multipart request data becomes available to be read without blocking.
 * </p>
 * <p>
 * A typical usage pattern is:
 * <pre>
 *    class MyPartListener implements PartListener
 *    {
 *      public void onPartAvailable(Stream stream) throws IOException
 *      {
 *        while(stream.isReady())
 *          process(stream.getPart());
 *      }
 *    }
 *  </pre>
 */
public interface PartListener
{
    /**
     * When an instance of the <code>PartListener</code> is registered with a {@link ServletInputStream},
     * this method will be invoked by the container the first time when it is possible
     * to read a part. Subsequently the container will invoke this method if and only
     * if {@link Stream#isReady()} method has been called and has returned <code>false</code>.
     *
     * @throws IOException if an I/O related error has occurred during processing
     */
    void onPartAvailable(PartListener.Stream stream) throws IOException;

    /**
     * Invoked when all data for the current request has been read.
     *
     * @throws IOException if an I/O related error has occurred during processing
     */

    public default void onAllDataRead() throws IOException {};

    /**
     * Invoked when an error occurs processing the request.
     */
    public default void onError(Throwable t) {};
    
    public interface Stream
    {
        /**
         * @return True if a Part is available to be returned from getPart();
         */
        boolean isReady();
        
        /**
         * @return A Part that has been read from the request body.  The part will be fully
         * constituted either in memory or as a file, so that any calls on the {@link Part#getInputStream()}
         * will not block on the remote connection.
         * @throws IllegalStateException if {@link #isReady()} has not been call or has been
         * called and returned false.
         */
        Part getPart();
    }
}

@gregw gregw added Enhancement New feature or request and removed Component: I/O labels Jan 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants