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

Client proxy framework clears previously set Content-Language header when setting POST message body entity

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Major Major
    • 3.5.1.Final, 4.0.0.Beta3
    • 3.0.19.Final
    • jaxrs
    • None
    • Hide

      Use the snippet below:

      public class App 
      {
          
          @Path("/api")
          interface MyInterface {
              @POST
              @Produces(MediaType.TEXT_PLAIN)
              @Consumes(MediaType.TEXT_PLAIN)
              String performOperation(
                      @HeaderParam(HttpHeaders.CONTENT_LANGUAGE) String contentLanguage,
                      String subject);
      
              @POST
              @Produces(MediaType.TEXT_PLAIN)
              @Consumes(MediaType.TEXT_PLAIN)
              String performOperation2(
                      String subject,
                      @HeaderParam(HttpHeaders.CONTENT_LANGUAGE) String contentLanguage);
          }
      
          
          public static void main( String[] args )
          {
              Client client = ClientBuilder.newClient();
              WebTarget target = client.target("http://example.com/base/uri");
              ResteasyWebTarget rtarget = (ResteasyWebTarget)target;
      
              MyInterface remoteService = rtarget.proxy(MyInterface.class);
              
              try {
                  remoteService.performOperation("fr", "a sentence to operate on");
              } catch (Exception ignore) {}
              
              try {
                  remoteService.performOperation2("a sentence to operate on", "fr");
              } catch (Exception ignore) {}
          }
      }
      

      Note the two methods, one having their parameters in the reverse order than the order.

      And run.

      First invocation sends no Content-Language header on the wire:

      DEBUG org.apache.http.wire -  >> "POST /base/uri/api HTTP/1.1[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Accept: text/plain[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Accept-Encoding: gzip, deflate[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Content-Type: text/plain[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Content-Length: 24[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Host: example.com[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Connection: Keep-Alive[\r][\n]"
      DEBUG org.apache.http.wire -  >> "[\r][\n]"
      

      But second invocation does send the Content-Language header:

      DEBUG org.apache.http.wire -  >> "POST /base/uri/api HTTP/1.1[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Accept: text/plain[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Accept-Encoding: gzip, deflate[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Content-Language: fr[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Content-Type: text/plain[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Content-Length: 24[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Host: example.com[\r][\n]"
      DEBUG org.apache.http.wire -  >> "Connection: Keep-Alive[\r][\n]"
      DEBUG org.apache.http.wire -  >> "[\r][\n]"
      
      Show
      Use the snippet below: public class App { @Path("/api") interface MyInterface { @POST @Produces(MediaType.TEXT_PLAIN) @Consumes(MediaType.TEXT_PLAIN) String performOperation( @HeaderParam(HttpHeaders.CONTENT_LANGUAGE) String contentLanguage, String subject); @POST @Produces(MediaType.TEXT_PLAIN) @Consumes(MediaType.TEXT_PLAIN) String performOperation2( String subject, @HeaderParam(HttpHeaders.CONTENT_LANGUAGE) String contentLanguage); } public static void main( String[] args ) { Client client = ClientBuilder.newClient(); WebTarget target = client.target("http://example.com/base/uri"); ResteasyWebTarget rtarget = (ResteasyWebTarget)target; MyInterface remoteService = rtarget.proxy(MyInterface.class); try { remoteService.performOperation("fr", "a sentence to operate on"); } catch (Exception ignore) {} try { remoteService.performOperation2("a sentence to operate on", "fr"); } catch (Exception ignore) {} } } Note the two methods, one having their parameters in the reverse order than the order. And run. First invocation sends no Content-Language header on the wire: DEBUG org.apache.http.wire - >> "POST /base/uri/api HTTP/1.1[\r][\n]" DEBUG org.apache.http.wire - >> "Accept: text/plain[\r][\n]" DEBUG org.apache.http.wire - >> "Accept-Encoding: gzip, deflate[\r][\n]" DEBUG org.apache.http.wire - >> "Content-Type: text/plain[\r][\n]" DEBUG org.apache.http.wire - >> "Content-Length: 24[\r][\n]" DEBUG org.apache.http.wire - >> "Host: example.com[\r][\n]" DEBUG org.apache.http.wire - >> "Connection: Keep-Alive[\r][\n]" DEBUG org.apache.http.wire - >> "[\r][\n]" But second invocation does send the Content-Language header: DEBUG org.apache.http.wire - >> "POST /base/uri/api HTTP/1.1[\r][\n]" DEBUG org.apache.http.wire - >> "Accept: text/plain[\r][\n]" DEBUG org.apache.http.wire - >> "Accept-Encoding: gzip, deflate[\r][\n]" DEBUG org.apache.http.wire - >> "Content-Language: fr[\r][\n]" DEBUG org.apache.http.wire - >> "Content-Type: text/plain[\r][\n]" DEBUG org.apache.http.wire - >> "Content-Length: 24[\r][\n]" DEBUG org.apache.http.wire - >> "Host: example.com[\r][\n]" DEBUG org.apache.http.wire - >> "Connection: Keep-Alive[\r][\n]" DEBUG org.apache.http.wire - >> "[\r][\n]"

      The Client clears the Content-Language header when adding the POST body, irrespective of what has be set previously.

      This was discovered with the proxy flavour but I suspect this would occur with the regular client as well.

      Short root cause analysis

      Processing the body parameter invokes method
      org.jboss.resteasy.client.jaxrs.internal.proxy.processors.invocation.MessageBodyParameterProcessor.process(ClientInvocationBuilder, Object)
      which creates an entity using constructor javax.ws.rs.client.Entity.Entity(T, MediaType, Annotation[]): this constructor creates a new Variant with a null Locale.

      Then setting the entity with method org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.setEntity(Entity)
      clears the existing Content-Language header because does not perform any null check, which is a problem because the ClientRequestHeaders.setLanguage method has a "remove-if-null" semantic...

              rhn-engineering-ema Jim Ma
              pdavoust Pascal Davoust (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Created:
                Updated:
                Resolved: