[resteasy-dev] [Resteasy-developers] Proper handling of NotModified/304

Marek Kopecky mkopecky at redhat.com
Mon Jun 27 03:59:41 EDT 2016


RestEasy is attempting to read the entity, because I call 
"response.readEntity(InputStream.class);".

Marek


On 06/22/2016 04:08 PM, Sean Dawson wrote:
>
>
> I'm using Jetty 8.1.7.v20120910.  You are seeing something slightly 
> different but I think it's the same issue - on a 304, why is RestEasy 
> attempting to read the entity (when everything says there shouldn't be 
> one).
>
>
> On Mon, Jun 20, 2016 at 4:53 AM, Marek Kopecky <mkopecky at redhat.com 
> <mailto:mkopecky at redhat.com>> wrote:
>
>     Hi Sean,
>
>     I'm still unable to reproduce this. What container do you use?
>
>     I use WildFly (with Undertow) with RESTEasy 3.0.17. I attach
>     WildFly application (with end-point and exception mapper) and
>     junit test with client part. I still see only ProcessingException:
>
>      1. mvn package -DskipTests
>      2. deploy
>      3. mvn test
>
>     I see this exception:
>
>     javax.ws.rs.ProcessingException: java.lang.IllegalStateException:
>     RESTEASY004575: Input stream was empty, there is no entity
>         at
>     org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readFrom(ClientResponse.java:285)
>         at
>     org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readEntity(ClientResponse.java:181)
>         at
>     org.jboss.resteasy.specimpl.BuiltResponse.readEntity(BuiltResponse.java:219)
>         at org.resteasy.test.MyTest.testBuildResponse(MyTest.java:29)
>         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>         at
>     sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>         at
>     sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>         at java.lang.reflect.Method.invoke(Method.java:498)
>         at
>     org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
>         at
>     org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
>         at
>     org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
>         at
>     org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
>         at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
>         at
>     org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
>         at
>     org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
>         at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
>         at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
>         at
>     org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
>         at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
>         at
>     org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
>         at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
>         at
>     org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
>         at
>     org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
>         at
>     org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
>         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>         at
>     sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>         at
>     sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>         at java.lang.reflect.Method.invoke(Method.java:498)
>         at
>     org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
>         at
>     org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
>         at
>     org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
>         at
>     org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
>         at
>     org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
>     Caused by: java.lang.IllegalStateException: RESTEASY004575: Input
>     stream was empty, there is no entity
>         at
>     org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readFrom(ClientResponse.java:239)
>         ... 32 more
>
>     Marek
>
>     On 06/14/2016 09:08 PM, Sean Dawson wrote:
>>
>>     Hi Marek, thanks for the response.
>>
>>     So I think you're right - that in the simplest of testcases,
>>     buffering of the (null) entity is NOT attempted.
>>
>>     There are a few other differences that may factor in to this but
>>     once I've modified the simple version to be slightly closer to
>>     our environment, the difference on the client between this...
>>
>>     Exception in thread "main" javax.ws.rs.RedirectionException: HTTP
>>     304 Not Modified
>>      at
>>     org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:172)
>>      at
>>     org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.BodyEntityExtractor.extractEntity(BodyEntityExtractor.java:60)
>>      at
>>     org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:104)
>>      at
>>     org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:76)
>>     Disconnected from the target VM, address: '127.0.0.1:64538
>>     <http://127.0.0.1:64538>', transport: 'socket'
>>      at com.sun.proxy.$Proxy18.download(Unknown Source)
>>      at Client.main(Client.java:29)
>>     Process finished with exit code 1
>>
>>     And this...
>>
>>     Exception in thread "main" java.lang.NullPointerException
>>      at
>>     org.jboss.resteasy.util.ReadFromStream.readFromStream(ReadFromStream.java:30)
>>      at
>>     org.jboss.resteasy.client.jaxrs.internal.ClientResponse.bufferEntity(ClientResponse.java:307)
>>      at
>>     org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:155)
>>      at
>>     org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.BodyEntityExtractor.extractEntity(BodyEntityExtractor.java:60)
>>      at
>>     org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:104)
>>      at
>>     org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:76)
>>      at com.sun.proxy.$Proxy18.download(Unknown Source)
>>      at Client.main(Client.java:29)
>>     Process finished with exit code 1
>>
>>     Is one line registering this exception mapper provider on the
>>     server (ie. adding it for the second run)...
>>
>>     @Provider public class MyExceptionMapperimplements ExceptionMapper<WebApplicationException>
>>     {
>>          @Override public Response toResponse(WebApplicationException wae)
>>          {
>>              int status = wae.getResponse().getStatus();
>>              Response.ResponseBuilder responseBuilder = Response.status(status);
>>              return responseBuilder.entity(wae.toString()).build();
>>          }
>>     }
>>     In both cases the status code is 304.  My actual exception
>>     mapper(s) are more complicated than this - setting media types,
>>     etc - but in this simple version, the above shows our issue. 
>>     What more/else should I be doing instead?
>>
>>
>>
>>     On Tue, Jun 14, 2016 at 4:44 AM, Marek Kopecky
>>     <mkopecky at redhat.com <mailto:mkopecky at redhat.com>> wrote:
>>
>>         Hi.
>>
>>         The mailing-list on sourceforge
>>         (resteasy-developers at lists.sourceforge.net
>>         <mailto:resteasy-developers at lists.sourceforge.net>) has been
>>         deprecated. Forwarding to correct mailing list (
>>         resteasy-dev at lists.jboss.org
>>         <mailto:resteasy-dev at lists.jboss.org> ).
>>
>>         Yes, "A 304 response cannot contain a message-body", see
>>         https://tools.ietf.org/html/rfc7232#section-4.1
>>
>>         Sean, can you sent example of your end-point and client part?
>>         I tried to use this endpoint and client. It works as I
>>         expected. Any NPE is thrown:
>>
>>         @GET @Path("nothing")
>>         @Produces("application/octet-stream")
>>         public InputStream nothing() {
>>              if (true) {
>>                  throw new WebApplicationException(304);
>>              }
>>              return new ByteArrayInputStream("hello".getBytes());
>>         }
>>
>>         -----------------------------------------------------------------------------------
>>
>>         Response response =client.target(generateURL("/nothing")).request().get();
>>         int code = response.getStatus();
>>         if (code ==200) {
>>              InputStream is = response.readEntity(InputStream.class);
>>              Assert.assertEquals("hello", TestUtil.readString(is));
>>         }
>>         if (code ==304) {
>>              try {
>>                  response.readEntity(InputStream.class);
>>                  Assert.fail("ProcessingException was not thrown");
>>              }catch (ProcessingException e) {
>>                  // expected exception }
>>         }
>>         response.close();
>>
>>         But I found some performance issue with 304. If I use this
>>         end-point:
>>
>>         @GET @Path("nothing")
>>         public Response nothing()
>>         {
>>             return Response.status(304).entity("test").build();
>>         }
>>
>>         In WildFly, body is erased in Undertow (AFAIK), but RESTEasy
>>         could do this too. Check for 304 can be implemented here:
>>         https://github.com/resteasy/Resteasy/blob/master/resteasy-jaxrs/src/main/java/org/jboss/resteasy/core/ServerResponseWriter.java#L50
>>         Now, interceptors are applied to these kinds of responses.
>>         This is not necessary and it may not be optimal for
>>         performance. Alessio, Ron, WDYT? Marek -------- Forwarded
>>         Message --------
>>         Subject: 	[Resteasy-developers] Proper handling of
>>         NotModified/304
>>         Date: 	Fri, 10 Jun 2016 10:50:03 -0400
>>         From: 	Sean Dawson <sean.dawson2014 at gmail.com>
>>         <mailto:sean.dawson2014 at gmail.com>
>>         To: 	resteasy-devel.
>>         <resteasy-developers at lists.sourceforge.net>
>>         <mailto:resteasy-developers at lists.sourceforge.net>
>>
>>         I posted this on users but I'm thinking it's a RestEasy bug
>>         at this point.
>>         The code seems to buffer the entity and then throw a
>>         processing exception if the status is bad.
>>         In the case of 304, no body is provided (and this seems to be
>>         correct according to the standard).  I have found no way
>>         server side to return anything but null as the entity.  So
>>         attempting to buffer it on a 304 just seems plain incorrect
>>         (and results in an NPE).
>>         Am I missing something?
>>         Setting the custom header on the response does work - but I'm
>>         not sure that'll make it back to the client when it passes
>>         through servers that usually strip those out.
>>
>>
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/resteasy-dev/attachments/20160627/967e71f5/attachment-0001.html 


More information about the resteasy-dev mailing list