hurl icon indicating copy to clipboard operation
hurl copied to clipboard

Working with list of response HTTP headers values in hurl

Open zdans-pk opened this issue 9 months ago • 3 comments

Hello, I would like to ask how to properly work with list in hurl. Maybe I've missed something but I couldn't find proper information in documentation or issues so I'm creating this request.

Scenario:

I want to check if there is a cookie that has "xsrf" string in the name. So it will match items like:

Set-Cookie: XSRF-TOKEN=eyJpdiI6Ik95cz
Set-Cookie: XSRF=eyJpdiI6Ik95cz
Set-Cookie: XSRF_token=eyJpdiI6Ik95cz
Set-Cookie: Xsrf_token=eyJpdiI6Ik95cz

Code

The code with one of the options I've tried:

GET http://127.0.0.1:3000/
[Asserts]
#this works only when there is one Set-Cookie in response
header "Set-Cookie" matches "(?i).*xsrf.*"

hurl version

hurl --version
hurl 6.1.1 (x86_64-apple-darwin24.0) libcurl/8.7.1 (SecureTransport) LibreSSL/3.3.6 zlib/1.2.12 nghttp2/1.63.0
Features (libcurl):  alt-svc AsynchDNS HSTS HTTP2 IPv6 Largefile libz NTLM SPNEGO SSL UnixSockets
Features (built-in): brotli

Error

But when I have more than one HTTP header in response with the same name (e.g. Set-Cookie) hurl reads it as a list and returns error that types between actual and expected are not consistent. Error:

error: Assert failure
  --> csrf.hurl:6:0
   |
   | GET http://127.0.0.1:3000/
   | ...
 6 | header "Set-Cookie" matches "(?i).*xsrf.*"
   |   actual:   list <[XSRF-TOKEN=eyJpdiI6Inc5ajFwMGJrZlgrRlZnWEZsRVNmamc9PSIsInZhbHVlIjoiR1ROSjZKMFNROU5mM2RvZzRSSGhrVnQwWUxaUGFLYm0yNEthbHcydFg5UjRSdDVSMDhsYktDbjFEQjBzdXlsZkRid2pUSi9nZGZ5T0UrME54RldXQ2JuSkF4bEJZZ0k4eDBiRmFVZVo2UVk1cExmQjJYUWNGYUowTHR4eU1IcW4iLCJtYWMiOiIyZmQ2OGI4YTNmMzM1ZThjNjY3N2E3YTAxM2E0MTc2NDBiODhmMGM1NDAyYjc4YjQ4YzkwNTUzYTczNTk2MjVkIiwidGFnIjoiIn0%3D; expires=Fri, 18 Apr 2025 11:20:51 GMT; Max-Age=604800; path=/; domain=.webhook.site,webhooksite_session=bsiE8ljHkUOWrCjt7jxnxScWM7zIzHsD3mDx9jeZ; expires=Fri, 18 Apr 2025 11:20:51 GMT; Max-Age=604800; path=/; domain=.webhook.site; httponly]>
   |   expected: matches regex <(?i).*xsrf.*>
   |   >>> types between actual and expected are not consistent

Options tried

I was trying to use code as below but it didn't work.

header "Set-Cookie[*]" matches "(?i).*xsrf.*"
header "Set-Cookie[1]" matches "(?i).*xsrf.*"

Also I can capture those values, but not sure how to properly work with that

[Captures]
cookie_list: header "Set-Cookie"

Will appreciate your answer and help!

zdans-pk avatar Apr 11 '25 11:04 zdans-pk

Hi @zdans-pk , you can access the nth item of an array with the nth filter for example header "Set-Cookie" nth 0 matches "(?i).xsrf."

But you need to know that the index exists beforehand. We may add something like a each predicate in the future https://github.com/Orange-OpenSource/hurl/issues/2212

fabricereix avatar Apr 11 '25 12:04 fabricereix

You can also work with cookie query: https://hurl.dev/docs/asserting-response.html#cookie-assert

GET http://localhost:8000/cookies/set
HTTP 200

# Explicit check of Set-Cookie header value. If the attributes are
# not in this exact order, this assert will fail. 
Set-Cookie: LSID=DQAAAKEaem_vYg; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly; Path=/accounts; SameSite=Lax;
Set-Cookie: HSID=AYQEVnDKrdst; Domain=localhost; Expires=Wed, 13 Jan 2021 22:23:01 GMT; HttpOnly; Path=/
Set-Cookie: SSID=Ap4PGTEq; Domain=localhost; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly; Path=/

# Using cookie assert, one can check cookie value and various attributes.
[Asserts]
cookie "LSID" == "DQAAAKEaem_vYg"
cookie "LSID[Value]" == "DQAAAKEaem_vYg"
cookie "LSID[Expires]" exists
cookie "LSID[Expires]" contains "Wed, 13 Jan 2021"
cookie "LSID[Max-Age]" not exists
cookie "LSID[Domain]" not exists
cookie "LSID[Path]" == "/accounts"
cookie "LSID[Secure]" exists
cookie "LSID[HttpOnly]" exists
cookie "LSID[SameSite]" == "Lax"

jcamiel avatar Apr 11 '25 12:04 jcamiel

Hi @zdans-pk , you can access the nth item of an array with the nth filter for example header "Set-Cookie" nth 0 matches "(?i).xsrf."

But you need to know that the index exists beforehand. We may add something like a each predicate in the future #2212

Thank you very much @fabricereix! This is very helpful! This works perfect!

Will try to find a way to detect number of headers. Already checked that count works here well.

Appreciate!

zdans-pk avatar Apr 11 '25 13:04 zdans-pk