Forum Discussion

richie's avatar
richie
Community Hero
6 years ago

Script Assertion To Grab 4 'Set-Cookies' To Set 1 'Cookie' Header In Follow Up Request

Hi,

 

This is related to my other 'cookie' post - but that other post has side tracked onto another issue I need to solve - so I've created a second post with a specific issue.

 

A while back nmrao created the script assertion below to extract the 'Set-Cookie' http header values and write them to corresponding 'Cookie' http headers, so if 4 'Set-Cookie' headers are included on the initial request, 4 'Cookie' headers with the relevant values (including all the additional header value attributes) are added to the nextStep.

//Courtesy of Rao
//This script assetion reads the http response, //collect the cookies for the next http request //Provide the next step name where you want to set the Cookie to the request or //Use property expansion for below def nextStepName = 'REST Request' def nextRequest = context.testCase.testSteps[nextStepName].httpRequest def headers = nextRequest.requestHeaders if (messageExchange.responseHeaders.containsKey('Set-Cookie')) { log.info "Found Cookie in the response headers" def cookiez = messageExchange.responseHeaders['Set-Cookie'].value def list = [] cookiez.each { cookies -> //def (name, value) = cookies.toString().split('=',2) list.add(cookies.toString()) } headers['Cookie'] = list } else { log.warn "Not Found Cookie in the response headers" } nextRequest.requestHeaders =

The above is great - exactly what I was told I needed - however, what the developers have now told me is that what I need is slighlty different from the above - despite them saying the above gave me what I need!  aah! frustrating!

 

