Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Content-Type request header issue under Chrome

    Hi,

    I'm having a faulty Content-Type request header built under Chrome when I issue an updateData() on
    my data source. Everything works fine under FireFox. My updateData() relies on the PUT HTTP method.

    The problem is that the Content-Type request header contains "text/xml, application/json" instead
    of simply "application/json" as defined in my data source. I checked the request headers under Chrome
    and FireFox (using FireBug) and they indeed don't get produced the same way...

    This makes my Spring MVC java backend produce an HTTP 500 error with the following stack trace :

    Code:
    2011-11-13 10:27:40,433 (http-8080-4) ERROR [com.meicpg.ti.web.exceptions.ExceptionResource] - java.lang.IllegalArgumentException: Invalid token character ',' in token "xml, application/json"
    	at org.springframework.http.MediaType.checkToken(MediaType.java:282)
    	at org.springframework.http.MediaType.<init>(MediaType.java:255)
    	at org.springframework.http.MediaType.parseMediaType(MediaType.java:584)
    	at org.springframework.http.HttpHeaders.getContentType(HttpHeaders.java:286)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.readWithMessageConverters(HandlerMethodInvoker.java:612)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveRequestBody(HandlerMethodInvoker.java:597)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:346)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:171)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
    	at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:571)
    ...
    Here's the relevant part of my data source definition:
    Code:
    MyDataSource.addProperties
    ({
    	dataFormat : 'json',
    ...
    	operationBindings :
    	[
    		{ operationType : 'fetch', dataProtocol : 'getParams', dataFormat : 'json',
    			requestProperties : { httpMethod : 'GET',
    				httpHeaders : { 'Accept' : 'application/json', 'Content-Type' : 'application/json' } } },
    
    		{ operationType : 'update', dataProtocol : 'postMessage', dataFormat : 'json',
    			requestProperties : { httpMethod : 'PUT',
    			httpHeaders : { 'Accept' : 'application/json', 'Content-Type' : 'application/json' } } }
    	],
    ...
    Any idea why this is happening ? Any way to fix this ?

    Thanks,

    #2
    We don't have anywhere where we would try to combine two mime-types for that header, which clearly would be incorrect. This suggests a Chrome bug. However, with similar code:

    Code:
    isc.DataSource.create({
        ID:"theDS",
    	dataFormat : 'json',
    	operationBindings :
    	[
    		{ operationType : 'fetch', dataProtocol : 'getParams', dataFormat : 'json',
    			requestProperties : { httpMethod : 'GET',
    				httpHeaders : { 'Accept' : 'application/json', 'Content-Type' : 'application/json' } } },
    
    		{ operationType : 'update', dataProtocol : 'postMessage', dataFormat : 'json',
    			requestProperties : { httpMethod : 'PUT',
    			httpHeaders : { 'Accept' : 'application/json', 'Content-Type' : 'application/json' } } }
    	]
    }).fetchData();
    .. we do not see this effect in Chrome 15.0.874.106 m on Windows 7, at least looking at the request with Chrome's own tools. Could you be using an old version of Chrome?

    Comment


      #3
      Hi,

      I just tested this using different versions, and have reproduced it on
      the following versions of Google:

      - Google Chrome 16.0.912.36 beta on OSX
      - Google Chrome 15.0.874.120 on OSX
      - Google Chrome 15.0.874.106 on Linux Ubuntu
      - Google Chrome 15.0.874.120m on Windows XP

      Also, I tried your example code, replacing fetchData() with updateData({})
      and I did reproduce the problem with all of these versions.

      Indeed, fetchData() does not expose this problem, but updateData({}) does ...

      Use this code to test :
      Code:
      isc.DataSource.create({
          ID:"theDS",
      	dataFormat : 'json',
      	operationBindings :
      	[
      		{ operationType : 'fetch', dataProtocol : 'getParams', dataFormat : 'json',
      			requestProperties : { httpMethod : 'GET',
      				httpHeaders : { 'Accept' : 'application/json', 'Content-Type' : 'application/json' } } },
      
      		{ operationType : 'update', dataProtocol : 'postMessage', dataFormat : 'json',
      			requestProperties : { httpMethod : 'PUT',
      			httpHeaders : { 'Accept' : 'application/json', 'Content-Type' : 'application/json' } } }
      	]
      }).updateData({});
      Thanks for providing some feedback as this is a major road block for us.

      Kind regards,

      Comment


        #4
        We've tracked this to a Chrome bug with xmlHttpRequest where multiple calls to setRequestHeader() are combined for the Content-Type header instead of the last-wins policy that all other browsers correctly implement. A workaround is to avoid setting the Content-Type header via requestProperties.httpHeaders and set dsRequest.contentType in transformRequest instead.

        Comment


          #5
          Thanks for the workaround. I'll try it out and I'll let you know how that turns out for me ...

          Comment


            #6
            Thanks,

            The proposed workaround does work, although what's weird is that for the "fetch" operation,
            supplying a dsRequest.contentType doesn't get propagated to the actual request headers,
            and this for all browsers (Chrome, FF, etc).

            So what I end up doing is setting up my operationBindings as follows :
            Code:
            operationBindings :
            [
             { operationType : 'fetch', dataProtocol : 'getParams', dataFormat : 'json',
                 requestProperties : { httpMethod : 'GET',
                 httpHeaders : { 'Accept' : 'application/json',
                      'Content-Type' : 'application/json' } } },
            
            { operationType : 'update', dataProtocol : 'postMessage', dataFormat : 'json',
                 requestProperties : { httpMethod : 'PUT',
                 httpHeaders : { 'Accept' : 'application/json' }}}
            ]
            And in my dataSource.transformRequest() I have the following :
            Code:
            if (dsRequest.operationType != 'fetch')
            	dsRequest.contentType = 'application/json';
            I find it odd that the behavior is different ... Not sure if it's related to 'GET' versus 'PUT'
            or actual difference between operationType values ...

            Is all of this normal ? Thanks,

            Comment


              #7
              What would be the meaning of "content-type" for a GET request? There's no body. Are you trying to tell the server that you've JSON-encoded things in the URL parameters?

              Comment


                #8
                That is is a good point. Indeed, the GET doesn't require a Content-Type per say, but we do use Spring MVC
                annotations and we require the Content-Type to be provided in order for Spring MVC to do the appropriate
                backend controller dispatching as this is the discriminent for 2 of our controllers.

                Does that make sense ?

                Comment


                  #9
                  A quick look at some GET requests from various browsers shows that they do not send Content-Type at all. We haven't made sure, but most likely the HTTP spec does not list this as a header that's relevant to GET requests. Can you just use some other discriminant that really applies to GET requests (eg a parameter).

                  Comment


                    #10
                    Thanks for the advice - It does make sense. We'll try and adapt our GET controllers to be "Content-Type" agnostic.

                    Comment

                    Working...
                    X