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

GZIPDecodingInterceptor may be registered twice when using JAX-RS and REsteasy client on the same application

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Major Major
    • 3.0.22.Final, 3.1.2.Final
    • 3.0.21.Final
    • jaxrs
    • None

      If we have a web application that has a JAX-RS resource and another interface not related to JAX-RS (servlet or a JAX-WS web service, for example), but using resteasy client, we might have an issue where:

      • If the JAX-RS endpoint is acessed and it is doing the providers registration;
      • At the same time, the other endpoint that uses the client request API is accessed;
      • The GZIPDecodingInterceptor will be registered twice

      The consequence is that two GZIPDecodingInterceptor will try to parse the GZIP requests corrupting the gzipinputstream and leading to the following error everytime we try to use the client again:

      Caused by: java.util.zip.ZipException: Not in GZIP format
          at java.util.zip.GZIPInputStream.readHeader(GZIPInputStream.java:164) [rt.jar:1.7.0_97]
          at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:78) [rt.jar:1.7.0_97]
          at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:90) [rt.jar:1.7.0_97]
          at org.jboss.resteasy.plugins.interceptors.encoding.GZIPDecodingInterceptor$FinishableGZIPInputStream.<init>(GZIPDecodingInterceptor.java:30)
          at org.jboss.resteasy.plugins.interceptors.encoding.GZIPDecodingInterceptor.read(GZIPDecodingInterceptor.java:47)
          at org.jboss.resteasy.core.interception.MessageBodyReaderContextImpl.proceed(MessageBodyReaderContextImpl.java:109)
          at org.jboss.resteasy.plugins.interceptors.encoding.GZIPDecodingInterceptor.read(GZIPDecodingInterceptor.java:51)
          at org.jboss.resteasy.core.interception.MessageBodyReaderContextImpl.proceed(MessageBodyReaderContextImpl.java:109)
      

      The issue, as greatly found by our colleague Dennis, is that the client request will try to create a wrapped provider during the other providerfactory provider registration. which means that the following synchronized code block from RegisterBuiltin class won't protect us:

      public class RegisterBuiltin
      {
      
         public static void register(ResteasyProviderFactory factory)
         {
            synchronized (factory)
            {
               if (factory.isBuiltinsRegistered() || !factory.isRegisterBuiltins()) return;
               try
               {
                  registerProviders(factory);
               }
               catch (Exception e)
               {
                  throw new RuntimeException(e);
               }
               factory.setBuiltinsRegistered(true);
            }
         }
      
      //....
      }
      

      This issue is hidden by the ResteasyDeployment.start() is triggered in deployment phase. If we lazily start the ResteasyDeployment when the resource class is accessed. We can find the synchronized block actually is added to different object : ResteasyProviderFactory and ThreadLocalResteasyProviderFactory by resteasy client code in the same deployment.

            rhn-engineering-ema Jim Ma
            rhn-engineering-ema Jim Ma
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: