The handler is executed
io.undertow.server.Connectors#executeRootHandler, which means that
when the call stack returns the exchange will be ended.
Conceptually this is similar to how dispatching to a thread pool
works, when you call dispatch(HttpHandler) the exchange will be ended
when the call stack returns, even though you are no longer on the IO
thread (unless you call dispatch again).
Stuart
On Wed, Jan 25, 2017 at 3:57 PM, Oliver Dain <oliver(a)analyticspot.com> wrote:
I have some code for handling file uploads. It uses FormDataProcessor
and
tries to do everything asynchronously. I call "FormDataParser.parse" passing
in another handler. I'll call that handler the OnFormDataAvailable. The
OnFormDataAvailable handler checks to see if it's on the IO thread. If it
is, it calls dispatch. Either way, once we're sure we're dispatched that
handler calls yet another handler.
What I've seen is that my OnFormDataAvailable handler (the one called by
parse()) is not on the IO thread so it doesn't need to call dispatch. And
yet, the exchange gets ended before the handler it calls is even close to
complete.
I've found a fix, but I don't understand why it's necessary. Specifically,
if OnFormDataAvailable is not on the IO thread when its invoked it calls the
0-argument version of "HttpServerExchange.dispatch()" (which you've told
me
in another conversation shouldn't ever be necessary). If I do that,
everything is fine.
For completeness, here's the complete code:
public class FormDataParsingHandler {
private static final Logger log =
LoggerFactory.getLogger(FormDataParsingHandler.class);
private static final FormParserFactory formParserFactory =
FormParserFactory.builder().build();
public static final AttachmentKey<FormData> FORM_DATA_ATTACHMENT_KEY =
AttachmentKey.create(FormData.class);
/**
* The only public method - this is what gets exposed as the HttpHandler.
*/
public CompletableFuture<FormData> parseForm(HttpServerExchange exchange)
{
log.info("audio file upload request received.");
FormDataParser parser = formParserFactory.createParser(exchange);
if (parser == null) {
log.warn("No parser found that can handle this content type. Headers
were: {}", exchange.getRequestHeaders());
throw new UserVisibleException("No parser for the given content
type.", ResponseCodes.BAD_REQUEST);
}
CompletableFuture<FormData> toComplete = new CompletableFuture<>();
try {
parser.parse(new OnFormDataAvailable(toComplete));
} catch (Exception e) {
log.error("Error parsing form data:", e);
throw wrapAsUnchecked(e);
}
exchange.addExchangeCompleteListener((ex, nextListener) -> {
// Must close the parser so it can free any temporary files that were
created.
try {
parser.close();
} catch (IOException e) {
log.error("Error closing the FormDataParser. Request was handled
successfully but temporary files may not "
+ "have been cleaned up.", e);
}
nextListener.proceed();
});
return toComplete;
}
// The FormDataParser calls an HttpHandler when it's complete so we add a
silly handler here that does nothing but
// complete this method's future when the form data is available.
private static class OnFormDataAvailable implements HttpHandler {
private final CompletableFuture<FormData> toComplete;
private OnFormDataAvailable(CompletableFuture<FormData> toComplete) {
this.toComplete = toComplete;
}
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception
{
// Before we complete the future we have to re-dispatch or we'll fall
off the end of this method and Undertow
// will complete the exchange on our behalf.
FormData data = exchange.getAttachment(FormDataParser.FORM_DATA);
if (exchange.isInIoThread()) {
log.debug("Was on the IO thread. Re-dispatching.");
exchange.dispatch(SameThreadExecutor.INSTANCE, () ->
afterDistpach(data));
} else {
// THIS THE MYSTERY LINE. WHY IS THIS NEEDED?
exchange.dispatch();
afterDistpach(data);
}
}
private void afterDistpach(FormData data) {
if (data == null) {
toComplete.completeExceptionally(
new UserVisibleException("Parsing of data failed.",
ResponseCodes.BAD_REQUEST));
} else {
toComplete.complete(data);
}
}
}
}
--
CTO, Analytic Spot
44 West Broadway #222
Eugene, OR 97401
analyticspot.com • 425-296-6556
www.linkedin.com/in/oliverdain
_______________________________________________
undertow-dev mailing list
undertow-dev(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/undertow-dev