> A request with `Content-Type: multipart/form-data` is an interesting place for establishing the async I/O patterns from Servlet 3.1.
>
> Some thoughts.
>
> Servlet 4.x will likely not be updated, as the project is moving to Jakarta EE 9 which is just Servlet 4.0 with the namespace change.
> Any new features will likely be part of Servlet 5.x on the jakarta namespace, and Jakarta EE 10.
I see. Makes sense.
> Each part would need it's own Async I/O behavior, with their own InputStream (and Charset) passed along with all of the part specific headers.
We may be able to reuse the same InputStream but I suppose one InputStream per part would make things more elegant. That way we can even reuse the existing `javax.servlet.http.Part` too.
> Since we are working with a form, what is the nature of the request if a partial / incomplete / bad form is detected half way through?
> How is this communicated via the API? There needs to be part level failure, and overall form level / request failure.
To have an API that is reasonably similar to `ReadListener`, I propose something like this:
```
public interface PartListener {
void onPartDataAvailable(javax.servlet.http.Part part);
void onAllPartDataRead(javax.servlet.http.Part part);
void onAllDataRead();
void onPartError(javax.servlet.http.Part part, Throwable t);
void onError(Throwable t);
}
```
> Currently, If the form is bad, the Container can communicate this back via the HttpServletResponse.
> But if we go Async, then the app has the ability to generate a HttpServletResponse that is nonsensical for the validity of the form as a whole.
>
> If the app is using this proposed new API, what does container do with the existing .getParts() / .getPart(), / and .getParameter() level APIs?
> Are they expected to continue to work? (I say yes, as the Servlet could be expecting it in async, but a Filter, or Security component might not be)
I suppose the behavior would be similar to Servlet 4's async/NIO APIs (
https://docs.oracle.com/javaee/7/tutorial/servlets013.htm):
```
public class ExampleServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
final AsyncContext acontext = request.startAsync();
final PartStream partStream = request.getPartStream();
partStream.setPartListener(new PartListener() {
@Override
void onPartDataAvailable(Part part) {
final InputStream input = part.getInputStream();
do {
final byte buffer[] = new byte[4 * 1024];
final int length = input.read(buffer);
// append buffer[0, length] to file...
} while (input.isReady());
}
@Override
void onAllPartDataRead(PartInfo part) {
// final touches to the file (e.g. resizing it if it is an image)
}
@Override
void onAllDataRead() {
// This signals that every part in the request has been processed
}
@Override
void onPartError(Part part, Throwable t) {
// This signals an error during processing of the given part
}
@Override
void onError(Throwable t) {
// This signals a general error (e.g. socket closed?)
}
});
}
}
```