Uploaded image for project: 'RESTEasy'
  1. RESTEasy
  2. RESTEASY-2693

AbstractMultipartFormDataWriter only sends one form data when using async IO

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Major Major
    • None
    • 4.5.8.Final
    • Netty integration
    • None

      This is a follow up issue to RESTEASY-2627.

      When creating a multipart/form-data response with more than one form data like this:

      MultipartFormDataOutput multipart = new MultipartFormDataOutput();
      multipart.addFormData("content", request.getContent(), MediaType.APPLICATION_OCTET_STREAM_TYPE);
      multipart.addFormData("more content", "test", MediaType.APPLICATION_OCTET_STREAM_TYPE);
      
      GenericEntity<MultipartFormDataOutput> entity = new GenericEntity<MultipartFormDataOutput>(multipart) {
      };
      return Response.ok(entity, MediaType.MULTIPART_FORM_DATA).build(); 

      only one of the added multiparts is actually sent.

      The output looks like the following:

      --a51b09ef-55d7-48fe-87a7-9832b6751079
      Content-Disposition: form-data; name="more content"
      Content-Type: application/octet-stream
      
      test 

      although I would expect:

      --a51b09ef-55d7-48fe-87a7-9832b6751079
      Content-Disposition: form-data; name="more content"
      Content-Type: application/octet-stream
      
      test
      --a51b09ef-55d7-48fe-87a7-9832b6751079
      Content-Disposition: form-data; name="content"
      Content-Type: application/octet-stream
      
      example string
      --a51b09ef-55d7-48fe-87a7-9832b6751079 

       

      I used RESTeasy 4.6.0-SNAPSHOT version from master, as RESTEASY-2627 is fixed there and I use Netty.

      Stack Trace
      org.jboss.resteasy.spi.LoggableFailure: RESTEASY003880: Unable to find contextual data of type: jakarta.ws.rs.ext.Providers
          at org.jboss.resteasy.core.ContextParameterInjector$GenericDelegatingProxy.invoke(ContextParameterInjector.java:155)
          at com.sun.proxy.$Proxy14.getMessageBodyWriter(Unknown Source)
          at org.jboss.resteasy.plugins.providers.multipart.AbstractMultipartWriter.asyncWritePart(AbstractMultipartWriter.java:178)
          at org.jboss.resteasy.plugins.providers.multipart.AbstractMultipartFormDataWriter.lambda$asyncWriteParts$0(AbstractMultipartFormDataWriter.java:60)
          at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1072)
          at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
          at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2073)
          at org.jboss.resteasy.plugins.server.netty.ChunkOutputStream.lambda$asyncWrite$1(ChunkOutputStream.java:148)
          at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:578)
          at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:552)
          at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:491)
          at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:616)
          at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:605)
          at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:96)
          at io.netty.channel.DefaultChannelPromise.setSuccess(DefaultChannelPromise.java:78)
          at io.netty.channel.DefaultChannelPromise.setSuccess(DefaultChannelPromise.java:73)
          at org.jboss.resteasy.plugins.server.netty.MultiPromise.forward(MultiPromise.java:44)
          at org.jboss.resteasy.plugins.server.netty.MultiPromise.lambda$newPromise$0(MultiPromise.java:31)
          at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:578)
          at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:552)
          at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:491)
          at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:616)
          at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:605)
          at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:104)
          at io.netty.util.concurrent.PromiseCombiner.tryPromise(PromiseCombiner.java:170)
          at io.netty.util.concurrent.PromiseCombiner.access$600(PromiseCombiner.java:35)
          at io.netty.util.concurrent.PromiseCombiner$1.operationComplete0(PromiseCombiner.java:62)
          at io.netty.util.concurrent.PromiseCombiner$1.operationComplete(PromiseCombiner.java:44)
          at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:578)
          at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:552)
          at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:491)
          at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:616)
          at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:605)
          at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:104)
          at io.netty.util.internal.PromiseNotificationUtil.trySuccess(PromiseNotificationUtil.java:48)
          at io.netty.channel.ChannelOutboundBuffer.safeSuccess(ChannelOutboundBuffer.java:717)
          at io.netty.channel.ChannelOutboundBuffer.remove(ChannelOutboundBuffer.java:272)
          at io.netty.channel.ChannelOutboundBuffer.removeBytes(ChannelOutboundBuffer.java:352)
          at io.netty.channel.socket.nio.NioSocketChannel.doWrite(NioSocketChannel.java:438)
          at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0(AbstractChannel.java:931)
          at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.flush0(AbstractNioChannel.java:354)
          at io.netty.channel.AbstractChannel$AbstractUnsafe.flush(AbstractChannel.java:895)
          at io.netty.channel.DefaultChannelPipeline$HeadContext.flush(DefaultChannelPipeline.java:1372)
          at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:750)
          at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:742)
          at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:728)
          at io.netty.channel.ChannelOutboundHandlerAdapter.flush(ChannelOutboundHandlerAdapter.java:125)
          at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:750)
          at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:765)
          at io.netty.channel.AbstractChannelHandlerContext$WriteTask.run(AbstractChannelHandlerContext.java:1071)
          at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
          at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
          at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
          at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:503)
          at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
          at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
          at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
          at java.base/java.lang.Thread.run(Thread.java:829)
      

              Unassigned Unassigned
              lars_ka Lars Kaulen (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

                Created:
                Updated: