Debug Tips

Now that we have many requests in our test file, let’s review some tips on how to debug the executed HTTP exchanges.

Verbose Mode

Using --verbose and --very-verbose for all entries

We can run our test with -v/--verbose option. In this mode, each entry is displayed with debugging information like request HTTP headers, response HTTP headers, cookie storage, duration etc...

$ hurl --verbose --no-output basic.hurl
* Options:
*     fail fast: true
*     insecure: false
*     follow redirect: false
*     max redirect: 50
* ------------------------------------------------------------------------------
* Executing entry 1
*
* Cookie store:
*
* Request:
* GET http://localhost:8080
*
* Request can be run with the following curl command:
* curl 'http://localhost:8080'
*
> GET / HTTP/1.1
> Host: localhost:8080
> Accept: */*
> User-Agent: hurl/1.7.0-snapshot
>
* Response:
*
< HTTP/1.1 200
< Set-Cookie: JSESSIONID=361948EF00AA04CB6659954A8D3EBC9D; Path=/; HttpOnly
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: text/html;charset=UTF-8
< Content-Language: en-FR
< Transfer-Encoding: chunked
< Date: Wed, 17 Aug 2022 07:30:15 GMT
<
*
* ------------------------------------------------------------------------------
* Executing entry 2
*
* Cookie store:
* #HttpOnly_localhost	FALSE	/	FALSE	0	JSESSIONID	361948EF00AA04CB6659954A8D3EBC9D
*
* Request:
* GET http://localhost:8080/not-found
*
* Request can be run with the following curl command:
* curl 'http://localhost:8080/not-found' --cookie 'JSESSIONID=361948EF00AA04CB6659954A8D3EBC9D'
*
> GET /not-found HTTP/1.1
> Host: localhost:8080
> Accept: */*
> Cookie: JSESSIONID=361948EF00AA04CB6659954A8D3EBC9D
> User-Agent: hurl/1.7.0-snapshot
>
* Response:
*
< HTTP/1.1 404
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: text/html;charset=UTF-8
< Content-Language: en-FR
< Transfer-Encoding: chunked
< Date: Wed, 17 Aug 2022 07:30:15 GMT
<
*
...

Lines beginning with * are debug info, lines that begin with > are HTTP request headers and lines that begin with < are HTTP response headers.

In verbose mode, HTTP request and response bodies are not displayed in the debug logs. If you need to inspect the request or response body, you can display more logs with --very-verbose option:

$ hurl --very-verbose --no-output basic.hurl
* Options:
*     fail fast: true
*     insecure: false
*     follow redirect: false
*     max redirect: 50
* ------------------------------------------------------------------------------
* Executing entry 1
*
* Cookie store:
*
* Request:
* GET http://localhost:8080
*
* Request can be run with the following curl command:
* curl 'http://localhost:8080'
*
> GET / HTTP/1.1
> Host: localhost:8080
> Accept: */*
> User-Agent: hurl/1.7.0-snapshot
>
* Request body:
*
* Response:
*
< HTTP/1.1 200
< Set-Cookie: JSESSIONID=0B417BD5890C001B5B25A9B321FE4800; Path=/; HttpOnly
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: text/html;charset=UTF-8
< Content-Language: en-FR
< Transfer-Encoding: chunked
< Date: Wed, 17 Aug 2022 07:42:46 GMT
<
* Response body:
* <!doctype html>
* <html lang="en">
* <head>
*     <meta charset="UTF-8" />
*     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
*     <title>Welcome to Quiz!</title>
*     <link rel="stylesheet" href="/style.css">
*     <!--<script src="script.js"></script>-->
* </head>
* <body>
* <div>
...
* </body>
* </html>
*
*
* ------------------------------------------------------------------------------
* Executing entry 2
*
* Cookie store:
* #HttpOnly_localhost	FALSE	/	FALSE	0	JSESSIONID	0B417BD5890C001B5B25A9B321FE4800
*
* Request:
* GET http://localhost:8080/not-found
*
* Request can be run with the following curl command:
* curl 'http://localhost:8080/not-found' --cookie 'JSESSIONID=0B417BD5890C001B5B25A9B321FE4800'
*
> GET /not-found HTTP/1.1
> Host: localhost:8080
> Accept: */*
> Cookie: JSESSIONID=0B417BD5890C001B5B25A9B321FE4800
> User-Agent: hurl/1.7.0-snapshot
>
* Request body:
*
* Response:
*
< HTTP/1.1 404
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: text/html;charset=UTF-8
< Content-Language: en-FR
< Transfer-Encoding: chunked
< Date: Wed, 17 Aug 2022 07:42:46 GMT
<
* Response body:
* <!doctype html>
* <html lang="en">
* <head>
*     <meta charset="UTF-8" />
*     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
*     <title>Error 404 - Quiz</title>
*     <link rel="stylesheet" href="/style.css">
*     <!--<script src="script.js"></script>-->
* </head>
* <body>
* <div>
*     <a href="/"><img class="logo-img" src="/quiz.svg" alt="Quiz logo"></a>
* </div>
* <div class="main">
*     
* <h1>Error 404, Page not Found!</h1>
*
...
* </body>
* </html>
*
*
...

