Forum Discussion

swlinn's avatar
swlinn
Occasional Contributor
12 years ago

Request HTTP Header Order is not deterministic

I have a backend that iterates through the HTTP request headers and returns an XML response that provides the name and value of the headers received. I have an assertion that validates the XML returned is as expected. I have 5 request headers defined on my request. What I've found is that the order that SoapUI places these headers on the wire (as seen in the Raw request view as well as my backend response) varies for the last two items, and that variation is causing my assertion to fail. The headers should be presented in the order that they are defined. For example, here are some cut/paste from the Raw request view:

Headers Test 4a - THE ASSERTION PASSES
GET http://192.168.72.70:37111/request/set/simple HTTP/1.1
Accept-Encoding: gzip,deflate
Cookie: c1=blah1;c2=blah2;MyCookie2=value2;c3=blah
Cookie: c1a=blah1a
changeMe: blah
deleteMe: blah
testNumber: 4a
Host: 192.168.72.70:37111
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)

Note ... the order of the headers here is the way the headers are ordered on the request Headers Tab


Headers Test 4a - THE ASSERTION FAILS
GET http://192.168.72.70:37111/request/set/simple HTTP/1.1
Accept-Encoding: gzip,deflate
Cookie: c1=blah1;c2=blah2;MyCookie2=value2;c3=blah
Cookie: c1a=blah1a
changeMe: blah
testNumber: 4a
deleteMe: blah
Host: 192.168.72.70:37111
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)

Note that the testNumber and deleteMe headers are reversed, which causes the backend to respond with these in a different order, which causes the assertion to fail.

Regards,
Steve Linn

4 Replies

  • swlinn's avatar
    swlinn
    Occasional Contributor
    I should have specified my version in my previous post, but based on my other issue I reported I updated to the latest SNAPSHOT of 5.0.0 (SoapUI 5.0.0-m-SNAPSHOT Build Date: 20140605-1354) and still see this problem. It seems to reverse these headers on just this teststep more times than not. This stepstep has 5 headers, but other teststeps that have these 5 and 2 more specified earlier in the list and they do not experience this problem.

    Regards,
    Steve
    • gok's avatar
      gok
      New Contributor

      This issue's been biting me on SOAP UI NG (in ReadyAPI 1.4.1) too. I've been trying to implement our version of HMAC authentication on REST requests. Our method takes the UID, the request method, the full request URI (including the path and query parts - context.requestURI), and the secret key and generates a map, including a hash and a timestamp for the request headers. The groovy script to generate the map can't be run for each header or else the hash and the timestamp may go out of sync between calls - it has to be run once then the values assigned to both headers. Now, on a SOAP UI REST request, the places to deploy a groovy script are limited (and I need to use the WsdlTestRunContext for the complete URI) and I've been trying to run it in the headers themselves, storing the timestamp value as a test case property, returning the hash as the script result, and then picking up the timestamp from the custom property.

       

      The problem is that the order of the headers keeps changing, so if I calculate the hash and store the timestamp value as a test case property, I can't guarantee that the timestamp header will follow the hash header, and the timestamp will have been populated from a previous run's timestamp, resulting in authentication failure.

       

      It's been driving me up the wall. I've spent 3 days trying to find away around the problem (with no success). I'm baffled as to why it's been designed this way - what possible use case could be satisfied by rearranging request headers (apparently at random) between one test run and another? And why can't the analyst set an order to the request headers themselves?

      • gok's avatar
        gok
        New Contributor

        I managed to figure it out - the epihany came when I fully internalised the fact that any HTTP request is just a bunch of text, and headers are just key/value text pairs delimited by a colon and a space and separated by newlines.

         

        Create the first header you want (e.g. header1) and then create the remaining headers you want in a given order with a sprintf call in the new header's Value column,  like so:

         

        ${=sprintf('%s\nheader2: %s\nheader3: %s\nheader4: %s', [${#TestCase#header1val}, ${#TestCase#header2val}, ${#TestCase#header3val}, ${#TestCase#header4}])}

         

        Of course, you have to subvert the UI to do something this straightforward, which makes me think the UI hasn't been designed well at all.