The http Set-Cookie/Cookie theory (according to the following links (link1 and link2) indicates that the 'Set-Cookie' header values (without the additional attributes) are used to populate the follow up single Cookie header value.

 

so if we receive in the initial message

 

Set-Cookie: returnurl=345678; Max-Age=3600; Expires=Tue, 18-Jun-2019 22:58:30 GMT; Path=/; Secure; HttpOnly

Set-Cookie: authtype=234567; Max-Age=3600; Expires=Tue, 18-Jun-2019 22:58:30 GMT; Path=/; Secure; HttpOnly

Set-Cookie: state=123456; Max-Age=3600; Expires=Tue, 18-Jun-2019 22:58:30 GMT; Path=/; Secure; HttpOnly

Set-Cookie: nonce=456789;  Max-Age=3600; Expires=Tue, 18-Jun-2019 22:58:30 GMT; Path=/; Secure; HttpOnly

 

The follow up request would have ONE individual 'Cookie' http header and the value would be made up of the semi colon delimited Set-Cookie values without the additional attributes - so the follow up message's 'Cookie' header would appear as follows:

 

Cookie: returnurl=345678; authtype=234567; state=123456; nonce=456789

Apparently what I've described above is standard http Set-Cookie/Cookie handling and I was told I should've known about this already!

 

I'm stuck updating the script. 

 

Essentially I need to concatenate all the Set-Cookie header VALUES into a single string (semi colon delimiter for each value) - but strip out the additional attributes like Max-Age, Expires, http, secure etc.

 

Can anyone help out?  I know I'm asking a lot here - especially when everyone's already helped so much already

 

I need to pass the 4 'Set-Cookie' header values into the 1 'Cookie' value (stripping out all the attributes so the only the Set Cookie header values are included - apparently this is supposed to be how http 'Set-Cookie' and http 'Cookie' headers work.  The server sends the Set-Cookie headers to tell the client to send a single Cookie http header and the value populating the Cookie are.

 

Thanks guys - really!

 

richie

 

  • richie 

     

    Finally, simulated the issue.

     

    Here you go:

     

    def nextStepName = 'REST Request'
    def headerToLook = 'Set-Cookie'
    def headerToSet = 'Cookie'
    
    def nextRequest = context.testCase.testSteps[nextStepName].httpRequest
    def headers = nextRequest.requestHeaders
    def showHeaderCount = {msg -> log.info "Header count ${msg} is: headers.size()" }
    showHeaderCount('before')
    if (headerToSet in headers.getKeys()) {
    	headers.remove(headerToSet)
    	showHeaderCount('after')
    }
    if (messageExchange.responseHeaders.containsKey(headerToLook)) {
      log.info "Found ${headerToLook} in the response headers"
      def cookiez = messageExchange.getResponseHeaders().get(headerToLook)
      def computedValue = cookiez.collect { it.split(';').first()}.join('; ')
      log.info "Value for Cookie header is evaluated to : ${computedValue}"
      headers.put(headerToSet, computedValue)
      log.info 'Headers updated'
      nextRequest.requestHeaders = headers
      log.info headers
    } else {
      log.warn "Not Found ${headerToLook} in the response headers"
    }
  • nmrao's avatar
    nmrao
    Champion Level 3

    richie 

    What does it show if you add below statement after

    "def cookiez = messageExchange.responseHeaders['Set-Cookie'].value"

     

    log.info cookiez.size()

    Also you may try adding  below instead of "list.add(cookies.toString())"

    list.add(cookies.split().first())

     

     

    • richie's avatar
      richie
      Community Hero

      Hey!

       

      nmrao adding the following

       

      log.info cookiez.size()

      immediately after 

      def cookiez = messageExchange.responseHeaders['Set-Cookie'].value

      Returned the following:

       

      Wed Jun 19 01:08:49 BST 2019: INFO: Found Cookie in the response headers
      Wed Jun 19 19:53:36 BST 2019: INFO: Found Cookie in the response headers
      Wed Jun 19 19:53:36 BST 2019: INFO: 4
      

       

      but when I commented out 

      list.add(cookies.toString())

      and replaced with

      list.add(cookies.split().first())

      I got an assertion failure on the script assertion - it was a nullpointer - I've attached the stacktrace if it helps at all.

       

      Currently the script assertion is as follows:

       

      //Courtesy of Rao
      //This script assetion reads the http response, 
      //collect the cookies for the next http request
      //Provide the next step name where you want to set the Cookie to the request or
      //Use property expansion for below
      def nextStepName = 'REST Request'
      def nextRequest = context.testCase.testSteps[nextStepName].httpRequest
      def headers = nextRequest.requestHeaders
      if (messageExchange.responseHeaders.containsKey('Set-Cookie')) {
        log.info "Found Cookie in the response headers"
        def cookiez = messageExchange.responseHeaders['Set-Cookie'].value
      log.info cookiez.size()  
        def list = []  
        cookiez.each { cookies ->
           //def (name, value) = cookies.toString().split('=',2)
           list.add(cookies.toString())
           //list.add(cookies.split().first())
           
        }
        headers['Cookie'] = list
      } else {
        log.warn "Not Found Cookie in the response headers"
      }
      nextRequest.requestHeaders = headers

      Thanks guys - Im sorry I cant do anymore to help - feels a bit cheeky - but I just dont know how to proceed!

       

      rich

       

       

      • nmrao's avatar
        nmrao
        Champion Level 3

        richie 

         

        Would you please try below?

         

        def nextStepName = 'REST Request'
        def nextRequest = context.testCase.testSteps[nextStepName].httpRequest
        def headers = nextRequest.requestHeaders
        if (messageExchange.responseHeaders.containsKey('Set-Cookie')) {
          log.info "Found Cookie in the response headers"
          def cookiez = messageExchange.responseHeaders['Set-Cookie'].value
          def computedValue = []
          computedValue << cookiez.flatten().collect { it.split(';').first()}.join('; ')
          headers['Cookie'] = computedValue
        } else {
          log.warn "Not Found Cookie in the response headers"
        }
        log.info headers
        nextRequest.requestHeaders = headers
  • nmrao's avatar
    nmrao
    Champion Level 3

    richie 

    You mean, below header is expected for the following request(s)?

    Cookie: returnurl=345678; authtype=234567; state=123456; nonce=456789
    • richie's avatar
      richie
      Community Hero

      Hey nmrao 

       

      exactly - the individual 'Set-Cookie' values (without the additional attribute name/values pair properties) sourced via the initial request's response are apparently concatenated into a single http 'Cookie' header which is then used in the follow up request

       

      So using my genuine detail from a request - the RAW details for the initial response are as follows:

      Set-Cookie: returnurl=881d9208ca983dcf9a2cc1971d02a8465eefd47cccdeafb751826e947204b8626f505fa6cf1e06dd9f9ceed91a8f0390dfbdf4077b308be6eb91306b6620ad2fd92d06c68387cddcc87a19c9909218dc-87b5428103f85588; Max-Age=3600; Expires=Tue, 18-Jun-2019 22:58:30 GMT; Path=/; Secure; HttpOnly
      Set-Cookie: authtype=b1a5ce49f6c1d7d0b3ccf284e38b9f377ae00744db3862e50c1a78a0c6cd2ad5-58170217357c5777; Max-Age=3600; Expires=Tue, 18-Jun-2019 22:58:30 GMT; Path=/; Secure; HttpOnly
      Set-Cookie: state=968a0b1b4944485e8d2b371d9bde404687b8bb939af05837d52c90c54844d3645b46ff6702dd6ff389e5d05d47917e6da5f2752dd5543e6cd7f4fe8e4d6c624f-707229dfb48ff182; Max-Age=3600; Expires=Tue, 18-Jun-2019 22:58:30 GMT; Path=/; Secure; HttpOnly
      Set-Cookie: nonce=2eee71dfa7b10994120ec98ffe927a47ae41d13409c484a936288463be1dc938-314d577578aaf35d; Max-Age=3600; Expires=Tue, 18-Jun-2019 22:58:30 GMT; Path=/; Secure; HttpOnly

      Should generate the 'Cookie' http header for the following request as

       

      Cookie: returnurl=881d9208ca983dcf9a2cc1971d02a8465eefd47cccdeafb751826e947204b8626f505fa6cf1e06dd9f9ceed91a8f0390dfbdf4077b308be6eb91306b6620ad2fd92d06c68387cddcc87a19c9909218dc-87b5428103f85588; authtype=b1a5ce49f6c1d7d0b3ccf284e38b9f377ae00744db3862e50c1a78a0c6cd2ad5-58170217357c5777; state=968a0b1b4944485e8d2b371d9bde404687b8bb939af05837d52c90c54844d3645b46ff6702dd6ff389e5d05d47917e6da5f2752dd5543e6cd7f4fe8e4d6c624f-707229dfb48ff182; nonce=2eee71dfa7b10994120ec98ffe927a47ae41d13409c484a936288463be1dc938-314d577578aaf35d

      Am I being clear enough?

       

      thanks guys :)

       

      rich