[undertow-dev] FormDataProcessor ending exchange prematurely
Bill O'Neil
bill at dartalley.com
Tue Feb 7 11:11:31 EST 2017
Hey Sven,
What kind of sanitization are you looking for? It should be handling form
encoding for you but I don't think any other type of sanitization.
On Tue, Feb 7, 2017 at 10:17 AM, Sven Kubiak <sven at kubiak.me> wrote:
> Anyone?
>
>
> Cheers,
>
> Sven
>
>
> ------------------------------
> *Von:* Sven Kubiak
> *Gesendet:* Mittwoch, 25. Januar 2017 15:58
> *An:* Bill O'Neil; Stuart Douglas
> *Cc:* Oliver Dain; undertow-dev at lists.jboss.org
> *Betreff:* AW: [undertow-dev] FormDataProcessor ending exchange
> prematurely
>
>
> Hi,
>
>
> sorry, for a kind of off-topic question, but as the FormDataProcessor is
> the topic here, I was wondering if there is already some kind of data
> sanitization in the core form handling of Undertow. If not, which handler
> is a good starting point to hook into for this?
>
>
> Best regards,
>
> Sven
>
>
> ------------------------------
> *Von:* undertow-dev-bounces at lists.jboss.org <undertow-dev-bounces at lists.
> jboss.org> im Auftrag von Bill O'Neil <bill at dartalley.com>
> *Gesendet:* Mittwoch, 25. Januar 2017 14:53
> *An:* Stuart Douglas
> *Cc:* Oliver Dain; undertow-dev at lists.jboss.org
> *Betreff:* Re: [undertow-dev] FormDataProcessor ending exchange
> prematurely
>
> Hey Stuart, your last response reminded me of of a question I had
> hopefully its not unrelated. I was curious how and when you should dispatch
> back to the IO thread. For example lets say we have a simple handler that
> does a SQL query that is composed with the AccessLogHandler.
>
> AccessLogHandler -> BlockingHandler -> CustomSqlHandler In this approach I
> believe the final access log statement will be logged from the worker
> thread not the initial IO thread.
>
> Is it possible / recommended to kick back to an IO thread once blocking is
> complete?
>
> AccessLogHandler -> BlockingHandler -> CustomSqlHandler ->
> DispatchBackToIOThread? This way the final logging of AccessLogHandler is
> handled in the IO thread.
>
> I'm not very familiar with the best ways to mix the nonblocking and
> blocking handlers.
>
>
>
> On Wed, Jan 25, 2017 at 12:24 AM, Stuart Douglas <sdouglas at redhat.com>
> wrote:
>
>> 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 at 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 at lists.jboss.org
>> > https://lists.jboss.org/mailman/listinfo/undertow-dev
>>
>> _______________________________________________
>> undertow-dev mailing list
>> undertow-dev at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/undertow-dev
>
>
>
> _______________________________________________
> undertow-dev mailing list
> undertow-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/undertow-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/undertow-dev/attachments/20170207/40d2e481/attachment.html
More information about the undertow-dev
mailing list