Debugging a specific entry

If you have a lot of entries (request / response pairs) in your Hurl file, using --verbose or --very-verbose can produce a lot of logs and can be difficult to analyse. Instead of passing options to the command line, you can use an [Options] section that will activate logs only for the specified entry:

# Checking our home page:
# ...

# Check that we have a 404 response for broken links:
# ...

# Check our health API:
# ...

# Check question API:
GET http://localhost:8080/api/questions
# You can pass options to this entry only
[Options]
verbose: true
[QueryStringParams]
offset: 0
size: 20
sort: oldest

HTTP/1.1 200

# ...

And run it without --verbose option:

$ hurl --no-output basic.hurl
* ------------------------------------------------------------------------------
* Executing entry 4
*
* Entry options:
* verbose: true
*
* Cookie store:
* #HttpOnly_localhost	FALSE	/	FALSE	0	JSESSIONID	31818147FB20A7085AC54C372318BAF1
*
* Request:
* GET http://localhost:8080/api/questions
* [QueryStringParams]
* offset: 0
* size: 20
* sort: oldest
*
* Request can be run with the following curl command:
* curl 'http://localhost:8080/api/questions?offset=0&size=20&sort=oldest' --cookie 'JSESSIONID=31818147FB20A7085AC54C372318BAF1'
*
> GET /api/questions?offset=0&size=20&sort=oldest HTTP/1.1
> Host: localhost:8080
> Accept: */*
> Cookie: JSESSIONID=31818147FB20A7085AC54C372318BAF1
> User-Agent: hurl/1.7.0-snapshot
>
* Response:
*
< HTTP/1.1 200
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Wed, 17 Aug 2022 08:11:50 GMT
<
*

Interactive Mode

We can run the whole Hurl file request by request, with the --interactive option:

* Options:
*     fail fast: true
*     insecure: false
*     follow redirect: false
*     max redirect: 50

Interactive mode:

Next request:

GET http://localhost:8080

Press Q (Quit) or C (Continue)

* ------------------------------------------------------------------------------
* Executing entry 1
*
* Cookie store:
*
* Request:
* GET http://localhost:8080
*
* Request can be run with the following curl command:
* curl 'http://localhost:8080'
*
> GET / HTTP/1.1
> Host: localhost:8080
> Accept: */*
> User-Agent: hurl/1.7.0-snapshot
>
* Response:
*
< HTTP/1.1 200
< Set-Cookie: JSESSIONID=B08BF0F6F83E91750A76E97713A5C144; Path=/; HttpOnly
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: text/html;charset=UTF-8
< Content-Language: en-FR
< Transfer-Encoding: chunked
< Date: Wed, 17 Aug 2022 08:18:36 GMT
<
*

Interactive mode:

Next request:

GET http://localhost:8080/not-found

Press Q (Quit) or C (Continue)

Include Headers Like curl

We can also run our file to only output HTTP headers, with -i/--include option. In this mode, headers of the last entry are displayed:

$ hurl -i basic.hurl
HTTP/1.1 200
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sun, 06 Jun 2021 15:11:31 GMT

[{"id":"c0d80047-4fbe-4d45-a005-91b5c7018b34","created":"1995-12-17T03:24:00Z"....

If you want to inspect any entry other than the last one, you can run your test to a given entry with the --to-entry option, starting at index 1:

$ hurl -i --to-entry 2 basic.hurl
HTTP/1.1 404
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: text/html;charset=UTF-8
Content-Language: en-US
Transfer-Encoding: chunked
Date: Sun, 06 Jun 2021 15:14:20 GMT

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title></title>
    <link rel="stylesheet" href="/style.css">
    <!--<script src="script.js"></script>-->
</head>
<body>
<div>
    <img class="logo" src="/quiz.svg" alt="Quiz logo">
</div>
<h1>Error 404, Page not Found!</h1>

<a href="/">Quiz Home</a>


</body>
</html>

Using a Proxy

Finally, you can use a proxy between Hurl and your server to inspect requests and responses.

For instance, with mitmproxy:

  1. First, launch mitmproxy, it will listen to connections on 8888 port

    $ mitmweb -p 8888 --web-port 8889 --web-open-browser
    Web server listening at http://127.0.0.1:8889/
    Proxy server listening at http://*:8888
    
  1. Then, run Hurl with -x/--proxy option

    $ hurl --proxy localhost:8888 basic.hurl
    

The web interface of mitmproxy allows you to inspect, intercept any requests run by Hurl, and see the returned response to Hurl.