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

Details

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

    Description

      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.

      Attachments

        Issue Links

          Activity

            People

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

              Dates

                Created:
                Updated:
                Resolved: