-
Notifications
You must be signed in to change notification settings - Fork 79
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
Comments
@glassfishrobot Commented |
@glassfishrobot Commented The values of these attributes must be equal to the return values of the 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 Commented
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 Commented 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 Commented |
|
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();
}
} |
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.
The text was updated successfully, but these errors were encountered: