# Technical Documentation: Orange-OpenSource/hurl

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/Orange-OpenSource/hurl)

### Overview (`README.md`)

<picture>
    <source media="(prefers-color-scheme: light)" srcset="/docs/assets/img/logo-light.svg?sanitize=true" > 
    <source media="(prefers-color-scheme: dark)" srcset="/docs/assets/img/logo-dark.svg?sanitize=true" > 
    <img src="/docs/assets/img/logo-light.svg?sanitize=true" width="264px" alt="Hurl Logo">
</picture>

[](https://github.com/Orange-OpenSource/hurl/actions)
[](https://Orange-OpenSource.github.io/hurl/coverage)
[](https://crates.io/crates/hurl)
[](https://hurl.dev)

# What's Hurl?

Hurl is a command line tool that runs <b>HTTP requests</b> defined in a simple <b>plain text format</b>.

It can chain requests, capture values and evaluate queries on headers and body response. Hurl is very
versatile: it can be used for both <b>fetching data</b> and <b>testing HTTP</b> sessions.

Hurl makes it easy to work with <b>HTML</b> content, <b>REST / SOAP / GraphQL</b> APIs, or any other <b>XML / JSON</b> based APIs. 

```hurl
# Go home and capture token
GET https://example.org
HTTP 200
[Captures]
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"


# Do login!
POST https://example.org/login
[Form]
user: toto
password: 1234
token: {{csrf_token}}
HTTP 302
```

Chaining multiple requests is easy:

```hurl
GET https://example.org/api/health
GET https://example.org/api/step1
GET https://example.org/api/step2
GET https://example.org/api/step3
```

# Also an HTTP Test Tool

Hurl can run HTTP requests but can also be used to <b>test HTTP responses</b>.
Different types of queries and predicates are supported, from [XPath] and [JSONPath] on body response,
to assert on status code and response headers.

<a href="https://hurl.dev/player.html?id=starwars&speed=3"><img src="/docs/assets/img/poster-starwars.png" width="100%" alt="Hurl Demo"/></a>


It is well adapted for <b>REST / JSON APIs</b>

```hurl
POST https://example.org/api/tests
{
    "id": "4568",
    "evaluate": true
}
HTTP 200
[Asserts]
header "X-Frame-Options" == "SAMEORIGIN"
jsonpath "$.status" == "RUNNING"    # Check the status code
jsonpath "$.tests" count == 25      # Check the number of items
jsonpath "$.id" matches /\d{4}/     # Check the format of the id
```

<b>HTML content</b>

```hurl
GET https://example.org
HTTP 200
[Asserts]
xpath "normalize-space(//head/title)" == "Hello world!"
```

<b>GraphQL</b> 

~~~hurl
POST https://example.org/graphql
```graphql
{
  human(id: "1000") {
    name
    height(unit: FOOT)
  }
}
```
HTTP 200
~~~

and even <b>SOAP APIs</b>

```hurl
POST https://example.org/InStock
Content-Type: application/soap+xml; charset=utf-8
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="https://example.org">
  <soap:Header></soap:Header>
  <soap:Body>
    <m:GetStockPrice>
      <m:StockName>GOOG</m:StockName>
    </m:GetStockPrice>
  </soap:Body>
</soap:Envelope>
HTTP 200
```

Hurl can also be used to test the <b>performance</b> of HTTP endpoints

```hurl
GET https://example.org/api/v1/pets
HTTP 200
[Asserts]
duration < 1000  # Duration in ms
```

And check response bytes

```hurl
GET https://example.org/data.tar.gz
HTTP 200
[Asserts]
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
```

Finally, Hurl is easy to <b>integrate in CI/CD</b>, with text, JUnit, TAP and HTML reports

<picture>
    <source media="(prefers-color-scheme: light)" srcset="/docs/assets/img/home-waterfall-light.png">
    <source media="(prefers-color-scheme: dark)" srcset="/docs/assets/img/home-waterfall-dark.png">
    <img src="/docs/assets/img/home-waterfall-light.png" width="480" alt="HTML report"/>
</picture>

# Why Hurl?

<ul class="showcase-container">
    <li><b>Text Format:</b> for both devops and developers</li>
    <li><b>Fast CLI:</b> a command line for local dev and continuous integration</li>
    <li><b>Single Binary:</b> easy to install, with no runtime required</li>
</ul>

# Powered by curl

Hurl is a lightweight binary written in [Rust]. Under the hood, Hurl HTTP engine is
powered by [libcurl], one of the most powerful and reliable file transfer libraries.
With its text file format, Hurl adds syntactic sugar to run and test HTTP requests,
but it's still the [curl] that we love: __fast__, __efficient__ and __IPv6 / HTTP/3 ready__.

# Feedbacks

To support its development, [star Hurl on GitHub]!

[Feedback, suggestion, bugs or improvements] are welcome.

```hurl
POST https://hurl.dev/api/feedback
{
  "name": "John Doe",
  "feedback": "Hurl is awesome!"
}
HTTP 200
```

# Resources

[License]

[Blog]

[Tutorial]

[Documentation] (download [HTML], [PDF], [Markdown]) 

[GitHub]

# Table of Contents

* [Samples](#samples)
    * [Getting Data](#getting-data)
        * [HTTP Headers](#http-headers)
        * [Query Params](#query-params)
        * [Basic Authentication](#basic-authentication)
        * [Passing Data between Requests ](#passing-data-between-requests)
    * [Sending Data](#sending-data)
        * [Sending HTML Form Data](#sending-html-form-data)
        * [Sending Multipart Form Data](#sending-multipart-form-data)
        * [Posting a JSON Body](#posting-a-json-body)
        * [Templating a JSON Body](#templating-a-json-body)
        * [Templating a XML Body](#templating-a-xml-body)
        * [Using GraphQL Query](#using-graphql-query)
        * [Using Dynamic Datas](#using-dynamic-datas)
    * [Testing Response](#testing-response)
        * [Testing Status Code](#testing-status-code)
        * [Testing Response Headers](#testing-response-headers)
        * [Testing REST APIs](#testing-rest-apis)
        * [Testing HTML Response](#testing-html-response)
        * [Testing Set-Cookie Attributes](#testing-set-cookie-attributes)
        * [Testing Bytes Content](#testing-bytes-content)
        * [SSL Certificate](#ssl-certificate)
        * [Checking Full Body](#checking-full-body)
        * [Testing Redirections](#testing-redirections)
    * [Debug Tips](#debug-tips)
        * [Verbose Mode](#verbose-mode)
        * [Error Format](#error-format)
        * [Output Response Body](#output-response-body)
        * [Export curl Commands](#export-curl-commands)
        * [Using Proxy](#using-proxy)
    * [Reports](#reports)
        * [HTML Report](#html-report)
        * [JSON Report](#json-report)
        * [JUnit Report](#junit-report)
        * [TAP Report](#tap-report)
        * [JSON Output](#json-output)
    * [Others](#others)
        * [HTTP Version](#http-version)
        * [IP Address](#ip-address)
        * [Polling and Retry](#polling-and-retry)
        * [Delaying Requests](#delaying-requests)
        * [Skipping Requests](#skipping-requests)
        * [Testing Endpoint Performance](#testing-endpoint-performance)
        * [Using SOAP APIs](#using-soap-apis)
        * [Capturing and Using a CSRF Token](#capturing-and-using-a-csrf-token)
        * [Redacting Secrets](#redacting-secrets)
        * [Checking Byte Order Mark (BOM) in Response Body](#checking-byte-order-mark-bom-in-response-body)
        * [AWS Signature Version 4 Requests](#aws-signature-version-4-requests)
        * [Using curl Options](#using-curl-options)
* [Manual](#manual)
    * [Name](#name)
    * [Synopsis](#synopsis)
    * [Description](#description)
    * [Hurl File Format](#hurl-file-format)
        * [Capturing values](#capturing-values)
        * [Asserts](#asserts)
    * [Configuration](#configuration)
    * [All Options](#all-options)
        * [HTTP options](#http-options)
        * [Output options](#output-options)
        * [Run options](#run-options)
        * [Report options](#report-options)
        * [Other options](#other-options)
    * [Exit Codes](#exit-codes)
    * [WWW](#www)
    * [See Also](#see-also)
* [Installation](#installation)
    * [Binaries Installation](#binaries-installation)
        * [Linux](#linux)
            * [Debian / Ubuntu](#debian--ubuntu)
            * [Alpine](#alpine)
            * [Arch Linux / Manjaro](#arch-linux--manjaro)
            * [NixOS / Nix](#nixos--nix)
            * [Guix](#guix)
        * [macOS](#macos)
            * [Homebrew](#homebrew)
            * [MacPorts](#macports)
        * [FreeBSD](#freebsd)
        * [Windows](#windows)
            * [Zip File](#zip-file)
            * [Installer](#installer)
            * [Chocolatey](#chocolatey)
            * [Scoop](#scoop)
            * [Windows Package Manager](#windows-package-manager)
        * [Cargo](#cargo)
        * [conda-forge](#conda-forge)
        * [Docker](#docker)
        * [npm](#npm)
    * [Building From Sources](#building-from-sources)
        * [Build on Linux](#build-on-linux)
            * [Debian based distributions](#debian-based-distributions)
            * [Fedora based distributions](#fedora-based-distributions)
            * [Red Hat based distributions](#red-hat-based-distributions)
            * [Arch based distributions](#arch-based-distributions)
            * [Alpine based distributions](#alpine-based-distributions)
        * [Build on macOS](#build-on-macos)
        * [Build on Windows](#build-on-windows)

# Samples

To run a sample, edit a file with the sample content, and run Hurl:

```shell
$ vi sample.hurl

GET https://example.org

$ hurl sample.hurl
```

By default, Hurl behaves like [curl] and outputs the last HTTP response's [entry]. To have a test
oriented output, you can use [`--test` option]:

```shell
$ hurl --test sample.hurl
```

A particular response can be saved with [`[Options] section`](https://hurl.dev/docs/request.html#options):

```hurl
GET https://example.org/cats/123
[Options]
output: cat123.txt    # use - to output to stdout
HTTP 200

GET https://example.org/dogs/567
HTTP 200
```

Finally, Hurl can take files as input, or directories. In the latter case, Hurl will search files with `.hurl` extension recursively.

```shell
$ hurl --test integration/*.hurl
$ hurl --test .
```

You can check [Hurl tests suite] for more samples.

## Getting Data

A simple GET:

```hurl
GET https://example.org
```

Requests can be chained:

```hurl
GET https://example.org/a
GET https://example.org/b
HEAD https://example.org/c
GET https://example.org/c
```

[Doc](https://hurl.dev/docs/request.html#method)

### HTTP Headers

A simple GET with headers:

```hurl
GET https://example.org/news
User-Agent: Mozilla/5.0 
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
```

[Doc](https://hurl.dev/docs/request.html#headers)

### Query Params

```hurl
GET https://example.org/news
[Query]
order: newest
search: something to search
count: 100
```

Or:

```hurl
GET https://example.org/news?order=newest&search=something%20to%20search&count=100
```

> With `[Query]` section, params don't need to be URL escaped.

[Doc](https://hurl.dev/docs/request.html#query-parameters)

### Basic Authentication

```hurl
GET https://example.org/protected
[BasicAuth]
bob: secret
```

[Doc](https://hurl.dev/docs/request.html#basic-authentication)

This is equivalent to construct the request with a [Authorization] header:

```hurl
# Authorization header value can be computed with `echo -n 'bob:secret' | base64`
GET https://example.org/protected
Authorization: Basic Ym9iOnNlY3JldA== 
```

Basic authentication section allows per request authentication. If you want to add basic authentication to all the
requests of a Hurl file you could use [`-u/--user` option]:

```shell
$ hurl --user bob:secret login.hurl
```

[`--user`] option can also be set per request:

```hurl
GET https://example.org/login
[Options]
user: bob:secret
HTTP 200

GET https://example.org/login
[Options]
user: alice:secret
HTTP 200
```

### Passing Data between Requests 

[Captures] can be used to pass data from one request to another:

```hurl
POST https://sample.org/orders
HTTP 201
[Captures]
order_id: jsonpath "$.order.id"

GET https://sample.org/orders/{{order_id}}
HTTP 200
```

[Doc](https://hurl.dev/docs/capturing-response.html)

## Sending Data

### Sending HTML Form Data

```hurl
POST https://example.org/contact
[Form]
default: false
token: {{token}}
email: john.doe@rookie.org
number: 33611223344
```

[Doc](https://hurl.dev/docs/request.html#form-parameters)

### Sending Multipart Form Data

```hurl
POST https://example.org/upload
[Multipart]
field1: value1
field2: file,example.txt;
# One can specify the file content type:
field3: file,example.zip; application/zip
```

[Doc](https://hurl.dev/docs/request.html#multipart-form-data)

Multipart forms can also be sent with a [multiline string body]:

~~~hurl
POST https://example.org/upload
Content-Type: multipart/form-data; boundary="boundary"
```
--boundary
Content-Disposition: form-data; name="key1"

value1
--boundary
Content-Disposition: form-data; name="upload1"; filename="data.txt"
Content-Type: text/plain

Hello World!
--boundary
Content-Disposition: form-data; name="upload2"; filename="data.html"
Content-Type: text/html

<div>Hello <b>World</b>!</div>
--boundary--
```
~~~

In that case, files have to be inlined in the Hurl file.

[Doc](https://hurl.dev/docs/request.html#multiline-string-body)

### Posting a JSON Body

With an inline JSON:

```hurl
POST https://example.org/api/tests
{
    "id": "456",
    "evaluate": true
}
```

[Doc](https://hurl.dev/docs/request.html#json-body)

With a local file:

```hurl
POST https://example.org/api/tests
Content-Type: application/json
file,data.json;
```

[Doc](https://hurl.dev/docs/request.html#file-body)

### Templating a JSON Body

```hurl
PUT https://example.org/api/hits
Content-Type: application/json
{
    "key0": "{{a_string}}",
    "key1": {{a_bool}},
    "key2": {{a_null}},
    "key3": {{a_number}}
}
```

Variables can be initialized via command line:

```shell
$ hurl --variable a_string=apple \
       --variable a_bool=true \
       --variable a_null=null \
       --variable a_number=42 \
       test.hurl
```

Resulting in a PUT request with the following JSON body:

```
{
    "key0": "apple",
    "key1": true,
    "key2": null,
    "key3": 42
}
```

[Doc](https://hurl.dev/docs/templates.html)

### Templating a XML Body

Using templates with [XML body] is not currently supported in Hurl. You can use templates in
[XML multiline string body] with variables to send a variable XML body:

~~~hurl
POST https://example.org/echo/post/xml
```xml
<?xml version="1.0" encoding="utf-8"?>
<Request>
    <Login>{{login}}</Login>
    <Password>{{password}}</Password>
</Request>
```
~~~

[Doc](https://hurl.dev/docs/request.html#multiline-string-body)

### Using GraphQL Query

A simple GraphQL query:

~~~hurl
POST https://example.org/starwars/graphql
```graphql
{
  human(id: "1000") {
    name
    height(unit: FOOT)
  }
}
```
~~~

A GraphQL query with variables:

~~~hurl
POST https://example.org/starwars/graphql
```graphql
query Hero($episode: Episode, $withFriends: Boolean!) {
  hero(episode: $episode) {
    name
    friends @include(if: $withFriends) {
      name
    }
  }
}

variables {
  "episode": "JEDI",
  "withFriends": false
}
```
~~~

GraphQL queries can also use [Hurl templates].

[Doc](https://hurl.dev/docs/request.html#graphql-query)

### Using Dynamic Datas

[Functions] like `newUuid` and `newDate` can be used in templates to create dynamic datas:


A file that creates a dynamic email (i.e `0531f78f-7f87-44be-a7f2-969a1c4e6d97@test.com`):

```hurl
POST https://example.org/api/foo
{
  "name": "foo",
  "email": "{{newUuid}}@test.com"
}
```

A file that creates a dynamic query parameter (i.e `2024-12-02T10:35:44.461731Z`):

```hurl
GET https://example.org/api/foo
[Query]
date: {{newDate}}
HTTP 200
```

[Doc](https://hurl.dev/docs/templates.html#functions)

## Testing Response

Responses are optional, everything after `HTTP` is part of the response asserts.

```hurl
# A request with (almost) no check:
GET https://foo.com

# A status code check:
GET https://foo.com
HTTP 200

# A test on response body
GET https://foo.com
HTTP 200
[Asserts]
jsonpath "$.state" == "running"
```

### Testing Status Code

```hurl
GET https://example.org/order/435
HTTP 200
```

[Doc](https://hurl.dev/docs/asserting-response.html#version-status)

```hurl
GET https://example.org/order/435
# Testing status code is in a 200-300 range
HTTP *
[Asserts]
status >= 200
status < 300
```

[Doc](https://hurl.dev/docs/asserting-response.html#status-assert)

### Testing Response Headers

Use implicit response asserts to test header values:

```hurl
GET https://example.org/index.html
HTTP 200
Set-Cookie: theme=light
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
```

[Doc](https://hurl.dev/docs/asserting-response.html#headers)


Or use explicit response asserts with [predicates]:

```hurl
GET https://example.org
HTTP 302
[Asserts]
header "Location" contains "www.example.net"
```

[Doc](https://hurl.dev/docs/asserting-response.html#header-assert)

Implicit and explicit asserts can be combined:

```hurl
GET https://example.org/index.html
HTTP 200
Set-Cookie: theme=light
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
[Asserts]
header "Location" contains "www.example.net"
```

### Testing REST APIs

Asserting JSON body response (node values, collection count etc...) with [JSONPath]:

```hurl
GET https://example.org/order
screencapability: low
HTTP 200
[Asserts]
jsonpath "$.validated" == true
jsonpath "$.userInfo" isObject
jsonpath "$.userInfo.firstName" == "Franck"
jsonpath "$.userInfo.lastName" == "Herbert"
jsonpath "$.hasDevice" == false
jsonpath "$.links" count == 12
jsonpath "$.state" != null
jsonpath "$.order" matches "^order-\\d{8}$"
jsonpath "$.order" matches /^order-\d{8}$/  # Alternative syntax with regex literal
jsonpath "$.id" matches /(?i)[a-z]*/        # See syntax for flags <https://docs.rs/regex/latest/regex/#grouping-and-flags>
jsonpath "$.created" isIsoDate
```

[Doc](https://hurl.dev/docs/asserting-response.html#jsonpath-assert)

### Testing HTML Response

```hurl
GET https://example.org
HTTP 200
Content-Type: text/html; charset=UTF-8
[Asserts]
xpath "string(/html/head/title)" contains "Example" # Check title
xpath "count(//p)" == 2  # Check the number of p
xpath "//p" count == 2  # Similar assert for p
xpath "boolean(count(//h2))" == false  # Check there is no h2  
xpath "//h2" not exists  # Similar assert for h2
xpath "string(//div[1])" matches /Hello.*/
```

[Doc](https://hurl.dev/docs/asserting-response.html#xpath-assert)

### Testing Set-Cookie Attributes

```hurl
GET https://example.org/home
HTTP 200
[Asserts]
cookie "JSESSIONID" == "8400BAFE2F66443613DC38AE3D9D6239"
cookie "JSESSIONID[Value]" == "8400BAFE2F66443613DC38AE3D9D6239"
cookie "JSESSIONID[Expires]" contains "Wed, 13 Jan 2021"
cookie "JSESSIONID[Secure]" exists
cookie "JSESSIONID[HttpOnly]" exists
cookie "JSESSIONID[SameSite]" == "Lax"
```

[Doc](https://hurl.dev/docs/asserting-response.html#cookie-assert)

### Testing Bytes Content

Check the SHA-256 response body hash:

```hurl
GET https://example.org/data.tar.gz
HTTP 200
[Asserts]
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
```

[Doc](https://hurl.dev/docs/asserting-response.html#sha-256-assert)

### SSL Certificate

Check the properties of a SSL certificate:

```hurl
GET https://example.org
HTTP 200
[Asserts]
certificate "Subject" == "CN=example.org"
certificate "Issuer" == "C=US, O=Let's Encrypt, CN=R3"
certificate "Expire-Date" daysAfterNow > 15
certificate "Serial-Number" matches /[\da-f]+/
certificate "Subject-Alt-Name" contains "DNS:example.org"
certificate "Subject-Alt-Name" split "," count == 2
certificate "Value" startsWith "-----BEGIN CERTIFICATE-----"
```

[Doc](https://hurl.dev/docs/asserting-response.html#ssl-certificate-assert)

### Checking Full Body

Use implicit body to test an exact JSON body match:

```hurl
GET https://example.org/api/cats/123
HTTP 200
{
  "name" : "Purrsloud",
  "species" : "Cat",
  "favFoods" : ["wet food", "dry food", "<strong>any</strong> food"],
  "birthYear" : 2016,
  "photo" : "https://learnwebcode.github.io/json-example/images/cat-2.jpg"
}
```

[Doc](https://hurl.dev/docs/asserting-response.html#json-body)

Or an explicit assert file:

```hurl
GET https://example.org/index.html
HTTP 200
[Asserts]
body == file,cat.json;
```

[Doc](https://hurl.dev/docs/asserting-response.html#body-assert)

Implicit asserts supports XML body:

```hurl
GET https://example.org/api/catalog
HTTP 200
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications with XML.</description>
   </book>
</catalog>
```

[Doc](https://hurl.dev/docs/asserting-response.html#xml-body)

Plain text:

~~~hurl
GET https://example.org/models
HTTP 200
```
Year,Make,Model,Description,Price
1997,Ford,E350,"ac, abs, moon",3000.00
1999,Chevy,"Venture ""Extended Edition""","",4900.00
1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00
1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00
```
~~~

[Doc](https://hurl.dev/docs/asserting-response.html#multiline-string-body)


One line:

```hurl
POST https://example.org/helloworld
HTTP 200
`Hello world!`
```

[Doc](https://hurl.dev/docs/asserting-response.html#oneline-string-body)

File:

```hurl
GET https://example.org
HTTP 200
file,data.bin;
```

[Doc](https://hurl.dev/docs/asserting-response.html#file-body)

### Testing Redirections

By default, Hurl doesn't follow redirection so each step of a redirect must be run manually and can be analysed:

```hurl
GET https://example.org/step1
HTTP 301
[Asserts]
header "Location" == "https://example.org/step2"


GET https://example.org/step2
HTTP 301
[Asserts]
header "Location" == "https://example.org/step3"


GET https://example.org/step3
HTTP 200
```

[Doc](https://hurl.dev/docs/asserting-response.html)

Using [`--location`] and [`--location-trusted`] (either with command line option or per request), Hurl follows 
redirection and each step of the redirection can be checked.

```hurl
GET https://example.org/step1
[Options]
location: true
HTTP 200
[Asserts]
redirects count == 2
redirects nth 0 location == "https://example.org/step2"
redirects nth 1 location == "https://example.org/step3"
```

```hurl
GET https://example.org/step1
[Options]
location-trusted: true
HTTP 200
[Asserts]
redirects last location == "https://example.org/step2"
```

[Doc](https://hurl.dev/docs/asserting-response.html#redirects-assert)

## Debug Tips

### Verbose Mode

To get more info on a given request/response, use [`[Options]` section](https://hurl.dev/docs/request.html#options):

```hurl
GET https://example.org
HTTP 200

GET https://example.org/api/cats/123
[Options]
very-verbose: true
HTTP 200
```

`--verbose` and `--very-verbose` can be also used globally as command line options.

[Doc](https://hurl.dev/docs/manual.html#very-verbose)

### Error Format

```shell
$ hurl --test --error-format long *.hurl
```

[Doc](https://hurl.dev/docs/manual.html#error-format)

### Output Response Body

Use `--output` on a specific request to get the response body (`-` can be used as standard output):

```hurl
GET https://foo.com/failure
[Options]
# use - to output on standard output, foo.bin to save on disk 
output: -
HTTP 200

GET https://foo.com/success
HTTP 200
```

[Doc](https://hurl.dev/docs/manual.html#output)

### Export curl Commands

```shell
$ hurl ---curl /tmp/curl.txt *.hurl
```

[Doc](https://hurl.dev/docs/manual.html#curl)

### Using Proxy

Use `--proxy` on a specific request or globally as command line option:

```hurl
GET https://foo.com/a
HTTP 200

GET https://foo.com/b
[Options]
proxy: localhost:8888
HTTP 200

GET https://foo.com/c
HTTP 200
```

## Reports

### HTML Report

```shell
$ hurl --test --report-html build/report/ *.hurl
```

[Doc](https://hurl.dev/docs/running-tests.html#generating-report)

### JSON Report

```shell
$ hurl --test --report-json build/report/ *.hurl
```

[Doc](https://hurl.dev/docs/running-tests.html#generating-report)

### JUnit Report

```shell
$ hurl --test --report-junit build/report.xml *.hurl
```

[Doc](https://hurl.dev/docs/running-tests.html#generating-report)

### TAP Report

```shell
$ hurl --test --report-tap build/report.txt *.hurl
```

[Doc](https://hurl.dev/docs/running-tests.html#generating-report)

### JSON Output

A structured output of running Hurl files can be obtained with [`--json` option]. Each file will produce a JSON export of the run.


```shell
$ hurl --json *.hurl
```

## Others

### HTTP Version

Testing HTTP version (HTTP/1.0, HTTP/1.1, HTTP/2 or HTTP/3) can be done using implicit asserts:

```hurl
GET https://foo.com
HTTP/3 200

GET https://bar.com
HTTP/2 200
```

[Doc](https://hurl.dev/docs/asserting-response.html#version-status)

Or explicit:

```hurl
GET https://foo.com
HTTP 200
[Asserts]
version == "3"

GET https://bar.com
HTTP 200
[Asserts]
version == "2"
version toFloat > 1.1
```

[Doc](https://hurl.dev/docs/asserting-response.html#version-assert)

### IP Address

Testing the IP address of the response, as a string. This string may be IPv6 address:

```hurl
GET https://foo.com
HTTP 200
[Asserts]
ip == "2001:0db8:85a3:0000:0000:8a2e:0370:733"
ip startsWith "2001"
ip isIpv6
```

### Polling and Retry

Retry request on any errors (asserts, captures, status code, runtime etc...):

```hurl
# Create a new job
POST https://api.example.org/jobs
HTTP 201
[Captures]
job_id: jsonpath "$.id"
[Asserts]
jsonpath "$.state" == "RUNNING"


# Pull job status until it is completed
GET https://api.example.org/jobs/{{job_id}}
[Options]
retry: 10   # maximum number of retry, -1 for unlimited
retry-interval: 500ms
HTTP 200
[Asserts]
jsonpath "$.state" == "COMPLETED"
```

[Doc](https://hurl.dev/docs/entry.html#retry)

### Delaying Requests

Add delay for every request, or a particular request:

```hurl
# Delaying this request by 5 seconds (aka sleep)
GET https://example.org/turtle
[Options]
delay: 5s
HTTP 200

# No delay!
GET https://example.org/turtle
HTTP 200
```

[Doc](https://hurl.dev/docs/manual.html#delay)

### Skipping Requests

```hurl
# a, c, d are run, b is skipped
GET https://example.org/a

GET https://example.org/b
[Options]
skip: true

GET https://example.org/c

GET https://example.org/d
```

[Doc](https://hurl.dev/docs/manual.html#skip)

### Testing Endpoint Performance

```hurl
GET https://sample.org/helloworld
HTTP *
[Asserts]
duration < 1000   # Check that response time is less than one second
```

[Doc](https://hurl.dev/docs/asserting-response.html#duration-assert)

### Using SOAP APIs

```hurl
POST https://example.org/InStock
Content-Type: application/soap+xml; charset=utf-8
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="https://example.org">
  <soap:Header></soap:Header>
  <soap:Body>
    <m:GetStockPrice>
      <m:StockName>GOOG</m:StockName>
    </m:GetStockPrice>
  </soap:Body>
</soap:Envelope>
HTTP 200
```

[Doc](https://hurl.dev/docs/request.html#xml-body)

### Capturing and Using a CSRF Token

```hurl
GET https://example.org
HTTP 200
[Captures]
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"


POST https://example.org/login?user=toto&password=1234
X-CSRF-TOKEN: {{csrf_token}}
HTTP 302
```

[Doc](https://hurl.dev/docs/capturing-response.html#xpath-capture)

### Redacting Secrets

Using command-line for known values:

```shell
$ hurl --secret token=1234 file.hurl
```

```hurl
POST https://example.org
X-Token: {{token}}
{
  "name": "Alice",
  "value": 100
}
HTTP 200
```

[Doc](https://hurl.dev/docs/templates.html#secrets)

Using `redact` for dynamic values:

```hurl
# Get an authorization token:
GET https://example.org/token
HTTP 200
[Captures]
token: header "X-Token" redact

# Send an authorized request:
POST https://example.org
X-Token: {{token}}
{
  "name": "Alice",
  "value": 100
}
HTTP 200
```

[Doc](https://hurl.dev/docs/capturing-response.html#redacting-secrets)

### Checking Byte Order Mark (BOM) in Response Body

```hurl
GET https://example.org/data.bin
HTTP 200
[Asserts]
bytes startsWith hex,efbbbf;
```

[Doc](https://hurl.dev/docs/asserting-response.html#bytes-assert)

### AWS Signature Version 4 Requests

Generate signed API requests with [AWS Signature Version 4], as used by several cloud providers.

```hurl
POST https://sts.eu-central-1.amazonaws.com/
[Options]
aws-sigv4: aws:amz:eu-central-1:sts
[Form]
Action: GetCallerIdentity
Version: 2011-06-15
```

The Access Key is given per [`--user`], either with command line option or within the [`[Options]`](https://hurl.dev/docs/request.html#options) section:

```hurl
POST https://sts.eu-central-1.amazonaws.com/
[Options]
aws-sigv4: aws:amz:eu-central-1:sts
user: bob=secret
[Form]
Action: GetCallerIdentity
Version: 2011-06-15
```

[Doc](https://hurl.dev/docs/manual.html#aws-sigv4)

### Using curl Options

curl options (for instance [`--resolve`] or [`--connect-to`]) can be used as CLI argument. In this case, they're applicable
to each request of an Hurl file.

```shell
$ hurl --resolve foo.com:8000:127.0.0.1 foo.hurl
```

Use  [`[Options]` section](https://hurl.dev/docs/request.html#options) to configure a specific request:

```hurl
GET http://bar.com
HTTP 200


GET http://foo.com:8000/resolve
[Options]
resolve: foo.com:8000:127.0.0.1
HTTP 200
`Hello World!`
```

[Doc](https://hurl.dev/docs/request.html#options)


# Manual

## Name

hurl - run and test HTTP requests.

## Synopsis

**hurl** [OPTIONS] [FILES...]

**hurl** --test [OPTIONS] [FILES...]

## Description

**Hurl** is a command line tool that runs HTTP requests defined in a simple plain text format.

It can chain requests, capture values and evaluate queries on headers and body response. Hurl is very versatile, it can be used for fetching data and testing HTTP sessions: HTML content, REST / SOAP / GraphQL APIs, or any other XML / JSON based APIs.

```shell
$ hurl session.hurl
```

If no input files are specified, input is read from stdin.

```shell
$ echo GET http://httpbin.org/get | hurl
    {
      "args": {},
      "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip",
        "Content-Length": "0",
        "Host": "httpbin.org",
        "User-Agent": "hurl/0.99.10",
        "X-Amzn-Trace-Id": "Root=1-5eedf4c7-520814d64e2f9249ea44e0"
      },
      "origin": "1.2.3.4",
      "url": "http://httpbin.org/get"
    }
```

Hurl can take files as input, or directories. In the latter case, Hurl will search files with `.hurl` extension recursively.

Output goes to stdout by default. To have output go to a file, use the [`-o, --output`](#output) option:

```shell
$ hurl -o output input.hurl
```

By default, Hurl executes all HTTP requests and outputs the response body of the last HTTP call.

To have a test oriented output, you can use [`--test`](#test) option:

```shell
$ hurl --test *.hurl
```


## Hurl File Format

The Hurl file format is fully documented in [https://hurl.dev/docs/hurl-file.html](https://hurl.dev/docs/hurl-file.html)

It consists of one or several HTTP requests

```hurl
GET http://example.org/endpoint1
GET http://example.org/endpoint2
```


### Capturing values

A value from an HTTP response can be-reused for successive HTTP requests.

A typical example occurs with CSRF tokens.

```hurl
GET https://example.org
HTTP 200
# Capture the CSRF token value from html body.
[Captures]
csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"

# Do the login !
POST https://example.org/login?user=toto&password=1234
X-CSRF-TOKEN: {{csrf_token}}
```

More information on captures can be found here [https://hurl.dev/docs/capturing-response.html](https://hurl.dev/docs/capturing-response.html)

### Asserts

The HTTP response defined in the Hurl file are used to make asserts. Responses are optional.

At the minimum, response includes assert on the HTTP status code.

```hurl
GET http://example.org
HTTP 301
```

It can also include asserts on the response headers

```hurl
GET http://example.org
HTTP 301
Location: http://www.example.org
```

Explicit asserts can be included by combining a query and a predicate

```hurl
GET http://example.org
HTTP 301
[Asserts]
xpath "string(//title)" == "301 Moved"
```

With the addition of asserts, Hurl can be used as a testing tool to run scenarios.

More information on asserts can be found here [https://hurl.dev/docs/asserting-response.html](https://hurl.dev/docs/asserting-response.html)

## Configuration

Options that exist in curl have exactly the same semantics.

Options specified on the command line are defined for every Hurl file's entry, except if they are tagged as cli-only 
(can not be defined in the Hurl request `[Options]` entry)

For instance:

```shell
$ hurl --location foo.hurl
```

will follow redirection for each entry in `foo.hurl`. You can also define an option only for a particular entry with an `[Options]` section. For instance, this Hurl file:

```hurl
GET https://example.org
HTTP 301

GET https://example.org
[Options]
location: true
HTTP 200
```

will follow a redirection only for the second entry.

Hurl looks also for a configuration file at the following places `$XDG_CONFIG_HOME/hurl/config` if `$XDG_CONFIG_HOME` exists,
or `$HOME/.config/hurl/config`. The configuration file is a list of options added to each Hurl run.

```shell
$ cat ~/.config/hurl/config
# Hurl config file
--header x-identifier:quux
--verbose
--delay=1s
--fail-with-body
```

Most of the options can also be defined with environment variables (like `HURL_INSECURE` for [`--insecure`](#insecure)). So, in order
to configure Hurl, there are four sources from the lowest priority (most easily overridden) to highest (overrides all others):

- Configuration file (ex: `~/.config/hurl/config`)
- Environment variables (ex: `export HURL_INSECURE=true`)
- Command-line options (ex: `hurl --insecure`)
- Options section options (ex: `insecure: true` in file)

## All Options

### HTTP options

| Option                                                                                                            | Description                                                                                                                                                                                                                                                                                                                                                                                                                   |
|-------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#aws-sigv4" id="aws-sigv4"><code>--aws-sigv4 &lt;PROVIDER1[:PROVIDER2[:REGION[:SERVICE]]]&gt;</code></a> | Generate an `Authorization` header with an AWS SigV4 signature.<br><br>Use [`-u, --user`](#user) to specify Access Key Id (username) and Secret Key (password).<br><br>To use temporary session credentials (e.g. for an AWS IAM Role), add the `X-Amz-Security-Token` header containing the session token.<br>                                                                                                               |
| <a href="#cacert" id="cacert"><code>--cacert &lt;FILE&gt;</code></a>                                              | Specifies the certificate file for peer verification. The file may contain multiple CA certificates and must be in PEM format.<br>Normally Hurl is built to use a default file for this, so this option is typically used to alter that default file.<br>                                                                                                                                                                     |
| <a href="#cert" id="cert"><code>-E, --cert &lt;CERTIFICATE[:PASSWORD]&gt;</code></a>                              | Client certificate file and password.<br><br>See also [`--key`](#key).<br>                                                                                                                                                                                                                                                                                                                                                    |
| <a href="#compressed" id="compressed"><code>--compressed</code></a>                                               | Request a compressed response using one of the algorithms br, gzip, deflate and automatically decompress the content.<br><br>Environment variables: HURL_COMPRESSED<br>                                                                                                                                                                                                                                                       |
| <a href="#connect-timeout" id="connect-timeout"><code>--connect-timeout &lt;SECONDS&gt;</code></a>                | Maximum time in seconds that you allow Hurl's connection to take.<br><br>You can specify time units in the connect timeout expression. Set Hurl to use a connect timeout of 20 seconds with `--connect-timeout 20s` or set it to 35,000 milliseconds with `--connect-timeout 35000ms`. No spaces allowed.<br><br>See also [`-m, --max-time`](#max-time).<br><br>Environment variables: HURL_CONNECT_TIMEOUT<br>               |
| <a href="#connect-to" id="connect-to"><code>--connect-to &lt;HOST1:PORT1:HOST2:PORT2&gt;</code></a>               | For a request to the given HOST1:PORT1 pair, connect to HOST2:PORT2 instead. This option can be used several times in a command line.<br><br>See also [`--resolve`](#resolve).<br>                                                                                                                                                                                                                                            |
| <a href="#digest" id="digest"><code>--digest</code></a>                                                           | Tell Hurl to use HTTP Digest authentication<br>                                                                                                                                                                                                                                                                                                                                                                               |
| <a href="#header" id="header"><code>-H, --header &lt;NAME:VALUE&gt;</code></a>                                    | Add an extra header to include in information sent. Can be used several times in a command.<br><br>Do not add newlines or carriage returns.<br><br>Environment variables: HURL_HEADER='name1:value1&#124;name2:value2' (headers are separated by &#124;)<br>                                                                                                                                                                  |
| <a href="#http10" id="http10"><code>-0, --http1.0</code></a>                                                      | Tells Hurl to use HTTP version 1.0 instead of using its internally preferred HTTP version.<br><br>Environment variables: HURL_HTTP10<br>                                                                                                                                                                                                                                                                                      |
| <a href="#http11" id="http11"><code>--http1.1</code></a>                                                          | Tells Hurl to use HTTP version 1.1.<br><br>Environment variables: HURL_HTTP11<br>                                                                                                                                                                                                                                                                                                                                             |
| <a href="#http2" id="http2"><code>--http2</code></a>                                                              | Tells Hurl to use HTTP version 2.<br>For HTTPS, this means Hurl negotiates HTTP/2 in the TLS handshake. Hurl does this by default.<br>For HTTP, this means Hurl attempts to upgrade the request to HTTP/2 using the Upgrade: request header.<br><br>Environment variables: HURL_HTTP2<br>                                                                                                                                     |
| <a href="#http2-prior-knowledge" id="http2-prior-knowledge"><code>--http2-prior-knowledge</code></a>              | Tells Hurl to issue a non-TLS HTTP request using HTTP/2 directly without HTTP/1.1 Upgrade. It requires prior knowledge that the server supports HTTP/2 straight away. HTTPS requests still do HTTP/2 the standard way with negotiated protocol versions in the TLS handshake.<br><br>Environment variables: HURL_HTTP2_PRIOR_KNOWLEDGE<br>                                                                                    |
| <a href="#http3" id="http3"><code>--http3</code></a>                                                              | Tells Hurl to try HTTP version 3 to the host in the URL, but fallback to earlier HTTP versions if the HTTP/3 connection establishment fails. HTTP/3 is only available for HTTPS and not for HTTP URLs.<br><br>Environment variables: HURL_HTTP3<br>                                                                                                                                                                           |
| <a href="#insecure" id="insecure"><code>-k, --insecure</code></a>                                                 | This option explicitly allows Hurl to perform "insecure" SSL connections and transfers.<br><br>Environment variables: HURL_INSECURE<br>                                                                                                                                                                                                                                                                                       |
| <a href="#ipv4" id="ipv4"><code>-4, --ipv4</code></a>                                                             | This option tells Hurl to use IPv4 addresses only when resolving host names, and not for example try IPv6.<br><br>Environment variables: HURL_IPV4<br>                                                                                                                                                                                                                                                                        |
| <a href="#ipv6" id="ipv6"><code>-6, --ipv6</code></a>                                                             | This option tells Hurl to use IPv6 addresses only when resolving host names, and not for example try IPv4.<br><br>Environment variables: HURL_IPV6<br>                                                                                                                                                                                                                                                                        |
| <a href="#key" id="key"><code>--key &lt;KEY&gt;</code></a>                                                        | Private key file name.<br>                                                                                                                                                                                                                                                                                                                                                                                                    |
| <a href="#limit-rate" id="limit-rate"><code>--limit-rate &lt;SPEED&gt;</code></a>                                 | Specify the maximum transfer rate you want Hurl to use, for both downloads and uploads. This feature is useful if you have a limited pipe and you would like your transfer not to use your entire bandwidth. To make it slower than it otherwise would be.<br>The given speed is measured in bytes/second.<br><br>Environment variables: HURL_LIMIT_RATE<br>                                                                  |
| <a href="#location" id="location"><code>-L, --location</code></a>                                                 | Follow redirect. To limit the amount of redirects to follow use the [`--max-redirs`](#max-redirs) option<br><br>Environment variables: HURL_LOCATION<br>                                                                                                                                                                                                                                                                      |
| <a href="#location-trusted" id="location-trusted"><code>--location-trusted</code></a>                             | Like [`-L, --location`](#location), but allows sending the name + password to all hosts that the site may redirect to.<br>This may or may not introduce a security breach if the site redirects you to a site to which you send your authentication info (which is plaintext in the case of HTTP Basic authentication).<br><br>Environment variables: HURL_LOCATION_TRUSTED<br>                                               |
| <a href="#max-filesize" id="max-filesize"><code>--max-filesize &lt;BYTES&gt;</code></a>                           | Specify the maximum size in bytes of a file to download. If the file requested is larger than this value, the transfer does not start.<br><br>Environment variables: HURL_MAX_FILESIZE<br><br>This is a cli-only option.<br>                                                                                                                                                                                                  |
| <a href="#max-redirs" id="max-redirs"><code>--max-redirs &lt;NUM&gt;</code></a>                                   | Set maximum number of redirection-followings allowed<br><br>By default, the limit is set to 50 redirections. Set this option to -1 to make it unlimited.<br><br>Environment variables: HURL_MAX_REDIRS<br>                                                                                                                                                                                                                    |
| <a href="#max-time" id="max-time"><code>-m, --max-time &lt;SECONDS&gt;</code></a>                                 | Maximum time in seconds that you allow a request/response to take. This is the standard timeout.<br><br>You can specify time units in the maximum time expression. Set Hurl to use a maximum time of 20 seconds with `--max-time 20s` or set it to 35,000 milliseconds with `--max-time 35000ms`. No spaces allowed.<br><br>See also [`--connect-timeout`](#connect-timeout).<br><br>Environment variables: HURL_MAX_TIME<br> |
| <a href="#negotiate" id="negotiate"><code>--negotiate</code></a>                                                  | Tell Hurl to use Negotiate (SPNEGO) authentication.<br>                                                                                                                                                                                                                                                                                                                                                                       |
| <a href="#no-cookie-store" id="no-cookie-store"><code>--no-cookie-store</code></a>                                | Do not use cookie storage for requests/responses in a file. By default, requests in the same Hurl file share cookie storage, this option deactivates cookie engine.<br><br>Environment variables: HURL_NO_COOKIE_STORE<br><br>This is a cli-only option.<br>                                                                                                                                                                  |
| <a href="#no-header" id="no-header"><code>--no-header &lt;NAME&gt;</code></a>                                     | Remove a header from information sent. Can be used several times in a command.<br><br>Environment variables: HURL_NO_HEADER='name1&#124;name2' (names are separated by &#124;)<br>                                                                                                                                                                                                                                            |
| <a href="#no-proxy" id="no-proxy"><code>--no-proxy &lt;HOST(S)&gt;</code></a>                                     | Comma-separated list of hosts which do not use a proxy.<br><br>Environment variables: no_proxy<br>                                                                                                                                                                                                                                                                                                                            |
| <a href="#ntlm" id="ntlm"><code>--ntlm</code></a>                                                                 | Tell Hurl to use NTLM authentication<br>                                                                                                                                                                                                                                                                                                                                                                                      |
| <a href="#path-as-is" id="path-as-is"><code>--path-as-is</code></a>                                               | Tell Hurl to not handle sequences of /../ or /./ in the given URL path. Normally Hurl will squash or merge them according to standards but with this option set you tell it not to do that.<br>                                                                                                                                                                                                                               |
| <a href="#pinnedpubkey" id="pinnedpubkey"><code>--pinnedpubkey &lt;HASHES&gt;</code></a>                          | When negotiating a TLS or SSL connection, the server sends a certificate indicating its identity. A public key is extracted from this certificate and if it does not exactly match the public key provided to this option, Hurl aborts the connection before sending or receiving any data.<br>                                                                                                                               |
| <a href="#proxy" id="proxy"><code>-x, --proxy &lt;[PROTOCOL://]HOST[:PORT]&gt;</code></a>                         | Use the specified proxy.<br><br>Environment variables: http_proxy https_proxy all_proxy<br>                                                                                                                                                                                                                                                                                                                                   |
| <a href="#proxy-header" id="proxy-header"><code>--proxy-header &lt;HEADER&gt;</code></a>                          | Extra header to include in the request when sending to a proxy. These headers are only applied when a proxy is involved; if Hurl connects directly to the target server, they are ignored.<br><br>Environment variables: HURL_PROXY_HEADER='name1:value1&#124;name2:value2' (headers are separated by &#124;)<br><br>This is a cli-only option.<br>                                                                           |
| <a href="#resolve" id="resolve"><code>--resolve &lt;HOST:PORT:ADDR&gt;</code></a>                                 | Provide a custom address for a specific host and port pair. Using this, you can make the Hurl requests(s) use a specified address and prevent the otherwise normally resolved address to be used. Consider it a sort of /etc/hosts alternative provided on the command line.<br>                                                                                                                                              |
| <a href="#ssl-no-revoke" id="ssl-no-revoke"><code>--ssl-no-revoke</code></a>                                      | (Windows) This option tells Hurl to disable certificate revocation checks. WARNING: this option loosens the SSL security, and by using this flag you ask for exactly that.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                              |
| <a href="#tls-max" id="tls-max"><code>--tls-max &lt;VERSION&gt;</code></a>                                        | Set the maximum allowed TLS version. If the connection is done without TLS, this option has no effect. This includes QUIC-using (HTTP/3) transfers.<br><br>default   Use up to the recommended TLS version.<br>1.0       Use up to TLSv1.0.<br>1.1       Use up to TLSv1.1.<br>1.2       Use up to TLSv1.2.<br>1.3       Use up to TLSv1.3.<br><br>Environment variables: HURL_TLS_MAX<br>                                    |
| <a href="#unix-socket" id="unix-socket"><code>--unix-socket &lt;PATH&gt;</code></a>                               | (HTTP) Connect through this Unix domain socket, instead of using the network.<br>                                                                                                                                                                                                                                                                                                                                             |
| <a href="#user" id="user"><code>-u, --user &lt;USER:PASSWORD&gt;</code></a>                                       | Add basic Authentication header to each request.<br><br>Environment variables: HURL_USER<br>                                                                                                                                                                                                                                                                                                                                  |
| <a href="#user-agent" id="user-agent"><code>-A, --user-agent &lt;NAME&gt;</code></a>                              | Specify the User-Agent string to send to the HTTP server.<br><br>Environment variables: HURL_USER_AGENT<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                 |

### Output options

| Option                                                                                   | Description                                                                                                                                                                                                                                                                                                                                                                                                                           |
|------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#color" id="color"><code>--color</code></a>                                     | Colorize standard output and standard error.<br><br>By default, Hurl outputs a prettified and colorized response. When redirected through pipes, standard streams are not colorized and color can be forced with this option.<br><br>Environment variables: HURL_COLOR<br><br>This is a cli-only option.<br>                                                                                                                          |
| <a href="#curl" id="curl"><code>--curl &lt;FILE&gt;</code></a>                           | Export each request to a list of curl commands.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                                                 |
| <a href="#error-format" id="error-format"><code>--error-format &lt;FORMAT&gt;</code></a> | Control the format of error message (short by default or long).  When using long, the response body is logged when there are errors.<br><br>Environment variables: HURL_ERROR_FORMAT<br><br>This is a cli-only option.<br>                                                                                                                                                                                                            |
| <a href="#fail-with-body" id="fail-with-body"><code>--fail-with-body</code></a>          | Output body response on standard output if there are any errors. By default, Hurl outputs the last body response on standard output only when a run is successful.<br><br>Environment variables: HURL_FAIL_WITH_BODY<br>                                                                                                                                                                                                              |
| <a href="#include" id="include"><code>-i, --include</code></a>                           | Include the HTTP headers in the output<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                                                          |
| <a href="#json" id="json"><code>--json</code></a>                                        | Output each Hurl file result to JSON. The format is very closed to HAR format.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                  |
| <a href="#no-color" id="no-color"><code>--no-color</code></a>                            | Do not colorize standard output nor standard error.<br><br>Environment variables: HURL_NO_COLOR NO_COLOR<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                        |
| <a href="#no-output" id="no-output"><code>--no-output</code></a>                         | Suppress output. By default, Hurl outputs the body of the last response.<br><br>Environment variables: HURL_NO_OUTPUT<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                           |
| <a href="#no-pretty" id="no-pretty"><code>--no-pretty</code></a>                         | Do not prettify response output for supported content type (JSON only for the moment). By default, output is prettified if<br>standard output is a terminal.<br><br>Environment variables: HURL_NO_PRETTY<br><br>This is a cli-only option.<br>                                                                                                                                                                                       |
| <a href="#output" id="output"><code>-o, --output &lt;FILE&gt;</code></a>                 | Write output to FILE instead of stdout. Use '-' for stdout in [Options] sections.<br>                                                                                                                                                                                                                                                                                                                                                 |
| <a href="#pretty" id="pretty"><code>--pretty</code></a>                                  | Prettify response output for supported content type (JSON only for the moment). By default, JSON response is prettified if standard output is a terminal, and colorized, see[`--no-color`](#no-color) to format without color.<br><br>Environment variables: HURL_PRETTY<br><br>This is a cli-only option.<br>                                                                                                                        |
| <a href="#progress-bar" id="progress-bar"><code>--progress-bar</code></a>                | Display a progress bar in test mode. The progress bar is displayed only in interactive TTYs. This option forces the progress bar to be displayed even in non-interactive TTYs.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                  |
| <a href="#verbose" id="verbose"><code>-v, --verbose</code></a>                           | Turn on verbose output on standard error stream.<br>Useful for debugging.<br><br>A line starting with '>' means data sent by Hurl.<br>A line staring with '<' means data received by Hurl.<br>A line starting with '*' means additional info provided by Hurl.<br><br>If you only want HTTP headers in the output, [`-i, --include`](#include) might be the option you're looking for.<br><br>Environment variables: HURL_VERBOSE<br> |
| <a href="#verbosity" id="verbosity"><code>--verbosity &lt;LEVEL&gt;</code></a>           | Set the verbosity level for debug logs on standard error stream (brief, verbose or debug)<br><br>If you only want HTTP headers in the output, [`-i, --include`](#include) might be the option you're looking for.<br>[`-v, --verbose`](#verbose) is an alias for `--verbosity verbose`<br>[`--very-verbose`](#very-verbose) is an alias for `--verbosity debug`<br><br>Environment variables: HURL_VERBOSITY<br>                      |
| <a href="#very-verbose" id="very-verbose"><code>--very-verbose</code></a>                | Turn on more verbose output on standard error stream.<br><br>In contrast to  [`--verbose`](#verbose) option, this option outputs the full HTTP body request and response on standard error. In addition, lines starting with '**' are libcurl debug logs.<br><br>Environment variables: HURL_VERY_VERBOSE<br>                                                                                                                         |

### Run options

| Option                                                                                               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#continue-on-error" id="continue-on-error"><code>--continue-on-error</code></a>             | Continue executing requests to the end of the Hurl file even when an assert error occurs. By default, Hurl exits after an assert error in the HTTP response.<br><br>Note that this option does not affect the behavior with multiple input Hurl files.<br><br>All the input files are executed independently. The result of one file does not affect the execution of the other Hurl files.<br><br>Environment variables: HURL_CONTINUE_ON_ERROR<br><br>This is a cli-only option.<br> |
| <a href="#delay" id="delay"><code>--delay &lt;MILLISECONDS&gt;</code></a>                            | Sets delay before each request (aka sleep). The delay is not applied to requests that have been retried because of [`--retry`](#retry). See [`--retry-interval`](#retry-interval) to space retried requests.<br><br>You can specify time units in the delay expression. Set Hurl to use a delay of 2 seconds with `--delay 2s` or set it to 500 milliseconds with `--delay 500ms`. Supported time units: ms, s, m, h. No spaces allowed.<br><br>Environment variables: HURL_DELAY<br>  |
| <a href="#from-entry" id="from-entry"><code>--from-entry &lt;ENTRY_NUMBER&gt;</code></a>             | Execute Hurl file from ENTRY_NUMBER (starting at 1).<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                                                                                             |
| <a href="#jobs" id="jobs"><code>--jobs &lt;NUM&gt;</code></a>                                        | Maximum number of parallel jobs in parallel mode. Default value corresponds (in most cases) to the current amount of CPUs. Set to 1 to disable parallel execution of files.<br><br>See also [`--parallel`](#parallel).<br><br>Environment variables: HURL_JOBS<br><br>This is a cli-only option.<br>                                                                                                                                                                                   |
| <a href="#no-assert" id="no-assert"><code>--no-assert</code></a>                                     | Ignore all asserts defined in the Hurl file.<br><br>Environment variables: HURL_NO_ASSERT<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                                                        |
| <a href="#no-jsonpath-coercion" id="no-jsonpath-coercion"><code>--no-jsonpath-coercion</code></a>    | Disable JSONPath result coercion.<br><br>By default, when JSONPath coercion is enabled, empty JSONPath results are returned as no value and single JSONPath results are returned as a scalar value. With this option, JSONPath results are always returned as arrays.<br><br>Environment variables: HURL_NO_JSONPATH_COERCION<br>                                                                                                                                                      |
| <a href="#parallel" id="parallel"><code>--parallel</code></a>                                        | Run files in parallel.<br><br>Each Hurl file is executed in its own worker thread, without sharing anything with the other workers. The default run mode is sequential. Parallel execution is by default in [`--test`](#test) mode.<br><br>See also [`--jobs`](#jobs).<br><br>This is a cli-only option.<br>                                                                                                                                                                           |
| <a href="#repeat" id="repeat"><code>--repeat &lt;NUM&gt;</code></a>                                  | Repeat the input files sequence NUM times, -1 for infinite loop. Given a.hurl, b.hurl, c.hurl as input, repeat two<br>times will run a.hurl, b.hurl, c.hurl, a.hurl, b.hurl, c.hurl.<br>                                                                                                                                                                                                                                                                                               |
| <a href="#retry" id="retry"><code>--retry &lt;NUM&gt;</code></a>                                     | Maximum number of retries, 0 for no retries, -1 for unlimited retries. Retry happens if any error occurs (asserts, captures, runtimes etc...).<br><br>Environment variables: HURL_RETRY<br>                                                                                                                                                                                                                                                                                            |
| <a href="#retry-interval" id="retry-interval"><code>--retry-interval &lt;MILLISECONDS&gt;</code></a> | Duration in milliseconds between each retry. Default is 1000 ms.<br><br>You can specify time units in the retry interval expression. Set Hurl to use a retry interval of 2 seconds with `--retry-interval 2s` or set it to 500 milliseconds with `--retry-interval 500ms`. No spaces allowed.<br><br>Environment variables: HURL_RETRY_INTERVAL<br>                                                                                                                                    |
| <a href="#secret" id="secret"><code>--secret &lt;NAME=VALUE&gt;</code></a>                           | Define secret value to be redacted from logs and report. When defined, secrets can be used as variable everywhere variables are used.<br><br>Environment variables: HURL_SECRET_name<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                             |
| <a href="#secrets-file" id="secrets-file"><code>--secrets-file &lt;FILE&gt;</code></a>               | Define a secrets file in which you define your secrets<br><br>Each secret is defined as name=value exactly as with [`--secret`](#secret) option.<br><br>Note that defining a secret twice produces an error.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                     |
| <a href="#test" id="test"><code>--test</code></a>                                                    | Activate test mode: with this, the HTTP response is not outputted anymore, progress is reported for each Hurl file tested, and a text summary is displayed when all files have been run.<br><br>In test mode, files are executed in parallel. To run test in a sequential way use `--jobs 1`.<br><br>See also [`--jobs`](#jobs).<br><br>Environment variables: HURL_TEST<br><br>This is a cli-only option.<br>                                                                         |
| <a href="#to-entry" id="to-entry"><code>--to-entry &lt;ENTRY_NUMBER&gt;</code></a>                   | Execute Hurl file to ENTRY_NUMBER (starting at 1).<br>Ignore the remaining of the file. It is useful for debugging a session.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                    |
| <a href="#variable" id="variable"><code>--variable &lt;NAME=VALUE&gt;</code></a>                     | Define variable (name/value) to be used in Hurl templates.<br><br>Environment variables: HURL_VARIABLE_name<br>                                                                                                                                                                                                                                                                                                                                                                        |
| <a href="#variables-file" id="variables-file"><code>--variables-file &lt;FILE&gt;</code></a>         | Set properties file in which your define your variables.<br><br>Each variable is defined as name=value exactly as with [`--variable`](#variable) option.<br><br>Note that defining a variable twice produces an error.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                           |

### Report options

| Option                                                                                 | Description                                                                                                                                                |
|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#report-html" id="report-html"><code>--report-html &lt;DIR&gt;</code></a>     | Generate HTML report in DIR.<br><br>If the HTML report already exists, it will be updated with the new test results.<br><br>This is a cli-only option.<br> |
| <a href="#report-json" id="report-json"><code>--report-json &lt;DIR&gt;</code></a>     | Generate JSON report in DIR.<br><br>If the JSON report already exists, it will be updated with the new test results.<br><br>This is a cli-only option.<br> |
| <a href="#report-junit" id="report-junit"><code>--report-junit &lt;FILE&gt;</code></a> | Generate JUnit File.<br><br>If the FILE report already exists, it will be updated with the new test results.<br><br>This is a cli-only option.<br>         |
| <a href="#report-tap" id="report-tap"><code>--report-tap &lt;FILE&gt;</code></a>       | Generate TAP report.<br><br>If the FILE report already exists, it will be updated with the new test results.<br><br>This is a cli-only option.<br>         |

### Other options

| Option                                                                               | Description                                                                                                                                                                                                                                                                                                                                                         |
|--------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#cookie" id="cookie"><code>-b, --cookie &lt;FILE&gt;</code></a>             | Read cookies from FILE (using the Netscape cookie file format).<br><br>Combined with [`-c, --cookie-jar`](#cookie-jar), you can simulate a cookie storage between successive Hurl runs.<br><br>This is a cli-only option.<br>                                                                                                                                       |
| <a href="#cookie-jar" id="cookie-jar"><code>-c, --cookie-jar &lt;FILE&gt;</code></a> | Write cookies to FILE after running the session.<br>The file will be written using the Netscape cookie file format.<br><br>Combined with [`-b, --cookie`](#cookie), you can simulate a cookie storage between successive Hurl runs.<br><br>This is a cli-only option.<br>                                                                                           |
| <a href="#file-root" id="file-root"><code>--file-root &lt;DIR&gt;</code></a>         | Set root directory to import files in Hurl. This is used for files in multipart form data, request body and response output.<br>When it is not explicitly defined, files are relative to the Hurl file's directory.<br><br>This is a cli-only option.<br>                                                                                                           |
| <a href="#glob" id="glob"><code>--glob &lt;GLOB&gt;</code></a>                       | Specify input files that match the given glob pattern.<br><br>Multiple glob flags may be used. This flag supports common Unix glob patterns like *, ? and [].<br>However, to avoid your shell accidentally expanding glob patterns before Hurl handles them, you must use single quotes or double quotes around each pattern.<br><br>This is a cli-only option.<br> |
| <a href="#netrc" id="netrc"><code>-n, --netrc</code></a>                             | Scan the .netrc file in the user's home directory for the username and password.<br><br>See also [`--netrc-file`](#netrc-file) and [`--netrc-optional`](#netrc-optional).<br>                                                                                                                                                                                       |
| <a href="#netrc-file" id="netrc-file"><code>--netrc-file &lt;FILE&gt;</code></a>     | Like [`--netrc`](#netrc), but provide the path to the netrc file.<br><br>See also [`--netrc-optional`](#netrc-optional).<br>                                                                                                                                                                                                                                        |
| <a href="#netrc-optional" id="netrc-optional"><code>--netrc-optional</code></a>      | Similar to [`--netrc`](#netrc), but make the .netrc usage optional.<br><br>See also [`--netrc-file`](#netrc-file).<br>                                                                                                                                                                                                                                              |
| <a href="#help" id="help"><code>-h, --help</code></a>                                | Usage help. This lists all current command line options with a short description.<br>                                                                                                                                                                                                                                                                               |
| <a href="#version" id="version"><code>-V, --version</code></a>                       | Prints version information<br>                                                                                                                                                                                                                                                                                                                                      |

## Exit Codes

| Value | Description                                             |
|-------|---------------------------------------------------------|
| `0`   | Success.<br>                                            |
| `1`   | Failed to parse command-line options.<br>               |
| `2`   | Input file parsing error.<br>                           |
| `3`   | Runtime error (such as failure to connect to host).<br> |
| `4`   | Assert error.<br>                                       |

## WWW

[https://hurl.dev](https://hurl.dev)


## See Also

curl(1)  hurlfmt(1)

# Installation

## Binaries Installation

### Linux

Precompiled binary (depending on libc >=2.35) is available at [Hurl latest GitHub release]:

```shell
$ INSTALL_DIR=/tmp
$ VERSION=8.0.1
$ curl --silent --location https://github.com/Orange-OpenSource/hurl/releases/download/$VERSION/hurl-$VERSION-x86_64-unknown-linux-gnu.tar.gz | tar xvz -C $INSTALL_DIR
$ export PATH=$INSTALL_DIR/hurl-$VERSION-x86_64-unknown-linux-gnu/bin:$PATH
```

#### Debian / Ubuntu

For Debian >=12 / Ubuntu 22.04 and 24.04, Hurl can be installed using a binary .deb file provided in each Hurl release.

```shell
$ VERSION=8.0.1
$ curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/$VERSION/hurl_${VERSION}_amd64.deb
$ sudo apt update && sudo apt install ./hurl_${VERSION}_amd64.deb
```

For Ubuntu >=22.04, Hurl can be installed from `ppa:lepapareil/hurl`

```shell
$ VERSION=8.0.1
$ sudo apt-add-repository -y ppa:lepapareil/hurl
$ sudo apt install hurl="${VERSION}"*
```

#### Alpine

Hurl is available on `testing` channel.

```shell
$ apk add --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing hurl
```

#### Arch Linux / Manjaro

Hurl is available on [extra] channel.

```shell
$ pacman -Sy hurl
```

#### NixOS / Nix

[NixOS / Nix package] is available on stable channel.

#### Guix

```shell
$ guix install hurl
```

### macOS

Precompiled binaries for Intel and ARM CPUs are available at [Hurl latest GitHub release].

#### Homebrew

```shell
$ brew install hurl
```

#### MacPorts

```shell
$ sudo port install hurl
```

### FreeBSD

```shell
$ sudo pkg install hurl
```

### Windows

Windows requires the [Visual C++ Redistributable Package] to be installed manually, as this is not included in the installer.

#### Zip File

Hurl can be installed from a standalone zip file at [Hurl latest GitHub release]. You will need to update your `PATH` variable.

#### Installer

An executable installer is also available at [Hurl latest GitHub release].

#### Chocolatey

```shell
$ choco install hurl
```

#### Scoop

```shell
$ scoop install hurl
```

#### Windows Package Manager

```shell
$ winget install hurl
```

### Cargo

If you're a Rust programmer, Hurl can be installed with cargo.

```shell
$ cargo install --locked hurl
```

### conda-forge

```shell
$ conda install -c conda-forge hurl
```

Hurl can also be installed with [`conda-forge`] powered package manager like [`pixi`].

### Docker

```shell
$ docker pull ghcr.io/orange-opensource/hurl:latest
```

### npm

```shell
$ npm install --save-dev @orangeopensource/hurl
```

## Building From Sources

Hurl sources are available in [GitHub].

### Build on Linux

Hurl depends on libssl, libcurl and libxml2 native libraries. You will need their development files in your platform.

#### Debian based distributions

```shell
$ apt install build-essential pkg-config libssl-dev libcurl4-openssl-dev libxml2-dev libclang-dev
```

#### Fedora based distributions

```shell
$ dnf install pkgconf-pkg-config gcc openssl-devel libxml2-devel clang-devel
```

#### Red Hat based distributions

```shell
$ yum install pkg-config gcc openssl-devel libxml2-devel clang-devel
```

#### Arch based distributions

```shell
$ pacman -S pkgconf gcc glibc openssl libxml2 clang
```

#### Alpine based distributions

```shell
$ apk add curl-dev gcc libxml2-dev musl-dev openssl-dev clang-dev
```

### Build on macOS

```shell
$ xcode-select --install
$ brew install pkg-config openssl
```

Hurl is written in [Rust]. You should [install] the latest stable release.

```shell
$ curl https://sh.rustup.rs -sSf | sh -s -- -y
$ source $HOME/.cargo/env
$ rustc --version
$ cargo --version
```

Then build hurl:

```shell
$ git clone https://github.com/Orange-OpenSource/hurl
$ cd hurl
$ cargo build --release
$ ./target/release/hurl --version
```

### Build on Windows

Please follow the [contrib on Windows section].

[XPath]: https://en.wikipedia.org/wiki/XPath
[JSONPath]: https://goessner.net/articles/JsonPath/
[Rust]: https://www.rust-lang.org
[curl]: https://curl.se
[the installation section]: https://hurl.dev/docs/installation.html
[Feedback, suggestion, bugs or improvements]: https://github.com/Orange-OpenSource/hurl/issues
[License]: https://hurl.dev/docs/license.html
[Tutorial]: https://hurl.dev/docs/tutorial/your-first-hurl-file.html
[Documentation]: https://hurl.dev/docs/installation.html
[Blog]: https://hurl.dev/blog/
[GitHub]: https://github.com/Orange-OpenSource/hurl
[libcurl]: https://curl.se/libcurl/
[star Hurl on GitHub]: https://github.com/Orange-OpenSource/hurl/stargazers
[HTML]: /docs/standalone/hurl-8.0.0.html
[PDF]: /docs/standalone/hurl-8.0.0.pdf
[Markdown]: /docs/standalone/hurl-8.0.0.md
[JSON body]: https://hurl.dev/docs/request.html#json-body
[XML body]: https://hurl.dev/docs/request.html#xml-body
[XML multiline string body]: https://hurl.dev/docs/request.html#multiline-string-body
[multiline string body]: https://hurl.dev/docs/request.html#multiline-string-body
[predicates]: https://hurl.dev/docs/asserting-response.html#predicates
[JSONPath]: https://goessner.net/articles/JsonPath/
[Basic authentication]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme
[`Authorization` header]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
[Hurl tests suite]: https://github.com/Orange-OpenSource/hurl/tree/master/integration/hurl/tests_ok
[Authorization]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
[`-u/--user` option]: https://hurl.dev/docs/manual.html#user
[curl]: https://curl.se
[entry]: https://hurl.dev/docs/entry.html
[`--test` option]: https://hurl.dev/docs/manual.html#test
[`--user`]: https://hurl.dev/docs/manual.html#user
[Hurl templates]: https://hurl.dev/docs/templates.html
[AWS Signature Version 4]: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
[Captures]: https://hurl.dev/docs/capturing-response.html
[`--json` option]: https://hurl.dev/docs/manual.html#json
[`--resolve`]: https://hurl.dev/docs/manual.html#resolve
[`--connect-to`]: https://hurl.dev/docs/manual.html#connect-to
[Functions]: https://hurl.dev/docs/templates.html#functions
[`--location`]: https://hurl.dev/docs/manual.html#location
[`--location-trusted`]: https://hurl.dev/docs/manual.html#location-trusted
[GitHub]: https://github.com/Orange-OpenSource/hurl
[Hurl latest GitHub release]: https://github.com/Orange-OpenSource/hurl/releases/latest
[Visual C++ Redistributable Package]: https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version
[install]: https://www.rust-lang.org/tools/install
[Rust]: https://www.rust-lang.org
[contrib on Windows section]: https://github.com/Orange-OpenSource/hurl/blob/master/contrib/windows/README.md
[NixOS / Nix package]: https://search.nixos.org/packages?from=0&size=1&sort=relevance&type=packages&query=hurl
[`conda-forge`]: https://conda-forge.org
[`pixi`]: https://prefix.dev
[extra]: https://archlinux.org/packages/extra/x86_64/hurl/

---

### Overview (`docs/README.md`)

# Hurl Documentation

This directory is the canonical source for Hurl documentation. The site <https://hurl.dev>, powered by Jekyll,
is generated from it. If you want to modify <https://hurl.dev>, you can make a PR in this repo.

> [!TIP]
> TLDR
> To update all docs:
> ```shell
> $ bin/docs/update_all.sh
> ```

## Documentation Generation

Some files are dependent and needs to be generated appropriated.
- `docs/spec/options/**/*.option`: define the command line option of `hurl` and `hurlfmt`. These are text declarative
files that will update project files (Rust files to produce the output of `--help`, Rust file options etc..., shell completion
script etc...). These files are also used to generate part of man files `docs/manual/hurl.md`, `docs/manual/hurlfmt.md`
- `docs/manual/hurl.md`/`docs/manual/hurlfmt.md`: Markdown source files of man pages `hurl.1``hurlfmt.1`
- `README.md` / `packages/hurl/README.md`, / `packages/hurlfmt/README.md`: GitHub and <https://crates.io> READMEs. These
files are entirely generated from previous files (`.options` files, `.md` manual) 


### Options

Hurl options files describes each option of `hurl` and `hurlfmt`. They're used to generated various files of the project. 


### Manual Page

The canonical source for the Hurl manual pages is at <https://github.com/Orange-OpenSource/hurl/tree/master/docs/manual>.
The markdown files [`hurl.md`] and [`hurlfmt.md`] are used :

- to generate manual pages [`hurl.1`] and [`hurlfmt.1`]
- to generate Markdown documentation page [`manual.md`] for <https://hurl.dev>

Dependencies:

```
docs/manual/hurl.md => docs/manual/hurl.1
docs/manual/hurl.md => docs/manual.md

docs/manual/hurlfmt.md => docs/manual/hurlfmt.1
```

### READMEs

[GitHub README] and [crates.io README] are generated from the canonical docs.

Dependencies:

```
docs/*.md => README.md
docs/*.md => packages/hurl/README.md
```

### Scripts to update manual and READMEs

1. generate manual
2. generate <hurl.dev> manual
3. generate GitHub README
4. generate crates.io README

```bash
$ cd ..
$ python3 bin/docs/build_man.py docs/manual/hurl.md > docs/manual/hurl.1
$ python3 bin/docs/build_man.py docs/manual/hurlfmt.md > docs/manual/hurlfmt.1
$ python3 bin/docs/build_man_md.py docs/manual/hurl.md > docs/manual.md
$ python3 bin/docs/build_readme.py github > README.md
$ python3 bin/docs/build_readme.py crates > packages/hurl/README.md
```


[`hurl.md`]: https://github.com/Orange-OpenSource/hurl/tree/master/docs/manual/hurl.md
[`hurlfmt.md`]: https://github.com/Orange-OpenSource/hurl/tree/master/docs/manual/hurlfmt.md
[`hurl.1`]: https://github.com/Orange-OpenSource/hurl/tree/master/docs/manual/hurl.1
[`hurlfmt.1`]: https://github.com/Orange-OpenSource/hurl/tree/master/docs/manual/hurlfmt.1
[`manual.md`]: https://github.com/Orange-OpenSource/hurl/blob/master/docs/manual.md
[GitHub README]: https://github.com/Orange-OpenSource/hurl/blob/master/README.md
[crates.io README]: https://github.com/Orange-OpenSource/hurl/blob/master/packages/hurl/README.md

---

### Overview (`integration/README.md`)

# Hurl Integration Tests Suite

## Introduction

In the Hurl project, there are three type of tests:

- Rust unit tests: run at the root of the project with `cargo test --lib`
- Rust integration tests: run at the root of the project with `cargo test`. You will also run unit test with this command. 
To run Rust integration tests, you need to launch a local test server (see below).

These tests are "classic" Rust tests and should not surprise a Rust developer.

Along with tests, we have an extensive integration test suite. These tests launch scripts to run `hurl` and
`hurlfmt` and test various options and Hurl files. To run these tests you have to set up a local server (see below)
All these tests will be performed automatically in Hurl CI/CD, on various OS, for every pull request. 


## Set up Test Local Server

### Python 3.9+

The local test server is a Flask application, so you will need Python 3.9+ on your machine. You can create a Python
virtual environment and install required dependencies:

```shell
$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip install --requirement bin/requirements-frozen.txt
```

### Proxy

Some integration tests need a proxy. Given our cross-platform needs, we selected [squid] rather than [mitmproxy].

### Start local server

You can use the scripts [`bin/test/test_prerequisites.sh`] / [`bin/test/test_prerequisites.ps1`] depending on your OS to start the 
local test server and proxy. Once launch, there is:

- a Flask server instance listening on <http://localhost:8000>
- a Flask server instance listening on <https://localhost:8001>
- a Flask server instance listening on <https://localhost:8002>
- a Flask server instance listening on <https://localhost:8003>
- a Flask server instance listening on `build/unix_socket.sock`
- a HTTP proxy listening on <http://localhost:8888>

Now, everything is ready to run the integration tests!

## Integration Tests

### Organisation

Integration tests to test `hurl` binary are grouped in `integration/hurl` directory:

- [`hurl/tests_ok`]: every test there must be successful (exit code 0). The Hurl files in this folder are formatted with `hurlfmt`.
- [`hurl/tests_ok_not_linted`]: every test here must be successful but are not necessary formatted with `hurlfmt`. This way we can 
ensure that there is no regression even if a Hurl file doesn't follow a stricter format.
- [`hurl/tests_failed`]: every test must fail (exit code different from 0). Tests are syntactically correct, so the error
raised by the test is a runtime error.
- [`hurl/tests_error_parser`]: every test is not a syntactically correct Hurl file. We test here the parsing error message.
- [`hurl/tests_ssl`]: tests SSL features (server, client certificates and test files)
- [`hurl/tests_unix_socket`]: tests Unix Socket (server and test files)
- [`hurl/tests_pty`]: tests that need a "terminal" env, contrary to other tests where standard output and error output 
are captured. These tests use a PTY only available on *Nix platform (Windows WSL included, but not "standard" Windows).


Integration tests to test `hurlfmt` binary are grouped in `integration/hurlfmt` directory:

- [`hurlfmt/tests_ok`]: every test there must be successful (exit code 0)
- [`hurlfmt/tests_failed`]: every test must fail (exit code different from 0)
- [`hurlfmt/tests_export`]: every Hurl file has its own JSON and HTML version/export. Hurl files are not linted.
- [`hurlfmt/tests_error_lint`]: every test is syntactically correct, but is not formatted through `hurlfmt`. We test here the linting.


### Files Description

An integration test consists of:

- two runnable scripts: one for Linux, macOS (`foo.sh`) and one for Windows (`foo.ps1`). These are the 
integration tests that we want to execute.
- a Hurl file (`foo.hurl`)
- a Flask endpoint (`foo.py`). This is the server side used by the Hurl file. You can add as many assert as you want 
to test that our Hurl client conforms to what is expected. Generally, each integration test has its own Flask endpoint, 
even if there is some duplication between tests.
- an expected stdout file (`foo.out`). This file is the expected value for stdout. This file is not dependent from the OS, as we
want a Hurl file to have the same stdout on any OS. If the stdout have some variant data (like timestamp for instance), one 
can use a patterned expected file, with `~~~` for wildcard matching (`foo.out.pattern`)
- an expected stderr file (`foo.err`). This file is the expected value for stderr. This file is not dependent from the OS, as we
  want a Hurl file to have the same stderr on any OS. Like stdout, stderr expected file can be patterned (`foo.err.pattern`)
- an expected exit code (`foo.exit`). This file is the expected value of the script. If absent, the default exit code is 0.
is a JSON view of the Hurl source file and can serve to convert from/to Hurl format.
- an expected list of `curl` commands. This list is the curl command equivalent to each request in the Hurl file
(which is logged in [`--verbose`]/[`--very-verbose`] mode). Each curl command is run against the server.

To run all integration tests:

```shell
$ bin/test/test_integ.sh 
```

To run a particular integration test without any check:

```shell
$ cd integration/hurl
$ tests_ok/hello.sh
```

To run a particular integration test with all check (stdout, stderr, HTML/JSON export etc...):

```shell
$ cd integration/hurl
$ python3 ../test_script.py tests_ok/hello.sh
```

### Sample

`include.sh`:

```shell
#!/bin/bash
set -Eeuo pipefail
hurl --include --verbose tests_ok/include.hurl
```

`include.ps1`:

```powershell
Set-StrictMode -Version latest
$ErrorActionPreference = 'Stop'
hurl tests_ok/include.hurl --include --verbose
```

`include.hurl`:

```hurl
GET http://localhost:8000/include

HTTP 200
`Hello`
```

`include.py`:

```python
from app import app
from flask import Response


@app.route("/include")
def include():
    return Response("Hello")
```

`include.out.pattern`:

```
HTTP/1.1 200
Server: Werkzeug/~~~ Python/~~~
Date: ~~~
Content-Type: text/html; charset=utf-8
Content-Length: 5
Server: Flask Server
Connection: close

Hello
```

`include.html`: 

```html
<pre><code class="language-hurl"><span class="entry"><span class="request"><span class="method">GET</span> <span class="url">http://localhost:8000/include</span>
</span><span class="response">
<span class="version">HTTP</span> <span class="number">200</span>
<span class="string">`Hello`</span>
</span></span>
</code></pre>
```

`include.json`:

```json
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/include"},"response":{"status":200,"body":{"type":"text","value":"Hello"}}}]}
```

`include.curl`:

```
curl 'http://localhost:8000/include'
```

[mitmproxy]: https://mitmproxy.org
[squid]: http://www.squid-cache.org
[`--json`]: /docs/manual.md#json
[`bin/test/test_prerequisites.sh`]: /bin/test/test_prerequisites.sh
[`bin/test/test_prerequisites.ps1`]: /bin/test/test_prerequisites.ps1
[`hurl/tests_ok`]: /integration/hurl/tests_ok
[`hurl/tests_ok_not_linted`]: /integration/hurl/tests_ok_not_linted
[`hurl/tests_failed`]: /integration/hurl/tests_failed
[`hurl/tests_error_parser`]: /integration/hurl/tests_error_parser
[`hurl/tests_ssl`]: /integration/hurl/tests_ssl
[`hurl/tests_unix_socket`]: /integration/hurl/tests_unix_socket
[`hurlfmt/tests_ok`]: /integration/hurlfmt/tests_ok
[`hurlfmt/tests_export`]: /integration/hurlfmt/tests_export
[`hurlfmt/tests_error_lint`]: /integration/hurlfmt/tests_error_lint
[`--verbose`]: /docs/manual.md#verbose
[`--very-verbose`]: /docs/manual.md#very-verbose

---

### Overview (`contrib/brew/README.md`)

# Hurl on Homebrew

## Publish

<https://docs.brew.sh/How-To-Open-a-Homebrew-Pull-Request>

On local terminal, to publish a new version `x.y.z`:

```shell
$ brew bump-formula-pr --url https://github.com/Orange-OpenSource/hurl/archive/refs/tags/x.y.z.tar.gz hurl --verbose --dry-run
$ brew bump-formula-pr --url https://github.com/Orange-OpenSource/hurl/archive/refs/tags/x.y.z.tar.gz hurl --verbose
```

Git config is from `/opt/homebrew`.

---

### Overview (`contrib/conda-forge/README.md`)

# Hurl on conda-forge

## Useful Links

- Public package web page: <https://anaconda.org/conda-forge/hurl>
- Git repo package (feedstock in conda-forge terminology): <https://github.com/conda-forge/hurl-feedstock>
- Help & community channel: <https://conda-forge.zulipchat.com>

## How to Publish a New Hurl Version 

Update to the feedstock can be made via forking the repo <https://github.com/conda-forge/hurl-feedstock> and PR.

---

### Overview (`contrib/cross_compile/README.md`)

# Create generic arm64 linux package

## Prepare docker build env

```
docker system prune -fa
docker buildx prune -fa
docker buildx rm mybuilder
export DOCKER_CLI_EXPERIMENTAL=enabled
sudo apt-get install -y qemu-user-static
ls -l /usr/bin/qemu-aarch64-static
qemu-aarch64-static --version
sudo apt-get install -y binfmt-support
update-binfmts --version
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker buildx create --name mybuilder
docker buildx use mybuilder
docker buildx inspect --bootstrap
docker buildx ls
```

## Choose desired tag

```
echo -n "tag: "
read -r tag
export tag
echo "tag=${tag}"
```

## Clone desired tag

```
git clone --depth 1 https://github.com/Orange-OpenSource/hurl.git --branch "${tag}" /tmp/hurl-"${tag}"
cd /tmp/hurl-"${tag}"
```

## Run docker arm64 ubuntu

```
ubuntu_docker_image=$(grep -E "package-generic-linux-x64|runs-on" .github/workflows/package.yml | head -2 | tail -1 | cut --delimiter ":" --field 2 | tr "-" ":" | tr -d " ")
echo "ubuntu_docker_image=${ubuntu_docker_image}"
docker run --platform linux/arm64 --volume /tmp/hurl-"${tag}":/hurl --workdir /hurl -it --rm "${ubuntu_docker_image}" bash
```

## Install system prerequisistes

```
uname -m
export DEBIAN_FRONTEND=noninteractive
apt update
bin/install_prerequisites_ubuntu.sh
```

## Build

```
source bin/export_cross_compile_env.sh
bin/install_rust.sh
bin/release/release.sh
```

## Create generic arm64 linux tarball

```
export PATH="${PWD}/target/release:${PATH}"
export VERSION=$(bin/release/get_version.sh)
bin/release/man.sh
bin/release/create_tarball.sh linux
```

## Test generic arm64 linux binary

```
bin/release/install_generic_linux_package.sh
export PATH="/tmp/hurl-generic-linux:${PATH}"
bin/activate_python3_venv.sh
export PATH=/tmp/hurl-python3-venv/bin:$PATH
bin/test/test_prerequisites.sh
bin/test/test_integ.sh
```

## List generic arm64 linux package

```
exit
cd target/upload
ls -lrt hurl*
```

---

### Overview (`contrib/docker/README.md`)

# Build multiplatform amd64 and arm64 with buildx

## Prepare docker build env

```
docker system prune -fa
docker buildx prune -fa
docker buildx rm mybuilder
export DOCKER_CLI_EXPERIMENTAL=enabled
sudo apt-get install -y qemu-user-static
ls -l /usr/bin/qemu-aarch64-static
qemu-aarch64-static --version
sudo apt-get install -y binfmt-support
update-binfmts --version
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker buildx create --name mybuilder
docker buildx use mybuilder
docker buildx inspect --bootstrap
docker buildx ls
```

## Connect to GitHub container registry

```
read -s -p "Hurl-bot github token: " hurl_bot_token
echo "${hurl_bot_token}" | docker login ghcr.io --username hurl-bot --password-stdin
```

## Clone desired tag

```
read -e -i "" -p "Hurl version: " tag
read -e -i "orange-opensource" -p "organisation: " organisation
git clone --depth 1 https://github.com/"${organisation}"/hurl.git --branch "${tag}" /tmp/hurl-"${tag}"
cd /tmp/hurl-"${tag}"
```

## Build and push

```
docker_build_tag=$(grep ^version packages/hurl/Cargo.toml | cut --delimiter '=' --field 2 | tr -d '" ')
echo "docker_build_tag=${docker_build_tag}"
docker_build_date=$(date "+%Y-%m-%d %H-%M-%S")
echo "docker_build_date=${docker_build_date}"
docker buildx build --platform linux/amd64,linux/arm64 --file contrib/docker/Dockerfile --build-arg docker_build_date="${docker_build_date}" --build-arg docker_build_tag="${docker_build_tag}" --tag ghcr.io/"${organisation}"/hurl:"${docker_build_tag}" --push .
```

## Get docker hurl version

```
docker run --rm ghcr.io/"${organisation}"/hurl:"${docker_build_tag}" --version
```

## Run docker hurl from STDIN

```
echo -e "GET https://hurl.dev\n\nHTTP 200" | docker run --rm -i ghcr.io/"${organisation}"/hurl:"${docker_build_tag}" --test --color --very-verbose
```

## Run docker hurl from FILE

```
echo -e "GET https://hurl.dev\n\nHTTP 200" > /tmp/test.hurl
docker run --rm -v /tmp/test.hurl:/tmp/test.hurl ghcr.io/"${organisation}"/hurl:"${docker_build_tag}" --test --color --very-verbose /tmp/test.hurl
```

## Tag latest

Get manifest list sha256 from github packages page (ex: sha256:d7727dcc0166de8aea88916e73ea435ee09bfecb8ba0c281200206b6cf37cf64) and :

```
read -e -i "" -p "Hurl ${docker_build_tag} manifest sha256: " sha
docker buildx imagetools create   -t ghcr.io/"${organisation}"/hurl:latest   ghcr.io/orange-opensource/hurl@"${sha}"
```

## Build and push

# Build amd64 image only

## Clone desired tag

```
read -e -i "" -p "Hurl version: " tag
read -e -i "orange-opensource" -p "organisation: " organisation
git clone --depth 1 https://github.com/"${organisation}"/hurl.git --branch "${tag}" /tmp/hurl-"${tag}"
```

## Prepare docker build env

```
docker rmi --force \
  ghcr.io/"${organisation}"/hurl:amd64-"${docker_build_tag}" \
  local/hurl
```

## Build

```
cd /tmp/hurl-"${tag}"
docker_build_tag=$(grep ^version packages/hurl/Cargo.toml | cut --delimiter '=' --field 2 | tr -d '" ')
echo "docker_build_tag=${docker_build_tag}"
docker_build_date=$(date "+%Y-%m-%d %H-%M-%S")
echo "docker_build_date=${docker_build_date}"
docker build --file contrib/docker/Dockerfile --build-arg docker_build_date="${docker_build_date}" --build-arg docker_build_tag="${docker_build_tag}" --tag  local/hurl --tag ghcr.io/"${organisation}"/hurl:amd64-"${docker_build_tag}" .
```

## Get docker hurl version

```
docker run --rm local/hurl --version
```

## Run docker hurl from STDIN

```
echo -e "GET https://hurl.dev\n\nHTTP 200" | docker run --rm -i local/hurl --test --color --very-verbose
```

## Run docker hurl from FILE

```
echo -e "GET https://hurl.dev\n\nHTTP 200" > /tmp/test.hurl
docker run --rm -v /tmp/test.hurl:/tmp/test.hurl local/hurl --test --color --very-verbose /tmp/test.hurl
```

## Connect to GitHub container registry

```
echo <hurl-bot github token> | docker login ghcr.io --username hurl-bot --password-stdin
```

## Push to GitHub registry

```
docker push ghcr.io/"${organisation}"/hurl:amd64-"${docker_build_tag}"
```

# Build arm64 image only

## Clone desired tag

```
read -e -i "" -p "Hurl version: " tag
read -e -i "orange-opensource" -p "organisation: " organisation
git clone --depth 1 https://github.com/"${organisation}"/hurl.git --branch "${tag}" /tmp/hurl-"${tag}"
```

## Prepare docker build env

```
docker rmi --force \
  ghcr.io/"${organisation}"/hurl:arm64-"${docker_build_tag}" \
  local/hurl
```

## Build

```
cd /tmp/hurl-"${tag}"
docker_build_tag=$(grep ^version packages/hurl/Cargo.toml | cut --delimiter '=' --field 2 | tr -d '" ')
echo "docker_build_tag=${docker_build_tag}"
docker_build_date=$(date "+%Y-%m-%d %H-%M-%S")
echo "docker_build_date=${docker_build_date}"
docker build --file contrib/docker/Dockerfile --build-arg docker_build_date="${docker_build_date}" --build-arg docker_build_tag="${docker_build_tag}" --tag  local/hurl --tag ghcr.io/"${organisation}"/hurl:arm64-"${docker_build_tag}" .
```

## Get docker hurl version

```
docker run --rm local/hurl --version
```

## Run docker hurl from STDIN

```
echo -e "GET https://hurl.dev\n\nHTTP 200" | docker run --rm -i local/hurl --test --color
```

## Run docker hurl from FILE

```
echo -e "GET https://hurl.dev\n\nHTTP 200" > /tmp/test.hurl
docker run --rm -v /tmp/test.hurl:/tmp/test.hurl local/hurl --test --color /tmp/test.hurl
```

## Connect to github container registry

```
echo <hurl-bot github token> | docker login ghcr.io --username hurl-bot --password-stdin
```

## Push to github registry

```
docker push ghcr.io/"${organisation}"/hurl:arm64-"${docker_build_tag}"
```

# Create image containing built amd64 and arm64 images

## Create tag and latest manifest

```
docker manifest create \
  ghcr.io/"${organisation}"/hurl:"${docker_build_tag}" \
  --amend ghcr.io/"${organisation}"/hurl:amd64-"${docker_build_tag}" \
  --amend ghcr.io/"${organisation}"/hurl:arm64-"${docker_build_tag}"
docker manifest create \
  ghcr.io/"${organisation}"/hurl:latest" \
  --amend ghcr.io/"${organisation}"/hurl:amd64-"${docker_build_tag}" \
  --amend ghcr.io/"${organisation}"/hurl:arm64-"${docker_build_tag}"
```

## Push new manifest

```
docker manifest push ghcr.io/"${organisation}"/hurl:"${docker_build_tag}"
docker manifest push ghcr.io/"${organisation}"/hurl:latest
```

---

### Overview (`contrib/docker/dockerhub_readme.md`)

# Container image has moved to github

Since hurl 2.0.0, docker hub is no more supported, please use https://github.com/Orange-OpenSource/hurl/pkgs/container/hurl :)

### Quick references

- **Maintained by**: Filipe PINTO, Fabrice REIX (Orange-OpenSource/hurl maintainers).
- **Home**: https://hurl.dev
- **Where to get help**: https://github.com/Orange-OpenSource/hurl/issues

### What is Hurl ?



Hurl is a command line tool that runs HTTP requests defined in a simple plain text format.
It can perform requests, capture values and evaluate queries on headers and body response. Hurl is very versatile: it can be used for both fetching data and testing HTTP sessions.

### How to use this image

Get Hurl version:

```
docker run --rm ghcr.io/orange-opensource/hurl:latest --version
```

Run Hurl from STDIN:

```
echo -e "GET https://hurl.dev\n\nHTTP/1.1 200" | docker run --rm -i ghcr.io/orange-opensource/hurl:latest --test --color
```

Run Hurl from FILE:

```
echo -e "GET https://hurl.dev\n\nHTTP/1.1 200" > /tmp/test.hurl
docker run --rm -v /tmp/test.hurl:/tmp/test.hurl -w /tmp ghcr.io/orange-opensource/hurl:latest --test --color /tmp/test.hurl
```

---

### Overview (`contrib/emacs/README.md`)

<div align="center">
  <h1>Emacs Hurl</h1>

Emacs major mode for Hurl.

</div>

---

## Features

- Keyword highlight

## Installation

### Doom Emacs

in `packages.el`

``` lisp
(package! hurl-mode :recipe
  (:host github
   :repo "Orange-OpenSource/hurl"
   :files ("contrib/emacs/*.el")))
```

### straight.el

``` lisp
(straight-use-package
 '(hurl-mode
   :type git :host github :repo "Orange-OpenSource/hurl" :files ("contrib/emacs/*.el")))

```

---

### Overview (`contrib/intellij/README.md`)

# Support for Hurl Syntax coloring

This enables basic syntax coloring for Hurl files in [IntelliJ](https://www.jetbrains.com/help/idea/directories-used-by-the-ide-to-store-settings-caches-plugins-and-logs.html#config-directory), until a proper Hurl Intellij plugin is developed (help
is welcome 🤓).


## Linux

1. Quit IntelliJ (or CLion etc...)
2. Copy Hurl.xml to ~/.config/JetBrains/[YOUR IDE DIR]/filetypes
3. Start IntelliJ

## macOS

1. Quit IntelliJ (or CLion etc...)
2. Copy Hurl.xml to ~/Library/Application Support/JetBrains/[YOUR IDE DIR]/filetypes 
3. Start IntelliJ

## Windows

1. Quit IntelliJ (or CLion etc...)
2. Copy Hurl.xml to C:\Users\[YOUR USER]\AppData\Roaming\JetBrains\[YOUR IDE DIR]\filetypes
3. Start IntelliJ

---

### Overview (`contrib/linux/README.md`)

# Information on Linux Hurl Package

## Alpine

### Information

Site: <https://www.alpinelinux.org>

There is one Hurl package <https://pkgs.alpinelinux.org/package/edge/testing/x86_64/hurl>

### Contributing

Repo: <https://gitlab.alpinelinux.org/alpine/aports.git>

File: <https://git.alpinelinux.org/aports/tree/testing/hurl/APKBUILD>

Contributing is done through the GitLab Alpine: <https://gitlab.alpinelinux.org>


## Arch Linux

### Information

Site: <https://archlinux.org>

There are two Hurl packages in AUR user repository:

- <https://aur.archlinux.org/packages/hurl-bin>: the original ones, we contribute to it. This package uses the 
GitHub binaries released and do not try to build from source.
- <https://aur.archlinux.org/packages/hurl-rs>: a package that build Hurl from sources, including Integration tests. We 
should contact the package maintainers to simplify this package (mainly remove dependencies from python etc...)

### Contributing

Repo: <ssh://aur@aur.archlinux.org/hurl-bin.git> <https://aur.archlinux.org/hurl-bin.git> (read only)

Register an account: <https://aur.archlinux.org/register>

File: <https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=hurl-bin>

File: <https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=hurl-rs>

## Debian 

??

## NixOS

### Information

Site: <https://nixos.org>

### Contributing

Repo: <https://github.com/NixOS/nixpkgs>

File: <https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/tools/networking/hurl/default.nix>

---

### Overview (`contrib/npm/README.md`)

# Hurl on npm

Hurl is [distributed on npm] as a thin wrapper around the native binary.

## Build

## Publish

To publish a new version of the package `PACKAGE_VERSION` using the binary `HURL_VERSION`:

```shell
$ cp docs/manual/*.1 contrib/npm/hurl/docs/
$ python3 ./contrib/npm/check_publish.py $HURL_VERSION $PACKAGE_VERSION
$ rm -rfd contrib/npm/hurl/dist contrib/npm/hurl/node_modules
$ npm publish --dry-run contrib/npm/hurl/
$ npm publish contrib/npm/hurl/
```


[distributed on npm]: https://www.npmjs.com/package/@orangeopensource/hurl

---

### Overview (`contrib/ppa/README.md`)

# Build and push to PPA

## Create the PPA for Ubuntu focal and newer

- Go to https://launchpad.net
- Create an account
- Create PPA
- Add your GPG Public key to https://keyserver.ubuntu.com/#submitKey
- Add your GPG public key to your PPA

```
########## gpg memo ##########

# get <gpg_keyid>
gpg_keyid=$(gpg --list-keys | grep -E "^ " | tr -d ' ')

# get <GPG-FINGERPRINT>
gpg --fingerprint "${gpg_keyid}"

# export ascii-armored gpg public key
gpg --armor --export "${gpg_keyid}"

# export public and private key
gpg --armor --export "${gpg_keyid}" > /tmp/mypublickey.asc
gpg --armor --export-secret-keys "${gpg_keyid}" > /tmp/myprivatekey.asc

# import public and private key
gpg --import /tmp/mypublickey.asc
gpg --import /tmp/myprivatekey.asc

```

## Choose Hurl version and Ubuntu codename

```
read -e -i "" -p "Hurl version: " hurl_version
read -e -i "" -p "Ubuntu codename: " codename
read -s -p "Gpg passphrase: " passphrase
```

## Export gpg key

```
mkdir -p /tmp/gpg
chmod 777 /tmp/gpg
gpg_keyid=$(gpg --list-keys | grep -E "^ " | tr -d ' ')
gpg --batch --passphrase "${passphrase}" --pinentry-mode loopback --armor --export "${gpg_keyid}" > /tmp/gpg/mypublickey.asc
gpg --batch --passphrase "${passphrase}" --pinentry-mode loopback --armor --export-secret-keys "${gpg_keyid}" > /tmp/gpg/myprivatekey.asc

```

## Run ubuntu container

```
docker run -it --rm --env gpg_keyid="${gpg_keyid}" --env hurl_version="${hurl_version}" --env codename="${codename}" --env passphrase="${passphrase}" --env date="$(date -u "+%a, %d %b %Y %H:%M:%S")" --volume "/tmp/gpg:/tmp/gpg" ubuntu:"${codename}" bash

```

## Install user prerequisites and build dependencies

```
export DEBIAN_FRONTEND=noninteractive
apt update
apt install -y  gpg git curl wget vim xz-utils gettext moreutils pv && \
apt install -y pkg-config gcc libclang-dev curl libxml2-dev libssl-dev devscripts debhelper

```

## Import GPG key into container

```
export GPG_TTY=$(tty)
gpg --batch --passphrase "${passphrase}" --pinentry-mode loopback --import /tmp/gpg/mypublickey.asc
gpg --batch --passphrase "${passphrase}" --pinentry-mode loopback --import /tmp/gpg/myprivatekey.asc

```

## Clone Hurl

```
rm -fr /tmp/ppa || true
git clone --depth 1 https://github.com/Orange-OpenSource/hurl.git --branch "${hurl_version}" /tmp/ppa/hurl-"${hurl_version}"
cd /tmp/ppa/hurl-"${hurl_version}"

```

## Get debian conf from master

```
git clone --depth 1 https://github.com/Orange-OpenSource/hurl.git /tmp/ppa/hurl-ppa
cp -r ../hurl-ppa/contrib/ppa/debian .

```

## Minimize repo

```
rm -fr .github \
       .git \
       rustfmt.toml \
       ruff.toml \
       art \
       contrib \
       integration \
       RELEASING.md \
       README.md \
       CONTRIBUTING.md
while read -r dir ; do
    rm -fr $dir
done < <(find bin -mindepth 1 -type d | grep -Ev "bin/release|bin/docs")
while read -r file ; do
    rm -fr $file
done < <(find bin -type f | grep -Ev "man\.sh|release\.sh|build_man\.py")
while read -r dir ; do
    rm -fr $dir
done < <(find docs -mindepth 1 -type d | grep -v "docs/manual")
while read -r file ; do
    rm -fr $file
done < <(find docs -type f | grep -Ev "manual/")

```

## Create minimized offline rust and cargo installer (because ppa workers do not have internet)

```
rust_version=$(grep '^rust-version' packages/hurl/Cargo.toml | cut -f2 -d'"')
for arch in x86_64 aarch64 ; do
package="rust-${rust_version}-${arch}-unknown-linux-gnu"
packagelight="${package}-light"
wget "https://static.rust-lang.org/dist/${package}.tar.xz"
xz -T0 -vd "${package}.tar.xz"
tar -x -f "${package}.tar"
dirs_to_delete=$(find "${package}" -type d | cut --delimiter "/" --field 1,2 | grep "/" | grep -Ev  "/cargo$|/rust-std-${arch}-unknown-linux-gnu$|/rustc$" | sort -u | tr '\n' ' ')
rm -fr $dirs_to_delete
grep -E "^cargo$|^rust-std-${arch}-unknown-linux-gnu$|^rustc$" "${package}/components" | sponge "${package}/components"
mv "${package}" "${packagelight}"
tar -c -f - "${packagelight}" | pv > "${packagelight}.tar"
xz -T0 -9 -v "${packagelight}.tar"
rm -fr "${package}.tar" "${packagelight}"
done

```

## Install rust and cargo

```
arch=$(uname -m)
package="rust-${rust_version}-${arch}-unknown-linux-gnu"
packagelight="${package}-light"
tar -x -f "${packagelight}".tar.xz
./"${packagelight}"/install.sh --destdir=/tmp/rust --disable-ldconfig
export PATH="/tmp/rust/usr/local/bin:$PATH"
rustc --version
cargo --version
rm -fr "${packagelight}"

```

## Create vendor.tar.xz (offline cargo deps)

```
cargo vendor
tar -p -c -J -f - vendor | pv > vendor.tar.xz
rm -rf vendor

```

## Create debian/cargo-checksum.json

```
cargo package --package hurl
sum=$(sha256sum target/package/hurl-"${hurl_version}".crate | cut -d' ' -f1 | tr -d ' ')
echo "{\"package\": \"${sum}\",\"files\": {}}" > debian/cargo-checksum.json
cat debian/cargo-checksum.json
rm -fr target

```

## Create debian/cargo_home/config and update .cargo/config

```
mkdir -p debian/cargo_home
cp Cargo.toml debian/cargo_home/config
{
cat .cargo/config.toml
echo
cat debian/cargo.config
} > .cargo/config

```

## Create debian/changelog

```
envsubst < debian/changelog.template > debian/changelog
cat debian/changelog

```

## Fix debian/control for Ubuntu <24

```
ubuntu_major_version=$(cat /etc/lsb-release | grep DISTRIB_RELEASE | cut -d'=' -f2 | cut -d'.' -f1)
if [[ $ubuntu_major_version -lt 24 ]] ; then
    sed -i "s/pkgconf/pkg-config/g" debian/control
fi
```

## Create deb package source

```
hurl_long_version=$(head -1 debian/changelog | cut -d'(' -f2 | cut -d')' -f1)
cd ..
tar --exclude="hurl-${hurl_version}/debian" -c -z -f - "hurl-${hurl_version}" | pv > "hurl_${hurl_long_version}.orig.tar.gz"
cd "hurl-${hurl_version}"
lintian -i -E --profile debian --display-info --display-experimental --suppress-tags source-is-missing
yes | debuild -S -sa -k"${gpg_keyid}" -p"gpg --batch --passphrase ${passphrase} --pinentry-mode loopback"

```

## Verify deb package source

```
cd ..
ls -l hurl_*

```

## Push to PPA

```
dput ppa:lepapareil/hurl hurl_*_source.changes

```

## Clean debuild packages

```
rm -fr hurl_"${hurl_version}"*

```

# Test Hurl from published PPA

## Choose Hurl version and Ubuntu codename

```shell
echo -n "hurl_version=" && read -r hurl_version
echo -n "Ubuntu codename=" && read -r codename
docker run -it --rm --env hurl_version="${hurl_version}" --env codename="${codename}" --volume "/tmp:/tmp" "ubuntu:${codename}" bash

```

## Install Hurl
```
export DEBIAN_FRONTEND=noninteractive
yes | unminimize
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1550DC447B95F03B
apt install -y git sudo man-db curl software-properties-common && \
    apt-add-repository -y ppa:lepapareil/hurl && \
    apt list --all-versions hurl && \
    apt install -y hurl="${hurl_version}"*
```


## Check Hurl installed version

```
hurl --version
hurlfmt --version
man hurl | head -1
man hurlfmt | head -1
```

## Run Hurl from STDIN

```
echo -e "GET https://hurl.dev\n\nHTTP 200" | hurl --test --color
```

## Run  Hurl from FILE

```
echo -e "GET https://hurl.dev\n\nHTTP 200" > /tmp/test.hurl
hurl --test --color /tmp/test.hurl
```

# Build libxml2

If you want to build another version of libxml2 on ubuntu:

```
minimum_version="2.9.11"
libxml2_installed_version=$(apt list --installed 2>/dev/null | grep libxml2 | cut --delimiter ' ' --field 2 | cut --delimiter '+' --field 1)
if dpkg --compare-versions "${libxml2_installed_version}" ge "${minimum_version}" ; then
    echo "ok"
else
    tar xf libxml2-"${minimum_version}".tar.gz
    cd libxml2-"${minimum_version}"
    ./configure --prefix=/opt/libxml2-"${minimum_version}" --with-zlib
    make -j$(nproc)
    make install
    export PKG_CONFIG_PATH=/opt/libxml2-"${minimum_version}"/lib/pkgconfig:$PKG_CONFIG_PATH
    export LD_LIBRARY_PATH=/opt/libxml2-"${minimum_version}"/lib:$LD_LIBRARY_PATH
    export PATH=/opt/libxml2-"${minimum_version}"/bin:$PATH
fi
```

---

### Overview (`contrib/sublime-text/README.md`)

# Support for Hurl Syntax Highlighting

This enables syntax coloring for Hurl files in [Sublime Text], and in any tool
that reuses Sublime Text syntax definitions, such as [bat].

The `Hurl.sublime-syntax` definition covers methods, URLs, versions and status,
sections, headers and parameters, queries, predicates, filters, functions,
templates/placeholders (`{{ ... }}`), comments, and bodies (JSON, XML,
multiline strings, oneline strings, and `base64,`/`hex,`/`file,` values).

## Sublime Text

File-extension detection is built into the syntax (`.hurl`), so a single file
is all that is needed.

1. In Sublime Text, open `Preferences > Browse Packages…` to open the
   `Packages` directory.
2. Copy `Hurl.sublime-syntax` into the `User` sub-directory:

   ```bash
   # Linux
   cp Hurl.sublime-syntax ~/.config/sublime-text/Packages/User/

   # macOS
   cp Hurl.sublime-syntax "~/Library/Application Support/Sublime Text/Packages/User/"

   # Windows
   copy Hurl.sublime-syntax "%APPDATA%\Sublime Text\Packages\User\"
   ```

3. Open any `.hurl` file; the `Hurl` syntax is applied automatically.

## bat

[bat] reuses Sublime Text syntaxes.

```bash
mkdir -p "$(bat --config-dir)/syntaxes"
cp Hurl.sublime-syntax "$(bat --config-dir)/syntaxes/"
bat cache --build
```

Then:

```bash
bat test.hurl
```

[Sublime Text]: https://www.sublimetext.com
[bat]: https://github.com/sharkdp/bat

---

### Overview (`contrib/vim/README.md`)

# Support for Hurl Syntax Highlighting

This enables basic syntax coloring for Hurl files in Vim/Neovim.

## Installation

### Vim

Install Vim syntax highlighting for Hurl

```bash
mkdir -p ~/.vim/{ftdetect,syntax}
cp ftdetect/hurl.vim ~/.vim/ftdetect
cp syntax/hurl.vim ~/.vim/syntax
```

### Neovim

Install Neovim syntax highlighting for Hurl

```bash
mkdir -p ~/.config/nvim/{ftdetect,syntax}
cp ftdetect/hurl.vim ~/.config/nvim/ftdetect
cp syntax/hurl.vim ~/.config/nvim/syntax
```

## Configuration

Activate syntax highlighting in your `~/.vimrc` or `~/.config/nvim/init.vim`

```vim
syntax on
```

---

### Overview (`contrib/windows/README.md`)

# What ?

This document describes the steps to build the `windows 64bits hurl binary` with Powershell 7.

All command have been launched with `admin` privileges on `c:\` root dir and executed sequentially. *(If you don't want to use `c:\` as installation path and git clone path, please replace all its references before executing commands )*

All the steps have been tested on a `blank` Windows 10 64bits and total operation time is about `30 minutes` with a xdsl connection (5mb/sec). 

You just have to follow each chapter sequentially until you get a windows installer allowing the native installation of hurl on your favorite windows 64bits computer.

# Build requirements

Install vs_buildtools

```pwsh
cd c:\
Invoke-WebRequest -UseBasicParsing https://aka.ms/vs/17/release/vs_buildtools.exe  -Outfile vs_buildtools.exe
Start-Process -Wait -PassThru -FilePath .\vs_buildtools.exe -ArgumentList "--addProductLang", "En-us", "--add", "Microsoft.VisualStudio.Workload.VCTools", "--includeRecommended", "--passive", "--norestart", "--nocache", "--wait"
```

Install chocolatey

```pwsh
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
```

Install git, llvm, nsis and python3

```pwsh
choco install --confirm --no-progress git winlibs-llvm-free llvm nsis
choco install --confirm --no-progress python311
python -m pip install --upgrade pip --quiet
```

Install rust

```pwsh
Invoke-WebRequest -UseBasicParsing -OutFile "c:\rustup-init.exe" "https://static.rust-lang.org/rustup/dist/i686-pc-windows-gnu/rustup-init.exe"
c:\rustup-init.exe -y  --default-toolchain stable-x86_64-pc-windows-msvc
Set-ItemProperty -Path HKCU:\Environment -Name RUST_BACKTRACE -Value "full"
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") 
```

Install vcpkg

```pwsh
git.exe config --global core.autocrlf false
git.exe config --global core.eol lf
git.exe clone https://github.com/microsoft/vcpkg
c:\vcpkg\bootstrap-vcpkg.bat
$oldpath = Get-ItemProperty -Path HKCU:\Environment -Name Path
$newpath = $oldpath.Path += ";c:\vcpkg"
Set-ItemProperty -Path HKCU:\Environment -Name Path -Value $newpath
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") 
```

# Clone hurl project

```pwsh
cd c:\
git.exe clone https://github.com/Orange-OpenSource/hurl.git
```

# Build

```pwsh
cd c:\hurl
.\bin\install_prerequisites_windows.ps1
.\bin\release\release.ps1
```

# Create a simple zip package

```pwsh
cd c:\hurl
.\bin\release\create_windows64_zip_package.ps1
```

# Create a package installer for win64

```pwsh
cd c:\hurl
.\bin\release\create_windows64_installer.ps1
```

---

### Overview (`packages/hurl/README.md`)

<picture>
    <source media="(prefers-color-scheme: light)" srcset="https://hurl.dev/assets/img/logo-light.svg" > 
    <source media="(prefers-color-scheme: dark)" srcset="https://hurl.dev/assets/img/logo-dark.svg" > 
    <img src="https://hurl.dev/assets/img/logo-light.svg" width="264px" alt="Hurl Logo">
</picture>

[](https://github.com/Orange-OpenSource/hurl/actions)
[](https://Orange-OpenSource.github.io/hurl/coverage)
[](https://crates.io/crates/hurl)
[](https://hurl.dev)

# What's Hurl?

Hurl is a command line tool that runs <b>HTTP requests</b> defined in a simple <b>plain text format</b>.

It can chain requests, capture values and evaluate queries on headers and body response. Hurl is very
versatile: it can be used for both <b>fetching data</b> and <b>testing HTTP</b> sessions.

Hurl makes it easy to work with <b>HTML</b> content, <b>REST / SOAP / GraphQL</b> APIs, or any other <b>XML / JSON</b> based APIs. 

```hurl
# Go home and capture token
GET https://example.org
HTTP 200
[Captures]
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"


# Do login!
POST https://example.org/login
[Form]
user: toto
password: 1234
token: {{csrf_token}}
HTTP 302
```

Chaining multiple requests is easy:

```hurl
GET https://example.org/api/health
GET https://example.org/api/step1
GET https://example.org/api/step2
GET https://example.org/api/step3
```

# Also an HTTP Test Tool

Hurl can run HTTP requests but can also be used to <b>test HTTP responses</b>.
Different types of queries and predicates are supported, from [XPath] and [JSONPath] on body response,
to assert on status code and response headers.

<a href="https://hurl.dev/player.html?id=starwars&speed=3"><img src="https://hurl.dev/assets/img/poster-starwars.png" width="100%" alt="Hurl Demo"/></a>


It is well adapted for <b>REST / JSON APIs</b>

```hurl
POST https://example.org/api/tests
{
    "id": "4568",
    "evaluate": true
}
HTTP 200
[Asserts]
header "X-Frame-Options" == "SAMEORIGIN"
jsonpath "$.status" == "RUNNING"    # Check the status code
jsonpath "$.tests" count == 25      # Check the number of items
jsonpath "$.id" matches /\d{4}/     # Check the format of the id
```

<b>HTML content</b>

```hurl
GET https://example.org
HTTP 200
[Asserts]
xpath "normalize-space(//head/title)" == "Hello world!"
```

<b>GraphQL</b> 

~~~hurl
POST https://example.org/graphql
```graphql
{
  human(id: "1000") {
    name
    height(unit: FOOT)
  }
}
```
HTTP 200
~~~

and even <b>SOAP APIs</b>

```hurl
POST https://example.org/InStock
Content-Type: application/soap+xml; charset=utf-8
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="https://example.org">
  <soap:Header></soap:Header>
  <soap:Body>
    <m:GetStockPrice>
      <m:StockName>GOOG</m:StockName>
    </m:GetStockPrice>
  </soap:Body>
</soap:Envelope>
HTTP 200
```

Hurl can also be used to test the <b>performance</b> of HTTP endpoints

```hurl
GET https://example.org/api/v1/pets
HTTP 200
[Asserts]
duration < 1000  # Duration in ms
```

And check response bytes

```hurl
GET https://example.org/data.tar.gz
HTTP 200
[Asserts]
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
```

Finally, Hurl is easy to <b>integrate in CI/CD</b>, with text, JUnit, TAP and HTML reports

<picture>
    <source media="(prefers-color-scheme: light)" srcset="https://hurl.dev/assets/img/home-waterfall-light.png">
    <source media="(prefers-color-scheme: dark)" srcset="https://hurl.dev/assets/img/home-waterfall-dark.png">
    <img src="https://hurl.dev/assets/img/home-waterfall-light.png" width="480" alt="HTML report"/>
</picture>

# Why Hurl?

<ul class="showcase-container">
    <li><b>Text Format:</b> for both devops and developers</li>
    <li><b>Fast CLI:</b> a command line for local dev and continuous integration</li>
    <li><b>Single Binary:</b> easy to install, with no runtime required</li>
</ul>

# Powered by curl

Hurl is a lightweight binary written in [Rust]. Under the hood, Hurl HTTP engine is
powered by [libcurl], one of the most powerful and reliable file transfer libraries.
With its text file format, Hurl adds syntactic sugar to run and test HTTP requests,
but it's still the [curl] that we love: __fast__, __efficient__ and __IPv6 / HTTP/3 ready__.

# Feedbacks

To support its development, [star Hurl on GitHub]!

[Feedback, suggestion, bugs or improvements] are welcome.

```hurl
POST https://hurl.dev/api/feedback
{
  "name": "John Doe",
  "feedback": "Hurl is awesome!"
}
HTTP 200
```

# Resources

[License]

[Blog]

[Tutorial]

[Documentation] (download [HTML], [PDF], [Markdown]) 

[GitHub]

# Table of Contents

* [Samples](#samples)
    * [Getting Data](#getting-data)
        * [HTTP Headers](#http-headers)
        * [Query Params](#query-params)
        * [Basic Authentication](#basic-authentication)
        * [Passing Data between Requests ](#passing-data-between-requests)
    * [Sending Data](#sending-data)
        * [Sending HTML Form Data](#sending-html-form-data)
        * [Sending Multipart Form Data](#sending-multipart-form-data)
        * [Posting a JSON Body](#posting-a-json-body)
        * [Templating a JSON Body](#templating-a-json-body)
        * [Templating a XML Body](#templating-a-xml-body)
        * [Using GraphQL Query](#using-graphql-query)
        * [Using Dynamic Datas](#using-dynamic-datas)
    * [Testing Response](#testing-response)
        * [Testing Status Code](#testing-status-code)
        * [Testing Response Headers](#testing-response-headers)
        * [Testing REST APIs](#testing-rest-apis)
        * [Testing HTML Response](#testing-html-response)
        * [Testing Set-Cookie Attributes](#testing-set-cookie-attributes)
        * [Testing Bytes Content](#testing-bytes-content)
        * [SSL Certificate](#ssl-certificate)
        * [Checking Full Body](#checking-full-body)
        * [Testing Redirections](#testing-redirections)
    * [Debug Tips](#debug-tips)
        * [Verbose Mode](#verbose-mode)
        * [Error Format](#error-format)
        * [Output Response Body](#output-response-body)
        * [Export curl Commands](#export-curl-commands)
        * [Using Proxy](#using-proxy)
    * [Reports](#reports)
        * [HTML Report](#html-report)
        * [JSON Report](#json-report)
        * [JUnit Report](#junit-report)
        * [TAP Report](#tap-report)
        * [JSON Output](#json-output)
    * [Others](#others)
        * [HTTP Version](#http-version)
        * [IP Address](#ip-address)
        * [Polling and Retry](#polling-and-retry)
        * [Delaying Requests](#delaying-requests)
        * [Skipping Requests](#skipping-requests)
        * [Testing Endpoint Performance](#testing-endpoint-performance)
        * [Using SOAP APIs](#using-soap-apis)
        * [Capturing and Using a CSRF Token](#capturing-and-using-a-csrf-token)
        * [Redacting Secrets](#redacting-secrets)
        * [Checking Byte Order Mark (BOM) in Response Body](#checking-byte-order-mark-bom-in-response-body)
        * [AWS Signature Version 4 Requests](#aws-signature-version-4-requests)
        * [Using curl Options](#using-curl-options)
* [Manual](#manual)
    * [Name](#name)
    * [Synopsis](#synopsis)
    * [Description](#description)
    * [Hurl File Format](#hurl-file-format)
        * [Capturing values](#capturing-values)
        * [Asserts](#asserts)
    * [Configuration](#configuration)
    * [All Options](#all-options)
        * [HTTP options](#http-options)
        * [Output options](#output-options)
        * [Run options](#run-options)
        * [Report options](#report-options)
        * [Other options](#other-options)
    * [Exit Codes](#exit-codes)
    * [WWW](#www)
    * [See Also](#see-also)
* [Installation](#installation)
    * [Binaries Installation](#binaries-installation)
        * [Linux](#linux)
            * [Debian / Ubuntu](#debian--ubuntu)
            * [Alpine](#alpine)
            * [Arch Linux / Manjaro](#arch-linux--manjaro)
            * [NixOS / Nix](#nixos--nix)
            * [Guix](#guix)
        * [macOS](#macos)
            * [Homebrew](#homebrew)
            * [MacPorts](#macports)
        * [FreeBSD](#freebsd)
        * [Windows](#windows)
            * [Zip File](#zip-file)
            * [Installer](#installer)
            * [Chocolatey](#chocolatey)
            * [Scoop](#scoop)
            * [Windows Package Manager](#windows-package-manager)
        * [Cargo](#cargo)
        * [conda-forge](#conda-forge)
        * [Docker](#docker)
        * [npm](#npm)
    * [Building From Sources](#building-from-sources)
        * [Build on Linux](#build-on-linux)
            * [Debian based distributions](#debian-based-distributions)
            * [Fedora based distributions](#fedora-based-distributions)
            * [Red Hat based distributions](#red-hat-based-distributions)
            * [Arch based distributions](#arch-based-distributions)
            * [Alpine based distributions](#alpine-based-distributions)
        * [Build on macOS](#build-on-macos)
        * [Build on Windows](#build-on-windows)

# Samples

To run a sample, edit a file with the sample content, and run Hurl:

```shell
$ vi sample.hurl

GET https://example.org

$ hurl sample.hurl
```

By default, Hurl behaves like [curl] and outputs the last HTTP response's [entry]. To have a test
oriented output, you can use [`--test` option]:

```shell
$ hurl --test sample.hurl
```

A particular response can be saved with [`[Options] section`](https://hurl.dev/docs/request.html#options):

```hurl
GET https://example.org/cats/123
[Options]
output: cat123.txt    # use - to output to stdout
HTTP 200

GET https://example.org/dogs/567
HTTP 200
```

Finally, Hurl can take files as input, or directories. In the latter case, Hurl will search files with `.hurl` extension recursively.

```shell
$ hurl --test integration/*.hurl
$ hurl --test .
```

You can check [Hurl tests suite] for more samples.

## Getting Data

A simple GET:

```hurl
GET https://example.org
```

Requests can be chained:

```hurl
GET https://example.org/a
GET https://example.org/b
HEAD https://example.org/c
GET https://example.org/c
```

[Doc](https://hurl.dev/docs/request.html#method)

### HTTP Headers

A simple GET with headers:

```hurl
GET https://example.org/news
User-Agent: Mozilla/5.0 
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
```

[Doc](https://hurl.dev/docs/request.html#headers)

### Query Params

```hurl
GET https://example.org/news
[Query]
order: newest
search: something to search
count: 100
```

Or:

```hurl
GET https://example.org/news?order=newest&search=something%20to%20search&count=100
```

> With `[Query]` section, params don't need to be URL escaped.

[Doc](https://hurl.dev/docs/request.html#query-parameters)

### Basic Authentication

```hurl
GET https://example.org/protected
[BasicAuth]
bob: secret
```

[Doc](https://hurl.dev/docs/request.html#basic-authentication)

This is equivalent to construct the request with a [Authorization] header:

```hurl
# Authorization header value can be computed with `echo -n 'bob:secret' | base64`
GET https://example.org/protected
Authorization: Basic Ym9iOnNlY3JldA== 
```

Basic authentication section allows per request authentication. If you want to add basic authentication to all the
requests of a Hurl file you could use [`-u/--user` option]:

```shell
$ hurl --user bob:secret login.hurl
```

[`--user`] option can also be set per request:

```hurl
GET https://example.org/login
[Options]
user: bob:secret
HTTP 200

GET https://example.org/login
[Options]
user: alice:secret
HTTP 200
```

### Passing Data between Requests 

[Captures] can be used to pass data from one request to another:

```hurl
POST https://sample.org/orders
HTTP 201
[Captures]
order_id: jsonpath "$.order.id"

GET https://sample.org/orders/{{order_id}}
HTTP 200
```

[Doc](https://hurl.dev/docs/capturing-response.html)

## Sending Data

### Sending HTML Form Data

```hurl
POST https://example.org/contact
[Form]
default: false
token: {{token}}
email: john.doe@rookie.org
number: 33611223344
```

[Doc](https://hurl.dev/docs/request.html#form-parameters)

### Sending Multipart Form Data

```hurl
POST https://example.org/upload
[Multipart]
field1: value1
field2: file,example.txt;
# One can specify the file content type:
field3: file,example.zip; application/zip
```

[Doc](https://hurl.dev/docs/request.html#multipart-form-data)

Multipart forms can also be sent with a [multiline string body]:

~~~hurl
POST https://example.org/upload
Content-Type: multipart/form-data; boundary="boundary"
```
--boundary
Content-Disposition: form-data; name="key1"

value1
--boundary
Content-Disposition: form-data; name="upload1"; filename="data.txt"
Content-Type: text/plain

Hello World!
--boundary
Content-Disposition: form-data; name="upload2"; filename="data.html"
Content-Type: text/html

<div>Hello <b>World</b>!</div>
--boundary--
```
~~~

In that case, files have to be inlined in the Hurl file.

[Doc](https://hurl.dev/docs/request.html#multiline-string-body)

### Posting a JSON Body

With an inline JSON:

```hurl
POST https://example.org/api/tests
{
    "id": "456",
    "evaluate": true
}
```

[Doc](https://hurl.dev/docs/request.html#json-body)

With a local file:

```hurl
POST https://example.org/api/tests
Content-Type: application/json
file,data.json;
```

[Doc](https://hurl.dev/docs/request.html#file-body)

### Templating a JSON Body

```hurl
PUT https://example.org/api/hits
Content-Type: application/json
{
    "key0": "{{a_string}}",
    "key1": {{a_bool}},
    "key2": {{a_null}},
    "key3": {{a_number}}
}
```

Variables can be initialized via command line:

```shell
$ hurl --variable a_string=apple \
       --variable a_bool=true \
       --variable a_null=null \
       --variable a_number=42 \
       test.hurl
```

Resulting in a PUT request with the following JSON body:

```
{
    "key0": "apple",
    "key1": true,
    "key2": null,
    "key3": 42
}
```

[Doc](https://hurl.dev/docs/templates.html)

### Templating a XML Body

Using templates with [XML body] is not currently supported in Hurl. You can use templates in
[XML multiline string body] with variables to send a variable XML body:

~~~hurl
POST https://example.org/echo/post/xml
```xml
<?xml version="1.0" encoding="utf-8"?>
<Request>
    <Login>{{login}}</Login>
    <Password>{{password}}</Password>
</Request>
```
~~~

[Doc](https://hurl.dev/docs/request.html#multiline-string-body)

### Using GraphQL Query

A simple GraphQL query:

~~~hurl
POST https://example.org/starwars/graphql
```graphql
{
  human(id: "1000") {
    name
    height(unit: FOOT)
  }
}
```
~~~

A GraphQL query with variables:

~~~hurl
POST https://example.org/starwars/graphql
```graphql
query Hero($episode: Episode, $withFriends: Boolean!) {
  hero(episode: $episode) {
    name
    friends @include(if: $withFriends) {
      name
    }
  }
}

variables {
  "episode": "JEDI",
  "withFriends": false
}
```
~~~

GraphQL queries can also use [Hurl templates].

[Doc](https://hurl.dev/docs/request.html#graphql-query)

### Using Dynamic Datas

[Functions] like `newUuid` and `newDate` can be used in templates to create dynamic datas:


A file that creates a dynamic email (i.e `0531f78f-7f87-44be-a7f2-969a1c4e6d97@test.com`):

```hurl
POST https://example.org/api/foo
{
  "name": "foo",
  "email": "{{newUuid}}@test.com"
}
```

A file that creates a dynamic query parameter (i.e `2024-12-02T10:35:44.461731Z`):

```hurl
GET https://example.org/api/foo
[Query]
date: {{newDate}}
HTTP 200
```

[Doc](https://hurl.dev/docs/templates.html#functions)

## Testing Response

Responses are optional, everything after `HTTP` is part of the response asserts.

```hurl
# A request with (almost) no check:
GET https://foo.com

# A status code check:
GET https://foo.com
HTTP 200

# A test on response body
GET https://foo.com
HTTP 200
[Asserts]
jsonpath "$.state" == "running"
```

### Testing Status Code

```hurl
GET https://example.org/order/435
HTTP 200
```

[Doc](https://hurl.dev/docs/asserting-response.html#version-status)

```hurl
GET https://example.org/order/435
# Testing status code is in a 200-300 range
HTTP *
[Asserts]
status >= 200
status < 300
```

[Doc](https://hurl.dev/docs/asserting-response.html#status-assert)

### Testing Response Headers

Use implicit response asserts to test header values:

```hurl
GET https://example.org/index.html
HTTP 200
Set-Cookie: theme=light
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
```

[Doc](https://hurl.dev/docs/asserting-response.html#headers)


Or use explicit response asserts with [predicates]:

```hurl
GET https://example.org
HTTP 302
[Asserts]
header "Location" contains "www.example.net"
```

[Doc](https://hurl.dev/docs/asserting-response.html#header-assert)

Implicit and explicit asserts can be combined:

```hurl
GET https://example.org/index.html
HTTP 200
Set-Cookie: theme=light
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
[Asserts]
header "Location" contains "www.example.net"
```

### Testing REST APIs

Asserting JSON body response (node values, collection count etc...) with [JSONPath]:

```hurl
GET https://example.org/order
screencapability: low
HTTP 200
[Asserts]
jsonpath "$.validated" == true
jsonpath "$.userInfo" isObject
jsonpath "$.userInfo.firstName" == "Franck"
jsonpath "$.userInfo.lastName" == "Herbert"
jsonpath "$.hasDevice" == false
jsonpath "$.links" count == 12
jsonpath "$.state" != null
jsonpath "$.order" matches "^order-\\d{8}$"
jsonpath "$.order" matches /^order-\d{8}$/  # Alternative syntax with regex literal
jsonpath "$.id" matches /(?i)[a-z]*/        # See syntax for flags <https://docs.rs/regex/latest/regex/#grouping-and-flags>
jsonpath "$.created" isIsoDate
```

[Doc](https://hurl.dev/docs/asserting-response.html#jsonpath-assert)

### Testing HTML Response

```hurl
GET https://example.org
HTTP 200
Content-Type: text/html; charset=UTF-8
[Asserts]
xpath "string(/html/head/title)" contains "Example" # Check title
xpath "count(//p)" == 2  # Check the number of p
xpath "//p" count == 2  # Similar assert for p
xpath "boolean(count(//h2))" == false  # Check there is no h2  
xpath "//h2" not exists  # Similar assert for h2
xpath "string(//div[1])" matches /Hello.*/
```

[Doc](https://hurl.dev/docs/asserting-response.html#xpath-assert)

### Testing Set-Cookie Attributes

```hurl
GET https://example.org/home
HTTP 200
[Asserts]
cookie "JSESSIONID" == "8400BAFE2F66443613DC38AE3D9D6239"
cookie "JSESSIONID[Value]" == "8400BAFE2F66443613DC38AE3D9D6239"
cookie "JSESSIONID[Expires]" contains "Wed, 13 Jan 2021"
cookie "JSESSIONID[Secure]" exists
cookie "JSESSIONID[HttpOnly]" exists
cookie "JSESSIONID[SameSite]" == "Lax"
```

[Doc](https://hurl.dev/docs/asserting-response.html#cookie-assert)

### Testing Bytes Content

Check the SHA-256 response body hash:

```hurl
GET https://example.org/data.tar.gz
HTTP 200
[Asserts]
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
```

[Doc](https://hurl.dev/docs/asserting-response.html#sha-256-assert)

### SSL Certificate

Check the properties of a SSL certificate:

```hurl
GET https://example.org
HTTP 200
[Asserts]
certificate "Subject" == "CN=example.org"
certificate "Issuer" == "C=US, O=Let's Encrypt, CN=R3"
certificate "Expire-Date" daysAfterNow > 15
certificate "Serial-Number" matches /[\da-f]+/
certificate "Subject-Alt-Name" contains "DNS:example.org"
certificate "Subject-Alt-Name" split "," count == 2
certificate "Value" startsWith "-----BEGIN CERTIFICATE-----"
```

[Doc](https://hurl.dev/docs/asserting-response.html#ssl-certificate-assert)

### Checking Full Body

Use implicit body to test an exact JSON body match:

```hurl
GET https://example.org/api/cats/123
HTTP 200
{
  "name" : "Purrsloud",
  "species" : "Cat",
  "favFoods" : ["wet food", "dry food", "<strong>any</strong> food"],
  "birthYear" : 2016,
  "photo" : "https://learnwebcode.github.io/json-example/images/cat-2.jpg"
}
```

[Doc](https://hurl.dev/docs/asserting-response.html#json-body)

Or an explicit assert file:

```hurl
GET https://example.org/index.html
HTTP 200
[Asserts]
body == file,cat.json;
```

[Doc](https://hurl.dev/docs/asserting-response.html#body-assert)

Implicit asserts supports XML body:

```hurl
GET https://example.org/api/catalog
HTTP 200
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications with XML.</description>
   </book>
</catalog>
```

[Doc](https://hurl.dev/docs/asserting-response.html#xml-body)

Plain text:

~~~hurl
GET https://example.org/models
HTTP 200
```
Year,Make,Model,Description,Price
1997,Ford,E350,"ac, abs, moon",3000.00
1999,Chevy,"Venture ""Extended Edition""","",4900.00
1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00
1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00
```
~~~

[Doc](https://hurl.dev/docs/asserting-response.html#multiline-string-body)


One line:

```hurl
POST https://example.org/helloworld
HTTP 200
`Hello world!`
```

[Doc](https://hurl.dev/docs/asserting-response.html#oneline-string-body)

File:

```hurl
GET https://example.org
HTTP 200
file,data.bin;
```

[Doc](https://hurl.dev/docs/asserting-response.html#file-body)

### Testing Redirections

By default, Hurl doesn't follow redirection so each step of a redirect must be run manually and can be analysed:

```hurl
GET https://example.org/step1
HTTP 301
[Asserts]
header "Location" == "https://example.org/step2"


GET https://example.org/step2
HTTP 301
[Asserts]
header "Location" == "https://example.org/step3"


GET https://example.org/step3
HTTP 200
```

[Doc](https://hurl.dev/docs/asserting-response.html)

Using [`--location`] and [`--location-trusted`] (either with command line option or per request), Hurl follows 
redirection and each step of the redirection can be checked.

```hurl
GET https://example.org/step1
[Options]
location: true
HTTP 200
[Asserts]
redirects count == 2
redirects nth 0 location == "https://example.org/step2"
redirects nth 1 location == "https://example.org/step3"
```

```hurl
GET https://example.org/step1
[Options]
location-trusted: true
HTTP 200
[Asserts]
redirects last location == "https://example.org/step2"
```

[Doc](https://hurl.dev/docs/asserting-response.html#redirects-assert)

## Debug Tips

### Verbose Mode

To get more info on a given request/response, use [`[Options]` section](https://hurl.dev/docs/request.html#options):

```hurl
GET https://example.org
HTTP 200

GET https://example.org/api/cats/123
[Options]
very-verbose: true
HTTP 200
```

`--verbose` and `--very-verbose` can be also used globally as command line options.

[Doc](https://hurl.dev/docs/manual.html#very-verbose)

### Error Format

```shell
$ hurl --test --error-format long *.hurl
```

[Doc](https://hurl.dev/docs/manual.html#error-format)

### Output Response Body

Use `--output` on a specific request to get the response body (`-` can be used as standard output):

```hurl
GET https://foo.com/failure
[Options]
# use - to output on standard output, foo.bin to save on disk 
output: -
HTTP 200

GET https://foo.com/success
HTTP 200
```

[Doc](https://hurl.dev/docs/manual.html#output)

### Export curl Commands

```shell
$ hurl ---curl /tmp/curl.txt *.hurl
```

[Doc](https://hurl.dev/docs/manual.html#curl)

### Using Proxy

Use `--proxy` on a specific request or globally as command line option:

```hurl
GET https://foo.com/a
HTTP 200

GET https://foo.com/b
[Options]
proxy: localhost:8888
HTTP 200

GET https://foo.com/c
HTTP 200
```

## Reports

### HTML Report

```shell
$ hurl --test --report-html build/report/ *.hurl
```

[Doc](https://hurl.dev/docs/running-tests.html#generating-report)

### JSON Report

```shell
$ hurl --test --report-json build/report/ *.hurl
```

[Doc](https://hurl.dev/docs/running-tests.html#generating-report)

### JUnit Report

```shell
$ hurl --test --report-junit build/report.xml *.hurl
```

[Doc](https://hurl.dev/docs/running-tests.html#generating-report)

### TAP Report

```shell
$ hurl --test --report-tap build/report.txt *.hurl
```

[Doc](https://hurl.dev/docs/running-tests.html#generating-report)

### JSON Output

A structured output of running Hurl files can be obtained with [`--json` option]. Each file will produce a JSON export of the run.


```shell
$ hurl --json *.hurl
```

## Others

### HTTP Version

Testing HTTP version (HTTP/1.0, HTTP/1.1, HTTP/2 or HTTP/3) can be done using implicit asserts:

```hurl
GET https://foo.com
HTTP/3 200

GET https://bar.com
HTTP/2 200
```

[Doc](https://hurl.dev/docs/asserting-response.html#version-status)

Or explicit:

```hurl
GET https://foo.com
HTTP 200
[Asserts]
version == "3"

GET https://bar.com
HTTP 200
[Asserts]
version == "2"
version toFloat > 1.1
```

[Doc](https://hurl.dev/docs/asserting-response.html#version-assert)

### IP Address

Testing the IP address of the response, as a string. This string may be IPv6 address:

```hurl
GET https://foo.com
HTTP 200
[Asserts]
ip == "2001:0db8:85a3:0000:0000:8a2e:0370:733"
ip startsWith "2001"
ip isIpv6
```

### Polling and Retry

Retry request on any errors (asserts, captures, status code, runtime etc...):

```hurl
# Create a new job
POST https://api.example.org/jobs
HTTP 201
[Captures]
job_id: jsonpath "$.id"
[Asserts]
jsonpath "$.state" == "RUNNING"


# Pull job status until it is completed
GET https://api.example.org/jobs/{{job_id}}
[Options]
retry: 10   # maximum number of retry, -1 for unlimited
retry-interval: 500ms
HTTP 200
[Asserts]
jsonpath "$.state" == "COMPLETED"
```

[Doc](https://hurl.dev/docs/entry.html#retry)

### Delaying Requests

Add delay for every request, or a particular request:

```hurl
# Delaying this request by 5 seconds (aka sleep)
GET https://example.org/turtle
[Options]
delay: 5s
HTTP 200

# No delay!
GET https://example.org/turtle
HTTP 200
```

[Doc](https://hurl.dev/docs/manual.html#delay)

### Skipping Requests

```hurl
# a, c, d are run, b is skipped
GET https://example.org/a

GET https://example.org/b
[Options]
skip: true

GET https://example.org/c

GET https://example.org/d
```

[Doc](https://hurl.dev/docs/manual.html#skip)

### Testing Endpoint Performance

```hurl
GET https://sample.org/helloworld
HTTP *
[Asserts]
duration < 1000   # Check that response time is less than one second
```

[Doc](https://hurl.dev/docs/asserting-response.html#duration-assert)

### Using SOAP APIs

```hurl
POST https://example.org/InStock
Content-Type: application/soap+xml; charset=utf-8
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="https://example.org">
  <soap:Header></soap:Header>
  <soap:Body>
    <m:GetStockPrice>
      <m:StockName>GOOG</m:StockName>
    </m:GetStockPrice>
  </soap:Body>
</soap:Envelope>
HTTP 200
```

[Doc](https://hurl.dev/docs/request.html#xml-body)

### Capturing and Using a CSRF Token

```hurl
GET https://example.org
HTTP 200
[Captures]
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"


POST https://example.org/login?user=toto&password=1234
X-CSRF-TOKEN: {{csrf_token}}
HTTP 302
```

[Doc](https://hurl.dev/docs/capturing-response.html#xpath-capture)

### Redacting Secrets

Using command-line for known values:

```shell
$ hurl --secret token=1234 file.hurl
```

```hurl
POST https://example.org
X-Token: {{token}}
{
  "name": "Alice",
  "value": 100
}
HTTP 200
```

[Doc](https://hurl.dev/docs/templates.html#secrets)

Using `redact` for dynamic values:

```hurl
# Get an authorization token:
GET https://example.org/token
HTTP 200
[Captures]
token: header "X-Token" redact

# Send an authorized request:
POST https://example.org
X-Token: {{token}}
{
  "name": "Alice",
  "value": 100
}
HTTP 200
```

[Doc](https://hurl.dev/docs/capturing-response.html#redacting-secrets)

### Checking Byte Order Mark (BOM) in Response Body

```hurl
GET https://example.org/data.bin
HTTP 200
[Asserts]
bytes startsWith hex,efbbbf;
```

[Doc](https://hurl.dev/docs/asserting-response.html#bytes-assert)

### AWS Signature Version 4 Requests

Generate signed API requests with [AWS Signature Version 4], as used by several cloud providers.

```hurl
POST https://sts.eu-central-1.amazonaws.com/
[Options]
aws-sigv4: aws:amz:eu-central-1:sts
[Form]
Action: GetCallerIdentity
Version: 2011-06-15
```

The Access Key is given per [`--user`], either with command line option or within the [`[Options]`](https://hurl.dev/docs/request.html#options) section:

```hurl
POST https://sts.eu-central-1.amazonaws.com/
[Options]
aws-sigv4: aws:amz:eu-central-1:sts
user: bob=secret
[Form]
Action: GetCallerIdentity
Version: 2011-06-15
```

[Doc](https://hurl.dev/docs/manual.html#aws-sigv4)

### Using curl Options

curl options (for instance [`--resolve`] or [`--connect-to`]) can be used as CLI argument. In this case, they're applicable
to each request of an Hurl file.

```shell
$ hurl --resolve foo.com:8000:127.0.0.1 foo.hurl
```

Use  [`[Options]` section](https://hurl.dev/docs/request.html#options) to configure a specific request:

```hurl
GET http://bar.com
HTTP 200


GET http://foo.com:8000/resolve
[Options]
resolve: foo.com:8000:127.0.0.1
HTTP 200
`Hello World!`
```

[Doc](https://hurl.dev/docs/request.html#options)


# Manual

## Name

hurl - run and test HTTP requests.

## Synopsis

**hurl** [OPTIONS] [FILES...]

**hurl** --test [OPTIONS] [FILES...]

## Description

**Hurl** is a command line tool that runs HTTP requests defined in a simple plain text format.

It can chain requests, capture values and evaluate queries on headers and body response. Hurl is very versatile, it can be used for fetching data and testing HTTP sessions: HTML content, REST / SOAP / GraphQL APIs, or any other XML / JSON based APIs.

```shell
$ hurl session.hurl
```

If no input files are specified, input is read from stdin.

```shell
$ echo GET http://httpbin.org/get | hurl
    {
      "args": {},
      "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip",
        "Content-Length": "0",
        "Host": "httpbin.org",
        "User-Agent": "hurl/0.99.10",
        "X-Amzn-Trace-Id": "Root=1-5eedf4c7-520814d64e2f9249ea44e0"
      },
      "origin": "1.2.3.4",
      "url": "http://httpbin.org/get"
    }
```

Hurl can take files as input, or directories. In the latter case, Hurl will search files with `.hurl` extension recursively.

Output goes to stdout by default. To have output go to a file, use the [`-o, --output`](#output) option:

```shell
$ hurl -o output input.hurl
```

By default, Hurl executes all HTTP requests and outputs the response body of the last HTTP call.

To have a test oriented output, you can use [`--test`](#test) option:

```shell
$ hurl --test *.hurl
```


## Hurl File Format

The Hurl file format is fully documented in [https://hurl.dev/docs/hurl-file.html](https://hurl.dev/docs/hurl-file.html)

It consists of one or several HTTP requests

```hurl
GET http://example.org/endpoint1
GET http://example.org/endpoint2
```


### Capturing values

A value from an HTTP response can be-reused for successive HTTP requests.

A typical example occurs with CSRF tokens.

```hurl
GET https://example.org
HTTP 200
# Capture the CSRF token value from html body.
[Captures]
csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"

# Do the login !
POST https://example.org/login?user=toto&password=1234
X-CSRF-TOKEN: {{csrf_token}}
```

More information on captures can be found here [https://hurl.dev/docs/capturing-response.html](https://hurl.dev/docs/capturing-response.html)

### Asserts

The HTTP response defined in the Hurl file are used to make asserts. Responses are optional.

At the minimum, response includes assert on the HTTP status code.

```hurl
GET http://example.org
HTTP 301
```

It can also include asserts on the response headers

```hurl
GET http://example.org
HTTP 301
Location: http://www.example.org
```

Explicit asserts can be included by combining a query and a predicate

```hurl
GET http://example.org
HTTP 301
[Asserts]
xpath "string(//title)" == "301 Moved"
```

With the addition of asserts, Hurl can be used as a testing tool to run scenarios.

More information on asserts can be found here [https://hurl.dev/docs/asserting-response.html](https://hurl.dev/docs/asserting-response.html)

## Configuration

Options that exist in curl have exactly the same semantics.

Options specified on the command line are defined for every Hurl file's entry, except if they are tagged as cli-only 
(can not be defined in the Hurl request `[Options]` entry)

For instance:

```shell
$ hurl --location foo.hurl
```

will follow redirection for each entry in `foo.hurl`. You can also define an option only for a particular entry with an `[Options]` section. For instance, this Hurl file:

```hurl
GET https://example.org
HTTP 301

GET https://example.org
[Options]
location: true
HTTP 200
```

will follow a redirection only for the second entry.

Hurl looks also for a configuration file at the following places `$XDG_CONFIG_HOME/hurl/config` if `$XDG_CONFIG_HOME` exists,
or `$HOME/.config/hurl/config`. The configuration file is a list of options added to each Hurl run.

```shell
$ cat ~/.config/hurl/config
# Hurl config file
--header x-identifier:quux
--verbose
--delay=1s
--fail-with-body
```

Most of the options can also be defined with environment variables (like `HURL_INSECURE` for [`--insecure`](#insecure)). So, in order
to configure Hurl, there are four sources from the lowest priority (most easily overridden) to highest (overrides all others):

- Configuration file (ex: `~/.config/hurl/config`)
- Environment variables (ex: `export HURL_INSECURE=true`)
- Command-line options (ex: `hurl --insecure`)
- Options section options (ex: `insecure: true` in file)

## All Options

### HTTP options

| Option                                                                                                            | Description                                                                                                                                                                                                                                                                                                                                                                                                                   |
|-------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#aws-sigv4" id="aws-sigv4"><code>--aws-sigv4 &lt;PROVIDER1[:PROVIDER2[:REGION[:SERVICE]]]&gt;</code></a> | Generate an `Authorization` header with an AWS SigV4 signature.<br><br>Use [`-u, --user`](#user) to specify Access Key Id (username) and Secret Key (password).<br><br>To use temporary session credentials (e.g. for an AWS IAM Role), add the `X-Amz-Security-Token` header containing the session token.<br>                                                                                                               |
| <a href="#cacert" id="cacert"><code>--cacert &lt;FILE&gt;</code></a>                                              | Specifies the certificate file for peer verification. The file may contain multiple CA certificates and must be in PEM format.<br>Normally Hurl is built to use a default file for this, so this option is typically used to alter that default file.<br>                                                                                                                                                                     |
| <a href="#cert" id="cert"><code>-E, --cert &lt;CERTIFICATE[:PASSWORD]&gt;</code></a>                              | Client certificate file and password.<br><br>See also [`--key`](#key).<br>                                                                                                                                                                                                                                                                                                                                                    |
| <a href="#compressed" id="compressed"><code>--compressed</code></a>                                               | Request a compressed response using one of the algorithms br, gzip, deflate and automatically decompress the content.<br><br>Environment variables: HURL_COMPRESSED<br>                                                                                                                                                                                                                                                       |
| <a href="#connect-timeout" id="connect-timeout"><code>--connect-timeout &lt;SECONDS&gt;</code></a>                | Maximum time in seconds that you allow Hurl's connection to take.<br><br>You can specify time units in the connect timeout expression. Set Hurl to use a connect timeout of 20 seconds with `--connect-timeout 20s` or set it to 35,000 milliseconds with `--connect-timeout 35000ms`. No spaces allowed.<br><br>See also [`-m, --max-time`](#max-time).<br><br>Environment variables: HURL_CONNECT_TIMEOUT<br>               |
| <a href="#connect-to" id="connect-to"><code>--connect-to &lt;HOST1:PORT1:HOST2:PORT2&gt;</code></a>               | For a request to the given HOST1:PORT1 pair, connect to HOST2:PORT2 instead. This option can be used several times in a command line.<br><br>See also [`--resolve`](#resolve).<br>                                                                                                                                                                                                                                            |
| <a href="#digest" id="digest"><code>--digest</code></a>                                                           | Tell Hurl to use HTTP Digest authentication<br>                                                                                                                                                                                                                                                                                                                                                                               |
| <a href="#header" id="header"><code>-H, --header &lt;NAME:VALUE&gt;</code></a>                                    | Add an extra header to include in information sent. Can be used several times in a command.<br><br>Do not add newlines or carriage returns.<br><br>Environment variables: HURL_HEADER='name1:value1&#124;name2:value2' (headers are separated by &#124;)<br>                                                                                                                                                                  |
| <a href="#http10" id="http10"><code>-0, --http1.0</code></a>                                                      | Tells Hurl to use HTTP version 1.0 instead of using its internally preferred HTTP version.<br><br>Environment variables: HURL_HTTP10<br>                                                                                                                                                                                                                                                                                      |
| <a href="#http11" id="http11"><code>--http1.1</code></a>                                                          | Tells Hurl to use HTTP version 1.1.<br><br>Environment variables: HURL_HTTP11<br>                                                                                                                                                                                                                                                                                                                                             |
| <a href="#http2" id="http2"><code>--http2</code></a>                                                              | Tells Hurl to use HTTP version 2.<br>For HTTPS, this means Hurl negotiates HTTP/2 in the TLS handshake. Hurl does this by default.<br>For HTTP, this means Hurl attempts to upgrade the request to HTTP/2 using the Upgrade: request header.<br><br>Environment variables: HURL_HTTP2<br>                                                                                                                                     |
| <a href="#http2-prior-knowledge" id="http2-prior-knowledge"><code>--http2-prior-knowledge</code></a>              | Tells Hurl to issue a non-TLS HTTP request using HTTP/2 directly without HTTP/1.1 Upgrade. It requires prior knowledge that the server supports HTTP/2 straight away. HTTPS requests still do HTTP/2 the standard way with negotiated protocol versions in the TLS handshake.<br><br>Environment variables: HURL_HTTP2_PRIOR_KNOWLEDGE<br>                                                                                    |
| <a href="#http3" id="http3"><code>--http3</code></a>                                                              | Tells Hurl to try HTTP version 3 to the host in the URL, but fallback to earlier HTTP versions if the HTTP/3 connection establishment fails. HTTP/3 is only available for HTTPS and not for HTTP URLs.<br><br>Environment variables: HURL_HTTP3<br>                                                                                                                                                                           |
| <a href="#insecure" id="insecure"><code>-k, --insecure</code></a>                                                 | This option explicitly allows Hurl to perform "insecure" SSL connections and transfers.<br><br>Environment variables: HURL_INSECURE<br>                                                                                                                                                                                                                                                                                       |
| <a href="#ipv4" id="ipv4"><code>-4, --ipv4</code></a>                                                             | This option tells Hurl to use IPv4 addresses only when resolving host names, and not for example try IPv6.<br><br>Environment variables: HURL_IPV4<br>                                                                                                                                                                                                                                                                        |
| <a href="#ipv6" id="ipv6"><code>-6, --ipv6</code></a>                                                             | This option tells Hurl to use IPv6 addresses only when resolving host names, and not for example try IPv4.<br><br>Environment variables: HURL_IPV6<br>                                                                                                                                                                                                                                                                        |
| <a href="#key" id="key"><code>--key &lt;KEY&gt;</code></a>                                                        | Private key file name.<br>                                                                                                                                                                                                                                                                                                                                                                                                    |
| <a href="#limit-rate" id="limit-rate"><code>--limit-rate &lt;SPEED&gt;</code></a>                                 | Specify the maximum transfer rate you want Hurl to use, for both downloads and uploads. This feature is useful if you have a limited pipe and you would like your transfer not to use your entire bandwidth. To make it slower than it otherwise would be.<br>The given speed is measured in bytes/second.<br><br>Environment variables: HURL_LIMIT_RATE<br>                                                                  |
| <a href="#location" id="location"><code>-L, --location</code></a>                                                 | Follow redirect. To limit the amount of redirects to follow use the [`--max-redirs`](#max-redirs) option<br><br>Environment variables: HURL_LOCATION<br>                                                                                                                                                                                                                                                                      |
| <a href="#location-trusted" id="location-trusted"><code>--location-trusted</code></a>                             | Like [`-L, --location`](#location), but allows sending the name + password to all hosts that the site may redirect to.<br>This may or may not introduce a security breach if the site redirects you to a site to which you send your authentication info (which is plaintext in the case of HTTP Basic authentication).<br><br>Environment variables: HURL_LOCATION_TRUSTED<br>                                               |
| <a href="#max-filesize" id="max-filesize"><code>--max-filesize &lt;BYTES&gt;</code></a>                           | Specify the maximum size in bytes of a file to download. If the file requested is larger than this value, the transfer does not start.<br><br>Environment variables: HURL_MAX_FILESIZE<br><br>This is a cli-only option.<br>                                                                                                                                                                                                  |
| <a href="#max-redirs" id="max-redirs"><code>--max-redirs &lt;NUM&gt;</code></a>                                   | Set maximum number of redirection-followings allowed<br><br>By default, the limit is set to 50 redirections. Set this option to -1 to make it unlimited.<br><br>Environment variables: HURL_MAX_REDIRS<br>                                                                                                                                                                                                                    |
| <a href="#max-time" id="max-time"><code>-m, --max-time &lt;SECONDS&gt;</code></a>                                 | Maximum time in seconds that you allow a request/response to take. This is the standard timeout.<br><br>You can specify time units in the maximum time expression. Set Hurl to use a maximum time of 20 seconds with `--max-time 20s` or set it to 35,000 milliseconds with `--max-time 35000ms`. No spaces allowed.<br><br>See also [`--connect-timeout`](#connect-timeout).<br><br>Environment variables: HURL_MAX_TIME<br> |
| <a href="#negotiate" id="negotiate"><code>--negotiate</code></a>                                                  | Tell Hurl to use Negotiate (SPNEGO) authentication.<br>                                                                                                                                                                                                                                                                                                                                                                       |
| <a href="#no-cookie-store" id="no-cookie-store"><code>--no-cookie-store</code></a>                                | Do not use cookie storage for requests/responses in a file. By default, requests in the same Hurl file share cookie storage, this option deactivates cookie engine.<br><br>Environment variables: HURL_NO_COOKIE_STORE<br><br>This is a cli-only option.<br>                                                                                                                                                                  |
| <a href="#no-header" id="no-header"><code>--no-header &lt;NAME&gt;</code></a>                                     | Remove a header from information sent. Can be used several times in a command.<br><br>Environment variables: HURL_NO_HEADER='name1&#124;name2' (names are separated by &#124;)<br>                                                                                                                                                                                                                                            |
| <a href="#no-proxy" id="no-proxy"><code>--no-proxy &lt;HOST(S)&gt;</code></a>                                     | Comma-separated list of hosts which do not use a proxy.<br><br>Environment variables: no_proxy<br>                                                                                                                                                                                                                                                                                                                            |
| <a href="#ntlm" id="ntlm"><code>--ntlm</code></a>                                                                 | Tell Hurl to use NTLM authentication<br>                                                                                                                                                                                                                                                                                                                                                                                      |
| <a href="#path-as-is" id="path-as-is"><code>--path-as-is</code></a>                                               | Tell Hurl to not handle sequences of /../ or /./ in the given URL path. Normally Hurl will squash or merge them according to standards but with this option set you tell it not to do that.<br>                                                                                                                                                                                                                               |
| <a href="#pinnedpubkey" id="pinnedpubkey"><code>--pinnedpubkey &lt;HASHES&gt;</code></a>                          | When negotiating a TLS or SSL connection, the server sends a certificate indicating its identity. A public key is extracted from this certificate and if it does not exactly match the public key provided to this option, Hurl aborts the connection before sending or receiving any data.<br>                                                                                                                               |
| <a href="#proxy" id="proxy"><code>-x, --proxy &lt;[PROTOCOL://]HOST[:PORT]&gt;</code></a>                         | Use the specified proxy.<br><br>Environment variables: http_proxy https_proxy all_proxy<br>                                                                                                                                                                                                                                                                                                                                   |
| <a href="#proxy-header" id="proxy-header"><code>--proxy-header &lt;HEADER&gt;</code></a>                          | Extra header to include in the request when sending to a proxy. These headers are only applied when a proxy is involved; if Hurl connects directly to the target server, they are ignored.<br><br>Environment variables: HURL_PROXY_HEADER='name1:value1&#124;name2:value2' (headers are separated by &#124;)<br><br>This is a cli-only option.<br>                                                                           |
| <a href="#resolve" id="resolve"><code>--resolve &lt;HOST:PORT:ADDR&gt;</code></a>                                 | Provide a custom address for a specific host and port pair. Using this, you can make the Hurl requests(s) use a specified address and prevent the otherwise normally resolved address to be used. Consider it a sort of /etc/hosts alternative provided on the command line.<br>                                                                                                                                              |
| <a href="#ssl-no-revoke" id="ssl-no-revoke"><code>--ssl-no-revoke</code></a>                                      | (Windows) This option tells Hurl to disable certificate revocation checks. WARNING: this option loosens the SSL security, and by using this flag you ask for exactly that.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                              |
| <a href="#tls-max" id="tls-max"><code>--tls-max &lt;VERSION&gt;</code></a>                                        | Set the maximum allowed TLS version. If the connection is done without TLS, this option has no effect. This includes QUIC-using (HTTP/3) transfers.<br><br>default   Use up to the recommended TLS version.<br>1.0       Use up to TLSv1.0.<br>1.1       Use up to TLSv1.1.<br>1.2       Use up to TLSv1.2.<br>1.3       Use up to TLSv1.3.<br><br>Environment variables: HURL_TLS_MAX<br>                                    |
| <a href="#unix-socket" id="unix-socket"><code>--unix-socket &lt;PATH&gt;</code></a>                               | (HTTP) Connect through this Unix domain socket, instead of using the network.<br>                                                                                                                                                                                                                                                                                                                                             |
| <a href="#user" id="user"><code>-u, --user &lt;USER:PASSWORD&gt;</code></a>                                       | Add basic Authentication header to each request.<br><br>Environment variables: HURL_USER<br>                                                                                                                                                                                                                                                                                                                                  |
| <a href="#user-agent" id="user-agent"><code>-A, --user-agent &lt;NAME&gt;</code></a>                              | Specify the User-Agent string to send to the HTTP server.<br><br>Environment variables: HURL_USER_AGENT<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                 |

### Output options

| Option                                                                                   | Description                                                                                                                                                                                                                                                                                                                                                                                                                           |
|------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#color" id="color"><code>--color</code></a>                                     | Colorize standard output and standard error.<br><br>By default, Hurl outputs a prettified and colorized response. When redirected through pipes, standard streams are not colorized and color can be forced with this option.<br><br>Environment variables: HURL_COLOR<br><br>This is a cli-only option.<br>                                                                                                                          |
| <a href="#curl" id="curl"><code>--curl &lt;FILE&gt;</code></a>                           | Export each request to a list of curl commands.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                                                 |
| <a href="#error-format" id="error-format"><code>--error-format &lt;FORMAT&gt;</code></a> | Control the format of error message (short by default or long).  When using long, the response body is logged when there are errors.<br><br>Environment variables: HURL_ERROR_FORMAT<br><br>This is a cli-only option.<br>                                                                                                                                                                                                            |
| <a href="#fail-with-body" id="fail-with-body"><code>--fail-with-body</code></a>          | Output body response on standard output if there are any errors. By default, Hurl outputs the last body response on standard output only when a run is successful.<br><br>Environment variables: HURL_FAIL_WITH_BODY<br>                                                                                                                                                                                                              |
| <a href="#include" id="include"><code>-i, --include</code></a>                           | Include the HTTP headers in the output<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                                                          |
| <a href="#json" id="json"><code>--json</code></a>                                        | Output each Hurl file result to JSON. The format is very closed to HAR format.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                  |
| <a href="#no-color" id="no-color"><code>--no-color</code></a>                            | Do not colorize standard output nor standard error.<br><br>Environment variables: HURL_NO_COLOR NO_COLOR<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                        |
| <a href="#no-output" id="no-output"><code>--no-output</code></a>                         | Suppress output. By default, Hurl outputs the body of the last response.<br><br>Environment variables: HURL_NO_OUTPUT<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                           |
| <a href="#no-pretty" id="no-pretty"><code>--no-pretty</code></a>                         | Do not prettify response output for supported content type (JSON only for the moment). By default, output is prettified if<br>standard output is a terminal.<br><br>Environment variables: HURL_NO_PRETTY<br><br>This is a cli-only option.<br>                                                                                                                                                                                       |
| <a href="#output" id="output"><code>-o, --output &lt;FILE&gt;</code></a>                 | Write output to FILE instead of stdout. Use '-' for stdout in [Options] sections.<br>                                                                                                                                                                                                                                                                                                                                                 |
| <a href="#pretty" id="pretty"><code>--pretty</code></a>                                  | Prettify response output for supported content type (JSON only for the moment). By default, JSON response is prettified if standard output is a terminal, and colorized, see[`--no-color`](#no-color) to format without color.<br><br>Environment variables: HURL_PRETTY<br><br>This is a cli-only option.<br>                                                                                                                        |
| <a href="#progress-bar" id="progress-bar"><code>--progress-bar</code></a>                | Display a progress bar in test mode. The progress bar is displayed only in interactive TTYs. This option forces the progress bar to be displayed even in non-interactive TTYs.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                  |
| <a href="#verbose" id="verbose"><code>-v, --verbose</code></a>                           | Turn on verbose output on standard error stream.<br>Useful for debugging.<br><br>A line starting with '>' means data sent by Hurl.<br>A line staring with '<' means data received by Hurl.<br>A line starting with '*' means additional info provided by Hurl.<br><br>If you only want HTTP headers in the output, [`-i, --include`](#include) might be the option you're looking for.<br><br>Environment variables: HURL_VERBOSE<br> |
| <a href="#verbosity" id="verbosity"><code>--verbosity &lt;LEVEL&gt;</code></a>           | Set the verbosity level for debug logs on standard error stream (brief, verbose or debug)<br><br>If you only want HTTP headers in the output, [`-i, --include`](#include) might be the option you're looking for.<br>[`-v, --verbose`](#verbose) is an alias for `--verbosity verbose`<br>[`--very-verbose`](#very-verbose) is an alias for `--verbosity debug`<br><br>Environment variables: HURL_VERBOSITY<br>                      |
| <a href="#very-verbose" id="very-verbose"><code>--very-verbose</code></a>                | Turn on more verbose output on standard error stream.<br><br>In contrast to  [`--verbose`](#verbose) option, this option outputs the full HTTP body request and response on standard error. In addition, lines starting with '**' are libcurl debug logs.<br><br>Environment variables: HURL_VERY_VERBOSE<br>                                                                                                                         |

### Run options

| Option                                                                                               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#continue-on-error" id="continue-on-error"><code>--continue-on-error</code></a>             | Continue executing requests to the end of the Hurl file even when an assert error occurs. By default, Hurl exits after an assert error in the HTTP response.<br><br>Note that this option does not affect the behavior with multiple input Hurl files.<br><br>All the input files are executed independently. The result of one file does not affect the execution of the other Hurl files.<br><br>Environment variables: HURL_CONTINUE_ON_ERROR<br><br>This is a cli-only option.<br> |
| <a href="#delay" id="delay"><code>--delay &lt;MILLISECONDS&gt;</code></a>                            | Sets delay before each request (aka sleep). The delay is not applied to requests that have been retried because of [`--retry`](#retry). See [`--retry-interval`](#retry-interval) to space retried requests.<br><br>You can specify time units in the delay expression. Set Hurl to use a delay of 2 seconds with `--delay 2s` or set it to 500 milliseconds with `--delay 500ms`. Supported time units: ms, s, m, h. No spaces allowed.<br><br>Environment variables: HURL_DELAY<br>  |
| <a href="#from-entry" id="from-entry"><code>--from-entry &lt;ENTRY_NUMBER&gt;</code></a>             | Execute Hurl file from ENTRY_NUMBER (starting at 1).<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                                                                                             |
| <a href="#jobs" id="jobs"><code>--jobs &lt;NUM&gt;</code></a>                                        | Maximum number of parallel jobs in parallel mode. Default value corresponds (in most cases) to the current amount of CPUs. Set to 1 to disable parallel execution of files.<br><br>See also [`--parallel`](#parallel).<br><br>Environment variables: HURL_JOBS<br><br>This is a cli-only option.<br>                                                                                                                                                                                   |
| <a href="#no-assert" id="no-assert"><code>--no-assert</code></a>                                     | Ignore all asserts defined in the Hurl file.<br><br>Environment variables: HURL_NO_ASSERT<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                                                        |
| <a href="#no-jsonpath-coercion" id="no-jsonpath-coercion"><code>--no-jsonpath-coercion</code></a>    | Disable JSONPath result coercion.<br><br>By default, when JSONPath coercion is enabled, empty JSONPath results are returned as no value and single JSONPath results are returned as a scalar value. With this option, JSONPath results are always returned as arrays.<br><br>Environment variables: HURL_NO_JSONPATH_COERCION<br>                                                                                                                                                      |
| <a href="#parallel" id="parallel"><code>--parallel</code></a>                                        | Run files in parallel.<br><br>Each Hurl file is executed in its own worker thread, without sharing anything with the other workers. The default run mode is sequential. Parallel execution is by default in [`--test`](#test) mode.<br><br>See also [`--jobs`](#jobs).<br><br>This is a cli-only option.<br>                                                                                                                                                                           |
| <a href="#repeat" id="repeat"><code>--repeat &lt;NUM&gt;</code></a>                                  | Repeat the input files sequence NUM times, -1 for infinite loop. Given a.hurl, b.hurl, c.hurl as input, repeat two<br>times will run a.hurl, b.hurl, c.hurl, a.hurl, b.hurl, c.hurl.<br>                                                                                                                                                                                                                                                                                               |
| <a href="#retry" id="retry"><code>--retry &lt;NUM&gt;</code></a>                                     | Maximum number of retries, 0 for no retries, -1 for unlimited retries. Retry happens if any error occurs (asserts, captures, runtimes etc...).<br><br>Environment variables: HURL_RETRY<br>                                                                                                                                                                                                                                                                                            |
| <a href="#retry-interval" id="retry-interval"><code>--retry-interval &lt;MILLISECONDS&gt;</code></a> | Duration in milliseconds between each retry. Default is 1000 ms.<br><br>You can specify time units in the retry interval expression. Set Hurl to use a retry interval of 2 seconds with `--retry-interval 2s` or set it to 500 milliseconds with `--retry-interval 500ms`. No spaces allowed.<br><br>Environment variables: HURL_RETRY_INTERVAL<br>                                                                                                                                    |
| <a href="#secret" id="secret"><code>--secret &lt;NAME=VALUE&gt;</code></a>                           | Define secret value to be redacted from logs and report. When defined, secrets can be used as variable everywhere variables are used.<br><br>Environment variables: HURL_SECRET_name<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                             |
| <a href="#secrets-file" id="secrets-file"><code>--secrets-file &lt;FILE&gt;</code></a>               | Define a secrets file in which you define your secrets<br><br>Each secret is defined as name=value exactly as with [`--secret`](#secret) option.<br><br>Note that defining a secret twice produces an error.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                     |
| <a href="#test" id="test"><code>--test</code></a>                                                    | Activate test mode: with this, the HTTP response is not outputted anymore, progress is reported for each Hurl file tested, and a text summary is displayed when all files have been run.<br><br>In test mode, files are executed in parallel. To run test in a sequential way use `--jobs 1`.<br><br>See also [`--jobs`](#jobs).<br><br>Environment variables: HURL_TEST<br><br>This is a cli-only option.<br>                                                                         |
| <a href="#to-entry" id="to-entry"><code>--to-entry &lt;ENTRY_NUMBER&gt;</code></a>                   | Execute Hurl file to ENTRY_NUMBER (starting at 1).<br>Ignore the remaining of the file. It is useful for debugging a session.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                    |
| <a href="#variable" id="variable"><code>--variable &lt;NAME=VALUE&gt;</code></a>                     | Define variable (name/value) to be used in Hurl templates.<br><br>Environment variables: HURL_VARIABLE_name<br>                                                                                                                                                                                                                                                                                                                                                                        |
| <a href="#variables-file" id="variables-file"><code>--variables-file &lt;FILE&gt;</code></a>         | Set properties file in which your define your variables.<br><br>Each variable is defined as name=value exactly as with [`--variable`](#variable) option.<br><br>Note that defining a variable twice produces an error.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                           |

### Report options

| Option                                                                                 | Description                                                                                                                                                |
|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#report-html" id="report-html"><code>--report-html &lt;DIR&gt;</code></a>     | Generate HTML report in DIR.<br><br>If the HTML report already exists, it will be updated with the new test results.<br><br>This is a cli-only option.<br> |
| <a href="#report-json" id="report-json"><code>--report-json &lt;DIR&gt;</code></a>     | Generate JSON report in DIR.<br><br>If the JSON report already exists, it will be updated with the new test results.<br><br>This is a cli-only option.<br> |
| <a href="#report-junit" id="report-junit"><code>--report-junit &lt;FILE&gt;</code></a> | Generate JUnit File.<br><br>If the FILE report already exists, it will be updated with the new test results.<br><br>This is a cli-only option.<br>         |
| <a href="#report-tap" id="report-tap"><code>--report-tap &lt;FILE&gt;</code></a>       | Generate TAP report.<br><br>If the FILE report already exists, it will be updated with the new test results.<br><br>This is a cli-only option.<br>         |

### Other options

| Option                                                                               | Description                                                                                                                                                                                                                                                                                                                                                         |
|--------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#cookie" id="cookie"><code>-b, --cookie &lt;FILE&gt;</code></a>             | Read cookies from FILE (using the Netscape cookie file format).<br><br>Combined with [`-c, --cookie-jar`](#cookie-jar), you can simulate a cookie storage between successive Hurl runs.<br><br>This is a cli-only option.<br>                                                                                                                                       |
| <a href="#cookie-jar" id="cookie-jar"><code>-c, --cookie-jar &lt;FILE&gt;</code></a> | Write cookies to FILE after running the session.<br>The file will be written using the Netscape cookie file format.<br><br>Combined with [`-b, --cookie`](#cookie), you can simulate a cookie storage between successive Hurl runs.<br><br>This is a cli-only option.<br>                                                                                           |
| <a href="#file-root" id="file-root"><code>--file-root &lt;DIR&gt;</code></a>         | Set root directory to import files in Hurl. This is used for files in multipart form data, request body and response output.<br>When it is not explicitly defined, files are relative to the Hurl file's directory.<br><br>This is a cli-only option.<br>                                                                                                           |
| <a href="#glob" id="glob"><code>--glob &lt;GLOB&gt;</code></a>                       | Specify input files that match the given glob pattern.<br><br>Multiple glob flags may be used. This flag supports common Unix glob patterns like *, ? and [].<br>However, to avoid your shell accidentally expanding glob patterns before Hurl handles them, you must use single quotes or double quotes around each pattern.<br><br>This is a cli-only option.<br> |
| <a href="#netrc" id="netrc"><code>-n, --netrc</code></a>                             | Scan the .netrc file in the user's home directory for the username and password.<br><br>See also [`--netrc-file`](#netrc-file) and [`--netrc-optional`](#netrc-optional).<br>                                                                                                                                                                                       |
| <a href="#netrc-file" id="netrc-file"><code>--netrc-file &lt;FILE&gt;</code></a>     | Like [`--netrc`](#netrc), but provide the path to the netrc file.<br><br>See also [`--netrc-optional`](#netrc-optional).<br>                                                                                                                                                                                                                                        |
| <a href="#netrc-optional" id="netrc-optional"><code>--netrc-optional</code></a>      | Similar to [`--netrc`](#netrc), but make the .netrc usage optional.<br><br>See also [`--netrc-file`](#netrc-file).<br>                                                                                                                                                                                                                                              |
| <a href="#help" id="help"><code>-h, --help</code></a>                                | Usage help. This lists all current command line options with a short description.<br>                                                                                                                                                                                                                                                                               |
| <a href="#version" id="version"><code>-V, --version</code></a>                       | Prints version information<br>                                                                                                                                                                                                                                                                                                                                      |

## Exit Codes

| Value | Description                                             |
|-------|---------------------------------------------------------|
| `0`   | Success.<br>                                            |
| `1`   | Failed to parse command-line options.<br>               |
| `2`   | Input file parsing error.<br>                           |
| `3`   | Runtime error (such as failure to connect to host).<br> |
| `4`   | Assert error.<br>                                       |

## WWW

[https://hurl.dev](https://hurl.dev)


## See Also

curl(1)  hurlfmt(1)

# Installation

## Binaries Installation

### Linux

Precompiled binary (depending on libc >=2.35) is available at [Hurl latest GitHub release]:

```shell
$ INSTALL_DIR=/tmp
$ VERSION=8.0.1
$ curl --silent --location https://github.com/Orange-OpenSource/hurl/releases/download/$VERSION/hurl-$VERSION-x86_64-unknown-linux-gnu.tar.gz | tar xvz -C $INSTALL_DIR
$ export PATH=$INSTALL_DIR/hurl-$VERSION-x86_64-unknown-linux-gnu/bin:$PATH
```

#### Debian / Ubuntu

For Debian >=12 / Ubuntu 22.04 and 24.04, Hurl can be installed using a binary .deb file provided in each Hurl release.

```shell
$ VERSION=8.0.1
$ curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/$VERSION/hurl_${VERSION}_amd64.deb
$ sudo apt update && sudo apt install ./hurl_${VERSION}_amd64.deb
```

For Ubuntu >=22.04, Hurl can be installed from `ppa:lepapareil/hurl`

```shell
$ VERSION=8.0.1
$ sudo apt-add-repository -y ppa:lepapareil/hurl
$ sudo apt install hurl="${VERSION}"*
```

#### Alpine

Hurl is available on `testing` channel.

```shell
$ apk add --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing hurl
```

#### Arch Linux / Manjaro

Hurl is available on [extra] channel.

```shell
$ pacman -Sy hurl
```

#### NixOS / Nix

[NixOS / Nix package] is available on stable channel.

#### Guix

```shell
$ guix install hurl
```

### macOS

Precompiled binaries for Intel and ARM CPUs are available at [Hurl latest GitHub release].

#### Homebrew

```shell
$ brew install hurl
```

#### MacPorts

```shell
$ sudo port install hurl
```

### FreeBSD

```shell
$ sudo pkg install hurl
```

### Windows

Windows requires the [Visual C++ Redistributable Package] to be installed manually, as this is not included in the installer.

#### Zip File

Hurl can be installed from a standalone zip file at [Hurl latest GitHub release]. You will need to update your `PATH` variable.

#### Installer

An executable installer is also available at [Hurl latest GitHub release].

#### Chocolatey

```shell
$ choco install hurl
```

#### Scoop

```shell
$ scoop install hurl
```

#### Windows Package Manager

```shell
$ winget install hurl
```

### Cargo

If you're a Rust programmer, Hurl can be installed with cargo.

```shell
$ cargo install --locked hurl
```

### conda-forge

```shell
$ conda install -c conda-forge hurl
```

Hurl can also be installed with [`conda-forge`] powered package manager like [`pixi`].

### Docker

```shell
$ docker pull ghcr.io/orange-opensource/hurl:latest
```

### npm

```shell
$ npm install --save-dev @orangeopensource/hurl
```

## Building From Sources

Hurl sources are available in [GitHub].

### Build on Linux

Hurl depends on libssl, libcurl and libxml2 native libraries. You will need their development files in your platform.

#### Debian based distributions

```shell
$ apt install build-essential pkg-config libssl-dev libcurl4-openssl-dev libxml2-dev libclang-dev
```

#### Fedora based distributions

```shell
$ dnf install pkgconf-pkg-config gcc openssl-devel libxml2-devel clang-devel
```

#### Red Hat based distributions

```shell
$ yum install pkg-config gcc openssl-devel libxml2-devel clang-devel
```

#### Arch based distributions

```shell
$ pacman -S pkgconf gcc glibc openssl libxml2 clang
```

#### Alpine based distributions

```shell
$ apk add curl-dev gcc libxml2-dev musl-dev openssl-dev clang-dev
```

### Build on macOS

```shell
$ xcode-select --install
$ brew install pkg-config openssl
```

Hurl is written in [Rust]. You should [install] the latest stable release.

```shell
$ curl https://sh.rustup.rs -sSf | sh -s -- -y
$ source $HOME/.cargo/env
$ rustc --version
$ cargo --version
```

Then build hurl:

```shell
$ git clone https://github.com/Orange-OpenSource/hurl
$ cd hurl
$ cargo build --release
$ ./target/release/hurl --version
```

### Build on Windows

Please follow the [contrib on Windows section].

[XPath]: https://en.wikipedia.org/wiki/XPath
[JSONPath]: https://goessner.net/articles/JsonPath/
[Rust]: https://www.rust-lang.org
[curl]: https://curl.se
[the installation section]: https://hurl.dev/docs/installation.html
[Feedback, suggestion, bugs or improvements]: https://github.com/Orange-OpenSource/hurl/issues
[License]: https://hurl.dev/docs/license.html
[Tutorial]: https://hurl.dev/docs/tutorial/your-first-hurl-file.html
[Documentation]: https://hurl.dev/docs/installation.html
[Blog]: https://hurl.dev/blog/
[GitHub]: https://github.com/Orange-OpenSource/hurl
[libcurl]: https://curl.se/libcurl/
[star Hurl on GitHub]: https://github.com/Orange-OpenSource/hurl/stargazers
[HTML]: https://hurl.dev/assets/docs/hurl-8.0.0.html.gz
[PDF]: https://hurl.dev/assets/docs/hurl-8.0.0.pdf.gz
[Markdown]: https://hurl.dev/assets/docs/hurl-8.0.0.md.gz
[JSON body]: https://hurl.dev/docs/request.html#json-body
[XML body]: https://hurl.dev/docs/request.html#xml-body
[XML multiline string body]: https://hurl.dev/docs/request.html#multiline-string-body
[multiline string body]: https://hurl.dev/docs/request.html#multiline-string-body
[predicates]: https://hurl.dev/docs/asserting-response.html#predicates
[JSONPath]: https://goessner.net/articles/JsonPath/
[Basic authentication]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme
[`Authorization` header]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
[Hurl tests suite]: https://github.com/Orange-OpenSource/hurl/tree/master/integration/hurl/tests_ok
[Authorization]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
[`-u/--user` option]: https://hurl.dev/docs/manual.html#user
[curl]: https://curl.se
[entry]: https://hurl.dev/docs/entry.html
[`--test` option]: https://hurl.dev/docs/manual.html#test
[`--user`]: https://hurl.dev/docs/manual.html#user
[Hurl templates]: https://hurl.dev/docs/templates.html
[AWS Signature Version 4]: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
[Captures]: https://hurl.dev/docs/capturing-response.html
[`--json` option]: https://hurl.dev/docs/manual.html#json
[`--resolve`]: https://hurl.dev/docs/manual.html#resolve
[`--connect-to`]: https://hurl.dev/docs/manual.html#connect-to
[Functions]: https://hurl.dev/docs/templates.html#functions
[`--location`]: https://hurl.dev/docs/manual.html#location
[`--location-trusted`]: https://hurl.dev/docs/manual.html#location-trusted
[GitHub]: https://github.com/Orange-OpenSource/hurl
[Hurl latest GitHub release]: https://github.com/Orange-OpenSource/hurl/releases/latest
[Visual C++ Redistributable Package]: https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version
[install]: https://www.rust-lang.org/tools/install
[Rust]: https://www.rust-lang.org
[contrib on Windows section]: https://github.com/Orange-OpenSource/hurl/blob/master/contrib/windows/README.md
[NixOS / Nix package]: https://search.nixos.org/packages?from=0&size=1&sort=relevance&type=packages&query=hurl
[`conda-forge`]: https://conda-forge.org
[`pixi`]: https://prefix.dev
[extra]: https://archlinux.org/packages/extra/x86_64/hurl/

---

### Overview (`packages/hurl_core/README.md`)

hurl_core
===============

The hurl_core crate provides the common functionalities used by both hurl and hurlfmt.

---

### Overview (`packages/hurlfmt/README.md`)

hurlfmt
=====================================

The hurlfmt crate provides the `hurlfmt` binary.
It can format hurl files and to export them to JSON/HTML.

---

### Overview (`contrib/npm/hurl/README.md`)

# Hurl

Hurl is a command line tool written in Rust that runs <b>HTTP requests</b> defined in a simple <b>plain text format</b>.

The `@orangeopensource/hurl` package allows JavaScript developers to use Hurl in npm scripts.

It can chain requests, capture values and evaluate queries on headers and body response. Hurl is very
versatile, it can be used for <b>fetching data</b> and <b>testing HTTP</b> sessions: <b>HTML</b> content, <b>REST / SOAP / GraphQL</b> APIs, or any other <b>XML / JSON</b> based APIs.


```hurl
# Get home:
GET https://example.net
HTTP 200
[Captures]
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"


# Do login!
POST https://example.net/login?user=toto&password=1234
X-CSRF-TOKEN: {{csrf_token}}
HTTP 302
```

Hurl can run HTTP requests but can also be used to <b>test HTTP responses</b>.
Different types of queries and predicates are supported, from [XPath](https://en.wikipedia.org/wiki/XPath) and 
[JSONPath](https://goessner.net/articles/JsonPath/) on body response, to assert on status code and response headers.

It is well adapted for <b>REST / JSON APIs</b>

```hurl
POST https://example.org/api/tests
{
    "id": "4568",
    "evaluate": true
}
HTTP 200
[Asserts]
header "X-Frame-Options" == "SAMEORIGIN"
jsonpath "$.status" == "RUNNING"    # Check the status code
jsonpath "$.tests" count == 25      # Check the number of items
jsonpath "$.id" matches /\d{4}/     # Check the format of the id
```

<b>HTML content</b>

```hurl
GET https://example.org
HTTP 200
[Asserts]
xpath "normalize-space(//head/title)" == "Hello world!"
```

<b>GraphQL</b>

~~~hurl
POST https://example.org/graphql
```graphql
{
  human(id: "1000") {
    name
    height(unit: FOOT)
  }
}
```
HTTP 200
~~~

and even <b>SOAP APIs</b>

```hurl
POST https://example.org/InStock
Content-Type: application/soap+xml; charset=utf-8
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="https://example.org">
  <soap:Header></soap:Header>
  <soap:Body>
    <m:GetStockPrice>
      <m:StockName>GOOG</m:StockName>
    </m:GetStockPrice>
  </soap:Body>
</soap:Envelope>
HTTP 200
```

## Installation

```
npm install --save-dev @orangeopensource/hurl
```

This will download the appropriate Hurl binaries for your platform. `hurlmft` binary is also installed, which 
you can use for [exporting Hurl files to JSON files](https://hurl.dev/docs/frequently-asked-questions.html#how-can-i-use-my-hurl-files-outside-hurl). 


## Usage

In your `package.json` file:

```
{
  "name": "sample-app",
  "scripts": {
    "test": "hurl --test --glob test/*.hurl",
    ...
  },
  ...
```



## Documentation

See <https://hurl.dev>

## Samples

See <https://hurl.dev/docs/samples.html>

---

### Overview (`docs/spec/grammar/README.md`)

This grammar can be validated and converted to HTML with the cli from
https://github.com/fabricereix/grammar

Validate and generate HTML

```shell
$ ./generate_html.sh
```

---

### Overview (`docs/spec/options/README.md`)

# Command Line Options

Hurl command line options are described with `.option` files. These files are used to generate:

- Rust code to parse this options in `hurl`/`hurlfmt` packages
- Man options


## Format all option files

```shell
$ bin/spec/options/format.py docs/spec/options/**/*.option
```

This script insures that all `.option` files are well formatted.

## Generate/Update clap command source file

```shell
$ bin/spec/options/generate_source.py docs/spec/options/hurl/*.option > packages/hurl/src/cli/options/commands.rs
$ bin/spec/options/generate_source.py docs/spec/options/hurlfmt/*.option >packages/hurlfmt/src/cli/options/commands.rs
```

This script generates Rust source file for parsing command line option.

## Generate/Update man options

```shell
$ bin/spec/options/generate_man.py docs/spec/options/hurl/*.option
$ bin/spec/options/generate_man.py docs/spec/options/hurlfmt/*.option
```

This script generates (part of) man file for `hurl` / `hurlfmt`.

A script is provided to run all these commands:

```shell
$ bin/spec/options/generate_all.py
```

---

### Overview (`contrib/windows/windows_package_managers/chocolatey/README.md`)

# how to manage hurl chocolatey package

Get latest released version

```
$hurl_latest_version=((Invoke-WebRequest -Headers @{'Authorisation' = '<github token>'} -UseBasicParsing https://api.github.com/repos/Orange-OpenSource/hurl/releases/latest).content | ConvertFrom-Json | Select -exp tag_name)
echo ${hurl_latest_version}
```

Get latest released hurl-x.y.z-x86_64-pc-windows-msvc.zip file's sha256 sum

```
Invoke-WebRequest -UseBasicParsing https://github.com/Orange-OpenSource/hurl/releases/download/${hurl_latest_version}/hurl-${hurl_latest_version}-x86_64-pc-windows-msvc.zip -OutFile C:\Windows\Temp\hurl-latest-win64.zip
$hurl_latest_sha=(Get-FileHash C:\Windows\Temp\hurl-latest-win64.zip).Hash
echo ${hurl_latest_sha}
```

Update choco package files with the latest released version and sha256 sum

```
(Get-Content -Path hurl.nuspec) | foreach{$_.replace('${hurl_latest_version}',${hurl_latest_version})} | Set-Content hurl.nuspec
(Get-Content -Path tools\chocolateyinstall.ps1) | foreach{$_.replace('${hurl_latest_version}',${hurl_latest_version})} | Set-Content tools\chocolateyinstall.ps1
(Get-Content -Path tools\chocolateyinstall.ps1) | foreach{$_.replace('${hurl_latest_sha}',${hurl_latest_sha})} | Set-Content tools\chocolateyinstall.ps1
```

Execute local installer:

```
choco pack
choco install hurl -s .
hurl --version
echo "GET https://google.fr" | hurl --location
```

And finally push package to official chocolatey repository

```
choco apikey -k <choco api key> --source https://push.chocolatey.org/
choco push --source https://push.chocolatey.org/
```

---

### Overview (`contrib/windows/windows_package_managers/scoop/README.md`)

Official Hurl bucket URL [#289](https://github.com/Orange-OpenSource/hurl/issues/289) :
- https://github.com/ScoopInstaller/Main/blob/master/bucket/hurl.json

Update manifest command:
- The update is automatically committed by scoop scheduled GitHub Actions.

---

### Overview (`contrib/windows/windows_package_managers/winget/README.md`)

Official hurl manifest URL:

- https://github.com/microsoft/winget-pkgs/tree/master/manifests/o/Orange-OpenSource/Hurl/

Update manifest command:
 
```
$hurl_latest_version=((Invoke-WebRequest -UseBasicParsing https://api.github.com/repos/Orange-OpenSource/hurl/releases/latest).content | ConvertFrom-Json | Select -exp tag_name)
echo ${hurl_latest_version}
wingetcreate update --submit --token <personal_github_token> --urls https://github.com/Orange-OpenSource/hurl/releases/download/${hurl_latest_version}/hurl-${hurl_latest_version}-x86_64-pc-windows-msvc-installer.exe --version ${hurl_latest_version} Orange-OpenSource.Hurl
```

---

### Index (`docs/index.md`)

# Documentation

## [Getting Started]

## [File Format]

## [Tutorial]

## [Resources]


[Getting Started]: /docs/manual.md
[File Format]: /docs/hurl-file.md
[Tutorial]: /docs/tutorial/your-first-hurl-file.md
[Resources]: /docs/license.md

---

### Tutorial Index (`docs/tutorial/index.md`)

# Tutorial

1. [Your First Hurl File](/docs/tutorial/your-first-hurl-file.md)
2. [Adding Asserts](/docs/tutorial/adding-asserts.md)
3. [Chaining Requests](/docs/tutorial/chaining-requests.md)
4. [Debug Tips](/docs/tutorial/debug-tips.md)
5. [Captures](/docs/tutorial/captures.md)
6. [Security](/docs/tutorial/security.md)
7. [CI/CD Integration](/docs/tutorial/ci-cd-integration.md)

---

### Asserting Response (`docs/asserting-response.md`)

# Asserting Response

## Asserts

Asserts are used to test various properties of an HTTP response. Asserts can be implicits (such as version, status, 
headers) or explicit within an `[Asserts]` section. The delimiter of the request / response is `HTTP <STATUS-CODE>`: 
after this delimiter, you'll find the implicit asserts, then an `[Asserts]` section with all the explicit checks.

```hurl
GET https://example.org/api/cats
HTTP 200
# Implicit assert on `Content-Type` Header
Content-Type: application/json; charset=utf-8 
[Asserts]
# Explicit asserts section 
bytes count == 120
header "Content-Type" contains "utf-8"
jsonpath "$.cats" count == 49
jsonpath "$.cats[0].name" == "Felix"
jsonpath "$.cats[0].lives" == 9
```

Body responses can be encoded by server (see [`Content-Encoding` HTTP header][content-encoding]) but asserts in Hurl files are not 
affected by this content compression. All body asserts (`body`, `bytes`, `sha256` etc...) except `rawbytes` work _after_ content decoding.

Finally, body text asserts (`body`, `jsonpath`, `xpath` etc...) are also decoded to strings based on [`Content-Type` header] 
so these asserts can be written with usual strings. 

### Structure

The asserts order in a Hurl file is:

- [implicit asserts on version and status](#version-status)
- [implicit asserts on headers](#headers)
- [explicit asserts](#explicit-asserts)
- [implicit assert on body](#body)

<div class="hurl-structure-schema">
  <div class="hurl-structure">
    <div class="hurl-structure-col-0">
        <div class="hurl-part-0">
            HTTP 200
        </div>
        <div class=" hurl-part-1">
            content-length: 206<br>accept-ranges: bytes<br>user-agent: Test
        </div>
        <div class="hurl-part-2">
            [Captures]<br>...
        </div>
        <div class="hurl-part-2">
            [Asserts]<br>...
        </div>
        <div class="hurl-part-3">
            {<br>
            &nbsp;&nbsp;"type": "FOO",<br>
            &nbsp;&nbsp;"value": 356789,<br>
            &nbsp;&nbsp;"ordered": true,<br>
            &nbsp;&nbsp;"index": 10<br>
            }
        </div>
    </div>
    <div class="hurl-structure-col-1">
        <div class="hurl-request-explanation-part-0">
            <a href="/docs/asserting-response.html#version-status">Version and status (mandatory if response present)</a>
        </div>
        <div class="hurl-request-explanation-part-1">
            <br><a href="/docs/asserting-response.html#headers">HTTP response headers</a> (optional)
        </div>
        <div class="hurl-request-explanation-part-2">
            <br>
            <br>
        </div>
        <div class="hurl-request-explanation-part-2">
            <a href="/docs/capturing-response.html">Captures</a> and <a href="/docs/asserting-response.html#explicit-asserts">explicit asserts</a> (optional sections, unordered)
        </div>
        <div class="hurl-request-explanation-part-2">
          <br>
          <br>
          <br>
          <br>
        </div>
        <div class="hurl-request-explanation-part-3">
            <a href="/docs/asserting-response.html#body">HTTP response body</a> (optional)
        </div>
    </div>
</div>
</div>


## Implicit asserts

### Version - Status

Expected protocol version and status code of the HTTP response.

Protocol version is one of `HTTP/1.0`, `HTTP/1.1`, `HTTP/2`, `HTTP/3` or
`HTTP`; `HTTP` describes any version. Note that there are no status text following the status code.

```hurl
GET https://example.org/404.html
HTTP 404
```

Wildcard keywords `HTTP` and `*` can be used to disable tests on protocol version and status:

```hurl
GET https://example.org/api/pets
HTTP *
# Check that response status code is > 400 and <= 500
[Asserts]
status > 400
status <= 500
```

While `HTTP/1.0`, `HTTP/1.1`, `HTTP/2` and `HTTP/3` explicitly check HTTP version:

```hurl
# Check that our server responds with HTTP/2
GET https://example.org/api/pets
HTTP/2 200 
```

### Headers

Optional list of the expected HTTP response headers that must be in the received response.

A header consists of a name, followed by a `:` and a value.

For each expected header, the received response headers are checked. If the received header is not equal to the 
expected, or not present, an error is raised. The comparison is case-insensitive for the name: expecting a 
`Content-Type` header is equivalent to a `content-type` one. Note that the expected headers list is not fully 
descriptive: headers present in the response and not in the expected list doesn't raise error.

```hurl
# Check that user toto is redirected to home after login.
POST https://example.org/login
[Form]
user: toto
password: 12345678
HTTP 302
Location: https://example.org/home
```

> Quotes in the header value are part of the value itself.
>
> This is used by the [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) Header
> ```
> ETag: W/"<etag_value>"
> ETag: "<etag_value>"
> ```

Testing duplicated headers is also possible.

For example with the `Set-Cookie` header:

```
Set-Cookie: theme=light
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
```

You can either test the two header values:

```hurl
GET https://example.org/index.html
Host: example.net
HTTP 200
Set-Cookie: theme=light
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
```

Or only one:

```hurl
GET https://example.org/index.html 
Host: example.net
HTTP 200
Set-Cookie: theme=light
```

If you want to test specifically the number of headers returned for a given header name, or if you want to test header 
value with [predicates] (like `startsWith`, `contains`, `exists`)you can use the explicit [header assert].

### Body

Optional assertion on the received HTTP response body. Body section can be seen as syntactic sugar over [body asserts]
(with `==` predicate). If the body of the response is a [JSON] string or a [XML] string, the body assertion can be 
directly inserted without any modification. For a text based body that is neither JSON nor XML, one can use multiline
string that starts with <code>&#96;&#96;&#96;</code> and ends with <code>&#96;&#96;&#96;</code>. For a precise byte
control of the response body, a [Base64] encoded string or an input file can be used to describe exactly the body byte
content to check.

Like explicit [`body` assert], the body section is automatically decompressed based on the value of `Content-Encoding`
response header. So, whatever is the response compression (`gzip`, `brotli`, etc...) body section doesn't depend on
the content encoding. For textual body sections (JSON, XML, multiline, etc...), content is also decoded to string, based
on the value of `Content-Type` response header.

#### JSON body

```hurl
# Get a doggy thing:
GET https://example.org/api/dogs/{{dog-id}}
HTTP 200
{
    "id": 0,
    "name": "Frieda",
    "picture": "images/scottish-terrier.jpeg",
    "age": 3,
    "breed": "Scottish Terrier",
    "location": "Lisco, Alabama"
}
```

JSON response body can be seen as syntactic sugar of [multiline string body] with `json` identifier:

~~~hurl
# Get a doggy thing:
GET https://example.org/api/dogs/{{dog-id}}
HTTP 200
```json
{
    "id": 0,
    "name": "Frieda",
    "picture": "images/scottish-terrier.jpeg",
    "age": 3,
    "breed": "Scottish Terrier",
    "location": "Lisco, Alabama"
}
```
~~~

#### XML body

~~~hurl
GET https://example.org/api/catalog
HTTP 200
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications with XML.</description>
   </book>
</catalog>
~~~

XML response body can be seen as syntactic sugar of [multiline string body] with `xml` identifier:

~~~hurl
GET https://example.org/api/catalog
HTTP 200
```xml
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications with XML.</description>
   </book>
</catalog>
```
~~~

#### Multiline string body

~~~hurl
GET https://example.org/models
HTTP 200
```
Year,Make,Model,Description,Price
1997,Ford,E350,"ac, abs, moon",3000.00
1999,Chevy,"Venture ""Extended Edition""","",4900.00
1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00
1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00
```
~~~

The standard usage of a multiline string is :

~~~
```
line1
line2
line3
```
~~~

##### Oneline string body

For text based response body that do not contain newlines, one can use oneline string, started and ending with <code>&#96;</code>.

~~~hurl
POST https://example.org/helloworld
HTTP 200
`Hello world!`
~~~

#### Base64 body

Base64 response body assert starts with `base64,` and end with `;`. MIME's Base64 encoding is supported (newlines and
white spaces may be present anywhere but are to be ignored on decoding), and `=` padding characters might be added.

```hurl
GET https://example.org
HTTP 200
base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIG
FkaXBpc2NpbmcgZWxpdC4gSW4gbWFsZXN1YWRhLCBuaXNsIHZlbCBkaWN0dW0g
aGVuZHJlcml0LCBlc3QganVzdG8gYmliZW5kdW0gbWV0dXMsIG5lYyBydXRydW
0gdG9ydG9yIG1hc3NhIGlkIG1ldHVzLiA=;
```

#### File body

To use the binary content of a local file as the body response assert, file body
can be used. File body starts with `file,` and ends with `;``

```hurl
GET https://example.org
HTTP 200
file,data.bin;
```

File are relative to the input Hurl file, and cannot contain implicit parent directory (`..`). You can use [`--file-root` option] 
to specify the root directory of all file nodes.

## Explicit asserts

Optional list of assertions on the HTTP response within an `[Asserts]` section. Assertions can describe checks
on status code, on the received body (or part of it) and on response headers.

__Structure of an explicit assert:__

<div class="schema-container schema-container u-font-size-1 u-font-size-2-sm u-font-size-3-md">
 <div class="schema">
   <span class="schema-token schema-color-2">jsonpath "$.book"<span class="schema-label">query</span></span>
   <span class="schema-token schema-color-1">contains<span class="schema-label">predicate type</span></span>
   <span class="schema-token schema-color-3">"Dune"<span class="schema-label">predicate value</span></span>
 </div>
</div>

<div class="schema-container schema-container u-font-size-1 u-font-size-2-sm u-font-size-3-md">
 <div class="schema">
   <span class="schema-token schema-color-2">body<span class="schema-label">query</span></span>
   <span class="schema-token schema-color-1">matches<span class="schema-label">predicate type</span></span>
   <span class="schema-token schema-color-3">/\d{4}-\d{2}-\d{2}/<span class="schema-label">predicate value</span></span>
 </div>
</div>


An assert consists of a query followed by a predicate. The format of the query is shared with [captures], and queries 
can extract data from

- status line:
  - [`status`](#status-assert)
  - [`version`](#version-assert)
- headers:
  - [`header`](#header-assert)
  - [`cookie`](#cookie-assert)
- body:
  - [`body`](#body-assert)
  - [`bytes`](#bytes-assert)
  - [`rawbytes`](#rawbytes-assert)
  - [`xpath`](#xpath-assert)
  - [`jsonpath`](#jsonpath-assert)
  - [`regex`](#regex-assert)
  - [`sha256`](#sha-256-assert)
  - [`md5`](#md5-assert)
- others:
  - [`url`](#url-assert)
  - [`redirects`](#redirects-assert)
  - [`ip`](#ip-address-assert)
  - [`variable`](#variable-assert)
  - [`duration`](#duration-assert)
  - [`certificate`](#ssl-certificate-assert)

Queries, in asserts and in captures, can be refined with [filters], like [`count`][count] to add tests on collections
sizes.

### Predicates

Predicates consist of a predicate function and a predicate value. Predicate functions are:

| Predicate        | Description                                                                                                                                                                                                                 | Example                                                                                                            | 
|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|
| __`==`__         | Query and predicate value are equal                                                                                                                                                                                         | `jsonpath "$.book" == "Dune"`                                                                                      |
| __`!=`__         | Query and predicate value are different                                                                                                                                                                                     | `jsonpath "$.color" != "red"`                                                                                      |
| __`>`__          | Query number or date is greater than predicate value                                                                                                                                                                        | `jsonpath "$.year" > 1978`<br><br>`jsonpath "$.createdAt" toDate "%+"  > {{ a_date }}`                             |
| __`>=`__         | Query number or date is greater than or equal to the predicate value                                                                                                                                                        | `jsonpath "$.year" >= 1978`                                                                                        |
| __`<`__          | Query number or date is less than that predicate value                                                                                                                                                                      | `jsonpath "$.year" < 1978`                                                                                         |
| __`<=`__         | Query number or date is less than or equal to the predicate value                                                                                                                                                           | `jsonpath "$.year" <= 1978`                                                                                        |
| __`startsWith`__ | Query starts with the predicate value<br>Value is string or a binary content                                                                                                                                                | `jsonpath "$.movie" startsWith "The"`<br><br>`bytes startsWith hex,efbbbf;`                                        |
| __`endsWith`__   | Query ends with the predicate value<br>Value is string or a binary content                                                                                                                                                  | `jsonpath "$.movie" endsWith "Back"`<br><br>`bytes endsWith hex,ab23456;`                                          |
| __`contains`__   | If query returns a collection of string or numbers, query collection includes the predicate value (string or number)<br>If query returns a string or a binary content, query contains the predicate value (string or bytes) | `jsonpath "$.movie" contains "Empire"`<br><br>`bytes contains hex,beef;`<br><br>`jsonpath "$.numbers" contains 42` |
| __`matches`__    | Part of the query string matches the regex pattern described by the predicate value (see [regex syntax](https://docs.rs/regex/latest/regex/#syntax))                                                                        | `jsonpath "$.release" matches "\\d{4}"`<br><br>`jsonpath "$.release" matches /\d{4}/`                              |
| __`exists`__     | Query returns a value                                                                                                                                                                                                       | `jsonpath "$.book" exists`                                                                                         |
| __`isBoolean`__  | Query returns a boolean                                                                                                                                                                                                     | `jsonpath "$.succeeded" isBoolean`                                                                                 |
| __`isEmpty`__    | Query returns an empty collection (list, object)                                                                                                                                                                            | `jsonpath "$.movies" isEmpty`                                                                                      |
| __`isFloat`__    | Query returns a float                                                                                                                                                                                                       | `jsonpath "$.height" isFloat`                                                                                      |
| __`isInteger`__  | Query returns an integer                                                                                                                                                                                                    | `jsonpath "$.count" isInteger`                                                                                     |
| __`isIpv4`__     | Query returns an IPv4 address                                                                                                                                                                                               | `ip isIpv4`                                                                                                        |
| __`isIpv6`__     | Query returns an IPv6 address                                                                                                                                                                                               | `ip isIpv6`                                                                                                        |
| __`isIsoDate`__  | Query string returns a [RFC 3339] date (`YYYY-MM-DDTHH:mm:ss.sssZ`)                                                                                                                                                         | `jsonpath "$.publication_date" isIsoDate`                                                                          |
| __`isList`__     | Query returns a list                                                                                                                                                                                                        | `jsonpath "$.books" isList`                                                                                        |
| __`isNumber`__   | Query returns an integer or a float                                                                                                                                                                                         | `jsonpath "$.count" isNumber`                                                                                      |
| __`isObject`__   | Query returns an object (JSON object or XML node set)                                                                                                                                                                       | `jsonpath "$.books[0]" isObject`                                                                                   |
| __`isString`__   | Query returns a string                                                                                                                                                                                                      | `jsonpath "$.name" isString`                                                                                       |
| __`isUuid`__     | Query returns a [UUID v4]                                                                                                                                                                                                   | `ip isUuid`                                                                                                        |


Each predicate can be negated by prefixing it with `not` (for instance, `not contains` or `not exists`)

<div class="schema-container schema-container u-font-size-1 u-font-size-2-sm u-font-size-3-md">
 <div class="schema">
   <span class="schema-token schema-color-2">jsonpath "$.book"<span class="schema-label">query</span></span>
   <span class="schema-token schema-color-1">not contains<span class="schema-label">predicate type</span></span>
   <span class="schema-token schema-color-3">"Dune"<span class="schema-label">predicate value</span></span>
 </div>
</div>

A predicate value is typed, and can be a string, a boolean, a number, a bytestream, `null` or a collection. Note that
`"true"` is a string, whereas `true` is a boolean.

For instance, to test the presence of a h1 node in an HTML response, the following assert can be used:

```hurl
GET https://example.org/home
HTTP 200
[Asserts]
xpath "boolean(count(//h1))" == true
xpath "//h1" exists # Equivalent but simpler
```

As the XPath query `boolean(count(//h1))` returns a boolean, the predicate value in the assert must be either
`true` or `false` without double quotes. On the other side, say you have an article node and you want to check the value of some
[data attributes]:

```xml
<article
  id="electric-cars"
  data-visible="true"
...
</article>
```

The following assert will check the value of the `data-visible` attribute:

```hurl
GET https://example.org/home
HTTP 200
[Asserts]
xpath "string(//article/@data-visible)" == "true"
```

In this case, the XPath query `string(//article/@data-visible)` returns a string, so the predicate value must be a
string.

The predicate function `==` can be used with string, numbers or booleans; `startWith` and `contains` can only
be used with strings and bytes, while `matches` only works on string. If a query returns a number, using a `matches` 
predicate will cause a runner error.

```hurl
# A really well tested web page...
GET https://example.org/home
HTTP 200
[Asserts]
header "Content-Type" contains "text/html"
header "Last-Modified" == "Wed, 21 Oct 2015 07:28:00 GMT"
xpath "//h1" exists  # Check we've at least one h1
xpath "normalize-space(//h1)" contains "Welcome"
xpath "//h2" count == 13
xpath "string(//article/@data-id)" startsWith "electric"
```

### Status assert

Check the received HTTP response status code. Status assert consists of the keyword `status` followed by a predicate
function and value.

```hurl
GET https://example.org
HTTP *
[Asserts]
status < 300
```

### Version assert

Check the received HTTP version. Version assert consists of the keyword `version` followed by a predicate function
and value. The value returns by `version` is a string:

```hurl
GET https://example.org
HTTP *
[Asserts]
version == "2"
```

### Header assert

Check the value of a received HTTP response header. Header assert consists of the keyword `header` followed by the value
of the header, a predicate function and a predicate value. Like [headers implicit asserts], the check is 
case-insensitive for the name: comparing a `Content-Type` header is equivalent to a `content-type` one.

```hurl
GET https://example.org
HTTP 302
[Asserts]
header "Location" contains "www.example.net"
header "Last-Modified" matches /\d{2} [a-z-A-Z]{3} \d{4}/
```

If there are multiple headers with the same name, the header assert returns a collection, so `count`, `contains` can be
used in this case to test the header list.

Let's say we have this request and response:

```
> GET /hello HTTP/1.1
> Host: example.org
> Accept: */*
> User-Agent: hurl/2.0.0-SNAPSHOT
>
* Response: (received 12 bytes in 11 ms)
*
< HTTP/1.0 200 OK
< Vary: Content-Type
< Vary: User-Agent
< Content-Type: text/html; charset=utf-8
< Content-Length: 12
< Server: Flask Server
< Date: Fri, 07 Oct 2022 20:53:35 GMT
```

One can use explicit header asserts:

```hurl
GET https://example.org/hello
HTTP 200
[Asserts]
header "Vary" count == 2
header "Vary" contains "User-Agent"
header "Vary" contains "Content-Type"
```

Or implicit header asserts:

```hurl
GET https://example.org/hello
HTTP 200
Vary: User-Agent
Vary: Content-Type
```

### Cookie assert

Check value or attributes of a [`Set-Cookie`] response header. Cookie assert consists of the keyword `cookie`, followed 
by the cookie name (and optionally a cookie attribute), a predicate function and value.

Cookie attributes value can be checked by using the following format:`<cookie-name>[cookie-attribute]`. The following 
attributes are supported: `Value`, `Expires`, `Max-Age`, `Domain`, `Path`, `Secure`, `HttpOnly` and `SameSite`.

```hurl
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"
```

> `Secure` and `HttpOnly` attributes can only be tested with `exists` or `not exists` predicates
> to reflect the [Set-Cookie header] semantics (in other words, queries `<cookie-name>[HttpOnly]`
> and `<cookie-name>[Secure]` don't return boolean).

### Body assert

Check the value of the received HTTP response body when decoded as a string. Body assert consists of the keyword `body`
followed by a predicate function and value.

```hurl
GET https://example.org
HTTP 200
[Asserts]
body contains "<h1>Welcome!</h1>"
```

The encoding used to decode the response body bytes to a string is based on the `charset` value in the `Content-Type`
header response.

```hurl
# Our HTML response is encoded with GB 2312 (see https://en.wikipedia.org/wiki/GB_2312)
GET https://example.org/cn
HTTP 200
[Asserts]
header "Content-Type" == "text/html; charset=gb2312"
# bytes of the response, without any text decoding:
bytes contains hex,c4e3bac3cac0bde7; # 你好世界 encoded in GB 2312
# text of the response, decoded with GB 2312:
body contains "你好世界"
```

If the `Content-Type` response header doesn't include any encoding hint, a [`decode` filter] can be used to explicitly
decode the response body bytes.

```hurl
# Our HTML response is encoded using GB 2312.
# But, the 'Content-Type' HTTP response header doesn't precise any charset,
# so we decode explicitly the bytes.
GET https://example.org/cn
HTTP 200
[Asserts]
header "Content-Type" == "text/html"
bytes contains hex,c4e3bac3cac0bde7; # 你好世界 encoded in GB2312
bytes charsetDecode "gb2312" contains "你好世界"
```

Body asserts are automatically decompressed based on the value of `Content-Encoding` response header. So,
whatever is the response compression (`gzip`, `brotli`) etc... asserts values don't depend on the content encoding.

```hurl
# Request a gzipped reponse, the `body` asserts works with ungzipped response
GET https://example.org
Accept-Encoding: gzip
HTTP 200
[Asserts]
header "Content-Encoding" == "gzip"
body contains "<h1>Welcome!</h1>"

# Without content encoding, asserts remains identical
GET https://example.org
HTTP 200
[Asserts]
header "Content-Encoding" not exists
body contains "<h1>Welcome!</h1>"
```

### Bytes assert

Check the value of the received HTTP response body as a bytestream. Body assert consists of the keyword `bytes`
followed by a predicate function and value.

```hurl
GET https://example.org/data.bin
HTTP 200
[Asserts]
bytes startsWith hex,efbbbf;
bytes count == 12424
header "Content-Length" == "12424"
```

Like `body` assert, `bytes` assert works _after_ content encoding decompression (so the predicates values are not
affected by `Content-Encoding` response header value).

### RawBytes assert

Check the value of the received HTTP response body as a raw bytestream. RawBytes assert consists of the keyword `rawbytes`
followed by a predicate function and value.

```hurl
GET https://example.org/data.bin
HTTP 200
Content-Encoding: gzip
[Asserts]
header "Content-Length" == "32"
rawbytes count == 32               # matches Content-Length (compressed size)
bytes count == 100                 # decompressed size is larger
rawbytes startsWith hex,1f8b;      # gzip magic bytes
bytes startsWith hex,48656c6c6f;   # decompressed content starts with "Hello"
```

Unlike `bytes` assert, `rawbytes` returns the raw bytes _before_ any content decoding. For uncompressed responses, `rawbytes` and `bytes` return the same data.

### XPath assert

Check the value of a [XPath] query on the received HTTP body decoded as a string (using the `charset` value in the
`Content-Type` header response). Currently, only XPath 1.0 expression can be used. Body assert consists of the
keyword `xpath` followed by a predicate function and value. Values can be string,
boolean or number depending on the XPath query.

Let's say we want to check this HTML response:

```plain
$ curl -v https://example.org

< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
...
<!doctype html>
<html>
  <head>
    <title>Example Domain</title>
    ...
  </head>

  <body>
    <div>
      <h1>Example</h1>
      <p>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</p>
      <p><a href="https://www.iana.org/domains/example">More information...</a></p>
    </div>
  </body>
</html>
```

With Hurl, we can write multiple XPath asserts describing the DOM content:

```hurl
GET https://example.org
HTTP 200
Content-Type: text/html; charset=UTF-8
[Asserts]
xpath "string(/html/head/title)" contains "Example" # Check title
xpath "count(//p)" == 2                             # Check the number of <p>
xpath "//p" count == 2                              # Similar assert for <p>
xpath "boolean(count(//h2))" == false               # Check there is no <h2>  
xpath "//h2" not exists                             # Similar assert for <h2> 
```

XML Namespaces are also supported. Let's say you want to check this XML response:

```xml
<?xml version="1.0"?>

<bk:book xmlns:bk='urn:loc.gov:books'
         xmlns:isbn='urn:ISBN:0-395-36341-6'>
    <bk:title>Cheaper by the Dozen</bk:title>
    <isbn:number>1568491379</isbn:number>
</bk:book>
```

This XML response can be tested with the following Hurl file:

```hurl
GET http://localhost:8000/assert-xpath
HTTP 200
[Asserts]

xpath "string(//bk:book/bk:title)" == "Cheaper by the Dozen"
xpath "string(//*[name()='bk:book']/*[name()='bk:title'])" == "Cheaper by the Dozen"
xpath "string(//*[local-name()='book']/*[local-name()='title'])" == "Cheaper by the Dozen"

xpath "string(//bk:book/isbn:number)" == "1568491379"
xpath "string(//*[name()='bk:book']/*[name()='isbn:number'])" == "1568491379"
xpath "string(//*[local-name()='book']/*[local-name()='number'])" == "1568491379"
```

The XPath expressions `string(//bk:book/bk:title)` and `string(//bk:book/isbn:number)` are written with `bk` and `isbn`
namespaces.

> For convenience, the first default namespace can be used with `_`

### JSONPath assert

Check the value of a [JSONPath] query on the received HTTP body decoded as a JSON document. JSONPath assert consists 
of the keyword `jsonpath` followed by a predicate function and value.

Let's say we want to check this JSON response:

```plain
curl -v http://httpbin.org/json

< HTTP/1.1 200 OK
< Content-Type: application/json
...

{
  "slideshow": {
    "author": "Yours Truly",
    "date": "date of publication",
    "slides": [
      {
        "title": "Wake up to WonderWidgets!",
        "type": "all"
      },
       ...
    ],
    "title": "Sample Slide Show"
  }
}
```

With Hurl, we can write multiple JSONPath asserts describing the DOM content:

```hurl
GET http://httpbin.org/json
HTTP 200
[Asserts]
jsonpath "$.slideshow.author" == "Yours Truly"
jsonpath "$.slideshow.slides[0].title" contains "Wonder"
jsonpath "$.slideshow.slides" count == 2
jsonpath "$.slideshow.date" != null
jsonpath "$.slideshow.slides[*].title" contains "Mind Blowing!"
```

> Explain that the value selected by the JSONPath is coerced to a string when only
> one node is selected.

In `matches` predicates, metacharacters beginning with a backslash (like `\d`, `\s`) must be escaped. Alternatively, 
`matches` predicate support [JavaScript-like Regular expression syntax] to enhance the readability:

```hurl
GET https://example.org/hello
HTTP 200
[Asserts]

# Predicate value with matches predicate:
jsonpath "$.date" matches "^\\d{4}-\\d{2}-\\d{2}$"
jsonpath "$.name" matches "Hello [a-zA-Z]+!"

# Equivalent syntax:
jsonpath "$.date" matches /^\d{4}-\d{2}-\d{2}$/
jsonpath "$.name" matches /Hello [a-zA-Z]+!/
```

### Regex assert

Check that the HTTP received body, decoded as text, matches a regex pattern.

```hurl
GET https://example.org/hello
HTTP 200
[Asserts]
regex "^(\\d{4}-\\d{2}-\\d{2})$" == "2018-12-31"
# Same assert as previous using regex literals
regex /^(\d{4}-\d{2}-\d{2})$/ == "2018-12-31"
```

The regex pattern must have at least one capture group, otherwise the assert will fail. The assertion is done on the 
captured group value. When the regex pattern is a double-quoted string, metacharacters beginning with a backslash in the
pattern (like `\d`, `\s`) must be escaped; literal pattern enclosed by `/` can also be used to avoid metacharacters
escaping.

The regex syntax is documented at <https://docs.rs/regex/latest/regex/#syntax>. For instance, once can use [flags](https://docs.rs/regex/latest/regex/#grouping-and-flags)
to enable case-insensitive match:

```hurl
GET https://example.org/hello
HTTP 200
[Asserts]
regex /(?i)hello (\w+)!/ == "World"
```

### SHA-256 assert

Check response body [SHA-256] hash.

```hurl
GET https://example.org/data.tar.gz
HTTP 200
[Asserts]
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
```

Like `body` assert, `sha256` assert works _after_ content encoding decompression (so the predicates values are not
affected by `Content-Encoding` response header). For instance, if we have a resource `a.txt` on a server with a
given hash `abcdef`, `sha256` value is not affected by `Content-Encoding`:

```hurl
# Without content encoding compression:
GET https://example.org/a.txt
HTTP 200
[Asserts]
sha256 == hex,abcdef;

# With content encoding compression:
GET https://example.org/a.txt
Accept-Encoding: brotli
HTTP 200
[Asserts]
header "Content-Encoding" == "brotli"
sha256 == hex,abcdef;
```

### MD5 assert

Check response body [MD5] hash.

```hurl
GET https://example.org/data.tar.gz
HTTP 200
[Asserts]
md5 == hex,ed076287532e86365e841e92bfc50d8c;
```

Like `sha256` asserts, `md5` assert works _after_ content encoding decompression (so the predicates values are not
affected by `Content-Encoding` response header)

### URL assert

Check the last fetched URL. This is most meaningful if you have told Hurl to follow redirection (see [`[Options]`section][options] or
[`--location` option]). URL assert consists of the keyword `url` followed by a predicate function and value.

```hurl
GET https://example.org/redirecting
[Options]
location: true
HTTP 200
[Asserts]
url == "https://example.org/redirected"
```

### Redirects assert

Check each step of redirection. This is most meaningful if you have told Hurl to follow redirection (see [`[Options]`section][options] or
[`--location` option]). Redirects assert consists of the keyword `redirects` followed by a predicate function and value. The `redirects`
query returns a collection of redirections that can be tested with a [`location` filter]:

```hurl
GET https://example.org/redirecting/1
[Options]
location: true
HTTP 200
[Asserts]
redirects count == 3
redirects nth 0 location == "https://example.org/redirecting/2"
redirects nth 1 location == "https://example.org/redirecting/3"
redirects nth 2 location == "https://example.org/redirected"
```

### IP address assert

Check the IP address of the last connection. The value of the `ip` query is a string.

> Predicates `isIpv4` and `isIpv6` are available to check if a particular string matches an IPv4 or IPv6 address and
> can use with `ip` queries.

```hurl
GET https://example.org/hello
HTTP 200
[Asserts]
ip isIpv4
ip not isIpv6
ip == "172.16.45.87"
```

### Variable assert

```hurl
# Test that the XML endpoint return 200 pets 
GET https://example.org/api/pets
HTTP 200
[Captures]
pets: xpath "//pets"
[Asserts]
variable "pets" count == 200
```

### Duration assert

Check the total duration (sending plus receiving time) of the HTTP transaction.

```hurl
GET https://example.org/helloworld
HTTP 200
[Asserts]
duration < 1000   # Check that response time is less than one second
```

### SSL certificate assert

Check the SSL certificate properties. Certificate assert consists of the keyword `certificate`, followed by the 
certificate attribute value.

The following attributes are supported: `Subject`, `Issuer`, `Start-Date`, `Expire-Date`, `Serial-Number`, 
`Subject-Alt-Name` and `Value`.

```hurl
GET https://example.org
HTTP 200
[Asserts]
certificate "Subject" == "CN=example.org"
certificate "Issuer" == "C=US, O=Let's Encrypt, CN=R3"
certificate "Expire-Date" daysAfterNow > 15
certificate "Serial-Number" matches "[0-9af]+"
certificate "Subject-Alt-Name" contains "DNS:example.org"
certificate "Subject-Alt-Name" split "," count == 2
certificate "Value" startsWith "-----BEGIN CERTIFICATE-----"
```

[predicates]: #predicates
[header assert]: #header-assert
[captures]: /docs/capturing-response.md#query
[data attributes]: https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
[`Set-Cookie`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
[Set-Cookie header]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
[XPath]: https://en.wikipedia.org/wiki/XPath
[JSONPath]: https://goessner.net/articles/JsonPath/
[body asserts]: #body-assert
[JSON]: https://www.json.org
[XML]: https://en.wikipedia.org/wiki/XML
[Base64]: https://en.wikipedia.org/wiki/Base64
[`--file-root` option]: /docs/manual.md#file-root
[JavaScript-like Regular expression syntax]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
[MD5]: https://en.wikipedia.org/wiki/MD5
[SHA-256]: https://en.wikipedia.org/wiki/SHA-2
[options]: /docs/request.md#options
[`--location` option]: /docs/manual.md#location
[multiline string body]: #multiline-string-body
[filters]: /docs/filters.md
[count]: /docs/filters.md#count
[`decode` filter]: /docs/filters.md#decode
[headers implicit asserts]: #headers
[RFC 3339]: https://www.rfc-editor.org/rfc/rfc3339
[content-encoding]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
[`Content-Type` header]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type
[`body` assert]: #body-assert
[`location` filter]: /docs/filters.md#location
[UUID v4]: https://en.wikipedia.org/wiki/Universally_unique_identifier

---

### Capturing Response (`docs/capturing-response.md`)

# Capturing Response

## Captures

Captures are optional values that are __extracted from the HTTP response__ and stored in a named variable.
These captures may be the response status code, part of or the entire the body, and response headers.

Captured variables can be accessed through a run session; each new value of a given variable overrides the last value.

Captures can be useful for using data from one request in another request, such as when working with [CSRF tokens].
Variables in a Hurl file can be created from captures or [injected into the session].

```hurl
# An example to show how to pass a CSRF token
# from one request to another:

# First GET request to get CSRF token value:
GET https://example.org
HTTP 200
# Capture the CSRF token value from html body.
[Captures]
csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"

# Do the login !
POST https://acmecorp.net/login?user=toto&password=1234
X-CSRF-TOKEN: {{csrf_token}}
HTTP 302
```

Body responses can be encoded by server (see [`Content-Encoding` HTTP header][content-encoding]) but captures in Hurl files are not
affected by this content compression. All body captures (`body`, `bytes`, `sha256` etc...) except `rawbytes` work _after_ content decoding.

Finally, body text captures (`body`, `jsonpath`, `xpath` etc...) are also decoded to strings based on [`Content-Type` header]
so these queries can be captures as usual strings.


__Structure of a capture:__

<div class="schema-container schema-container u-font-size-2 u-font-size-3-sm">
 <div class="schema">
   <span class="schema-token schema-color-1">my_var<span class="schema-label">variable</span></span>
   <span> : </span>
   <span class="schema-token schema-color-2">xpath "string(//h1)"<span class="schema-label">query</span></span>
 </div>
</div>

A capture consists of a variable name, followed by `:` and a query. Captures
section starts with `[Captures]`.

### Query

Queries are used to extract data from an HTTP response.

A query can extract data from

- status line:
  - [`status`](#status-capture)
  - [`version`](#version-capture)
- headers:
  - [`header`](#header-capture)
  - [`cookie`](#cookie-capture)
- body:
  - [`body`](#body-capture)
  - [`bytes`](#bytes-capture)
  - [`rawbytes`](#bytes-capture)
  - [`xpath`](#xpath-capture)
  - [`jsonpath`](#jsonpath-capture)
  - [`regex`](#regex-capture)
  - [`sha256`](#sha-256-capture)
  - [`md5`](#md5-capture)
- others:
  - [`url`](#url-capture)
  - [`redirects`](#redirects-capture)
  - [`ip`](#ip-address-capture)
  - [`variable`](#variable-capture)
  - [`duration`](#duration-capture)
  - [`certificate`](#ssl-certificate-capture)

Extracted data can then be further refined using [filters].

### Status capture

Capture the received HTTP response status code. Status capture consists of a variable name, followed by a `:`, and the
keyword `status`.

```hurl
GET https://example.org
HTTP 200
[Captures]
my_status: status
```

### Version capture

Capture the received HTTP version. Version capture consists of a variable name, followed by a `:`, and the
keyword `version`. The value captured is a string:

```hurl
GET https://example.org
HTTP 200
[Captures]
http_version: version
```

### Header capture

Capture a header from the received HTTP response headers. Header capture consists of a variable name, followed by a `:`,
then the keyword `header` and a header name.

```hurl
POST https://example.org/login
[Form]
user: toto
password: 12345678
HTTP 302
[Captures]
next_url: header "Location"
```

### Cookie capture

Capture a [`Set-Cookie`] header from the received HTTP response headers. Cookie
capture consists of a variable name, followed by a `:`, then the keyword `cookie`
and a cookie name.

```hurl
GET https://example.org/cookies/set
HTTP 200
[Captures]
session-id: cookie "LSID"
```

Cookie attributes value can also be captured by using the following format:
`<cookie-name>[cookie-attribute]`. The following attributes are supported:
`Value`, `Expires`, `Max-Age`, `Domain`, `Path`, `Secure`, `HttpOnly` and `SameSite`.

```hurl
GET https://example.org/cookies/set
HTTP 200
[Captures]
value1: cookie "LSID"
value2: cookie "LSID[Value]"     # Equivalent to the previous capture
expires: cookie "LSID[Expires]"
max-age: cookie "LSID[Max-Age]"
domain: cookie "LSID[Domain]"
path: cookie "LSID[Path]"
secure: cookie "LSID[Secure]"
http-only: cookie "LSID[HttpOnly]"
same-site: cookie "LSID[SameSite]"
```

### Body capture

Capture the entire body (decoded as text) from the received HTTP response. The encoding used to decode the body 
is based on the `charset` value in the `Content-Type` header response.

```hurl
GET https://example.org/home
HTTP 200
[Captures]
my_body: body
```

If the `Content-Type` doesn't include any encoding hint, a [`decode` filter] can be used to explicitly decode the body response
bytes.

```hurl
# Our HTML response is encoded using GB 2312.
# But, the 'Content-Type' HTTP response header doesn't precise any charset,
# so we decode explicitly the bytes.
GET https://example.org/cn
HTTP 200
[Captures]
my_body: bytes charsetDecode "gb2312"
```

`body` capture works _after_ content encoding decompression (so the captured value is not affected by `Content-Encoding` response header).

### Bytes capture

Capture the entire body (as a raw bytestream) from the received HTTP response

```hurl
GET https://example.org/data.bin
HTTP 200
[Captures]
my_data: bytes
```

Like `body` capture, `bytes` capture works _after_ content encoding decompression (so the captured value is not
affected by `Content-Encoding` response header).

### RawBytes capture

Capture the entire body as a raw bytestream from the received HTTP response, _before_ any content decoding.

```hurl
GET https://example.org/data.bin
HTTP 200
[Captures]
raw_data: rawbytes
```

Unlike `bytes` capture, `rawbytes` returns the raw bytes before content encoding decompression. For uncompressed responses, `rawbytes` and `bytes` capture the same data.

### XPath capture

Capture a [XPath] query from the received HTTP body decoded as a string.
Currently, only XPath 1.0 expression can be used.

```hurl
GET https://example.org/home
# Capture the identifier from the dom node <div id="pet0">5646eaf23</div
HTTP 200
[Captures]
pet-id: xpath "normalize-space(//div[@id='pet0'])"

# Open the captured page.
GET https://example.org/home/pets/{{pet-id}}
HTTP 200
```

XPath captures are not limited to node values (like string, or boolean); any
valid XPath can be captured and asserted with variable asserts.

```hurl
# Test that the XML endpoint return 200 pets
GET https://example.org/api/pets
HTTP 200
[Captures]
pets: xpath "//pets"
[Asserts]
variable "pets" count == 200
```

XPath expression can also be evaluated against part of the body with a [`xpath` filter]:

```hurl
GET https://example.org/home_cn
HTTP 200
[Captures]
pet-id: bytes charsetDecode "gb2312" xpath "normalize-space(//div[@id='pet0'])"
```

### JSONPath capture

Capture a [JSONPath] query from the received HTTP body.

```hurl
POST https://example.org/api/contact
[Form]
token: {{token}}
email: toto@rookie.net
HTTP 200
[Captures]
contact-id: jsonpath "$['id']"
```

> Explain that the value selected by the JSONPath is coerced to a string when only one node is selected.

As with [XPath captures], JSONPath captures can be anything from string, number, to object and collections.
For instance, if we have a JSON endpoint that returns the following JSON:

```
{
  "a_null": null,
  "an_object": {
    "id": "123"
  },
  "a_list": [
    1,
    2,
    3
  ],
  "an_integer": 1,
  "a float": 1.1,
  "a_bool": true,
  "a_string": "hello"
}
```

We can capture the following paths:

```hurl
GET https://example.org/captures-json
HTTP 200
[Captures]
an_object:  jsonpath "$['an_object']"
a_list:     jsonpath "$['a_list']"
a_null:     jsonpath "$['a_null']"
an_integer: jsonpath "$['an_integer']"
a_float:    jsonpath "$['a_float']"
a_bool:     jsonpath "$['a_bool']"
a_string:   jsonpath "$['a_string']"
all:        jsonpath "$"
```

### Regex capture

Capture a regex pattern from the HTTP received body, decoded as text.

```hurl
GET https://example.org/helloworld
HTTP 200
[Captures]
id_a: regex "id_a:([0-9]+)"
id_b: regex "id_b:(\\d+)"   # pattern using double quote 
id_c: regex /id_c:(\d+)/    # pattern using forward slash
name: regex "Hello ([a-zA-Z]+)"
```

The regex pattern must have at least one capture group, otherwise the
capture will fail. When the pattern is a double-quoted string, metacharacters beginning with a backslash in the pattern
(like `\d`, `\s`) must be escaped; literal pattern enclosed by `/` can also be used to avoid metacharacters escaping.

The regex syntax is documented at <https://docs.rs/regex/latest/regex/#syntax>. For instance, one can use [flags](https://docs.rs/regex/latest/regex/#grouping-and-flags)
to enable case-insensitive match:

```hurl
GET https://example.org/hello
HTTP 200
[Captures]
word: regex /(?i)hello (\w+)!/
```

### SHA-256 capture

Capture the [SHA-256] hash of the response body.

```hurl
GET https://example.org/data.tar.gz
HTTP 200
[Captures]
my_hash: sha256
```

Like `body` assert, `sha256` capture works _after_ content encoding decompression (so the captured value is not
affected by `Content-Encoding` response header).

### MD5 capture

Capture the [MD5] hash of the response body.

```hurl
GET https://example.org/data.tar.gz
HTTP 200
[Captures]
my_hash: md5
```

Like `sha256` asserts, `md5` assert works _after_ content encoding decompression (so the predicates values are not
affected by `Content-Encoding` response header)

### URL capture

Capture the last fetched URL. This is most meaningful if you have told Hurl to follow redirection (see [`[Options]` section][options] or
[`--location` option]). URL capture consists of a variable name, followed by a `:`, and the keyword `url`.

```hurl
GET https://example.org/redirecting
[Options]
location: true
HTTP 200
[Captures]
landing_url: url
```

### Redirects capture

Capture each step of redirection. This is most meaningful if you have told Hurl to follow redirection (see [`[Options]`section][options] or
[`--location` option]). Redirects capture consists of a variable name, followed by a `:`, and the keyword `redirects`.
Redirects query returns a collection so each step of the redirection can be capture.

```hurl
GET https://example.org/redirecting/1
[Options]
location: true
HTTP 200
[Asserts]
redirects count == 3
[Captures]
step1: redirects nth 0 location
step2: redirects nth 1 location
step3: redirects nth 2 location
```

### IP address capture

Capture the IP address of the last connection. The value of the `ip` query is a string.

```hurl
GET https://example.org/hello
HTTP 200
[Captures]
server_ip: ip
```

### Variable capture

Capture the value of a variable into another.

```hurl
GET https://example.org/helloworld
HTTP 200
[Captures]
in: body
name: variable "in"
```

### Duration capture

Capture the response time of the request in ms.

```hurl
GET https://example.org/helloworld
HTTP 200
[Captures]
duration_in_ms: duration
```

### SSL certificate capture

Capture the SSL certificate properties. Certificate capture consists of the keyword `certificate`, followed by the certificate attribute value.

The following attributes are supported: `Subject`, `Issuer`, `Start-Date`, `Expire-Date`, `Serial-Number`,
`Subject-Alt-Name` and `Value`.

```hurl
GET https://example.org
HTTP 200
[Captures]
cert_subject: certificate "Subject"
cert_issuer: certificate "Issuer"
cert_expire_date: certificate "Expire-Date"
cert_serial_number: certificate "Serial-Number"
san: certificate "Serial-Number"
value: certificate "Value"
```

## Redacting Secrets

When capturing data, you may need to hide captured values from logs and report. To do this, captures can use secrets
which are redacted from logs and reports, using [`--secret` option]:

```shell
$ hurl --secret pass=sesame-ouvre-toi file.hurl
```

If the secret value to be redacted is dynamic, or not known before execution, a capture can become a secret using `redact`
at the end of the query's capture:

```hurl
GET https://foo.com
HTTP 200
[Captures]
pass: header "token" redact
```

[CSRF tokens]: https://en.wikipedia.org/wiki/Cross-site_request_forgery
[injected into the session]: /docs/templates.md#injecting-variables
[`Set-Cookie`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
[XPath]: https://en.wikipedia.org/wiki/XPath
[JSONPath]: https://goessner.net/articles/JsonPath/
[XPath captures]: #xpath-capture
[JavaScript-like Regular expression syntax]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
[options]: /docs/request.md#options
[`--location` option]: /docs/manual.md#location
[filters]: /docs/filters.md
[`xpath` filter]: /docs/filters.md#xpath
[`decode` filter]: /docs/filters.md#decode
[`--secret` option]: /docs/templates.md#secrets
[MD5]: https://en.wikipedia.org/wiki/MD5
[SHA-256]: https://en.wikipedia.org/wiki/SHA-2
[content-encoding]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
[`Content-Type` header]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type

---

### Entry (`docs/entry.md`)

# Entry

## Definition

A Hurl file is a list of entries, each entry being a mandatory [request], optionally followed by a [response].

Responses are not mandatory, a Hurl file consisting only of requests is perfectly valid. To sum up, responses can be used
to [capture values] to perform subsequent requests, or [add asserts to HTTP responses].

## Example

```hurl
# First, test home title.
GET https://acmecorp.net
HTTP 200
[Asserts]
xpath "normalize-space(//head/title)" == "Hello world!"

# Get some news, response description is optional
GET https://acmecorp.net/news

# Do a POST request without CSRF token and check
# that status code is Forbidden 403
POST https://acmecorp.net/contact
[Form]
default: false
email: john.doe@rookie.org
number: 33611223344
HTTP 403
```

## Description

### Options

[Options] specified on the command line apply to every entry in an Hurl file. For instance, with [`--location` option],
every entry of a given file will follow redirection:

```shell
$ hurl --location foo.hurl
```

You can use an [`[Options]` section][options] to set option only for a specified request. For instance, in this Hurl file,
the second entry will follow location (so we can test the status code to be 200 instead of 301).

```hurl
GET https://google.fr
HTTP 301

GET https://google.fr
[Options]
location: true
HTTP 200

GET https://google.fr
HTTP 301
```

You can use the `[Options]` section to log a specific entry:

```hurl
# ... previous entries

GET https://api.example.org
[Options]
very-verbose: true
HTTP 200

# ... next entries
```

### Cookie storage

By default, requests in the same Hurl file share cookie storage, enabling session-based scenario. The shared cookie store can
be disabled with [`--no-cookie-store`] option.

### Redirects

By default, Hurl doesn't follow redirection. To effectively run a redirection, entries should describe each step
of the redirection, allowing insertion of asserts in each response.

```hurl
# First entry, test the redirection (status code and 'Location' header)
GET https://example.org
HTTP 301
Location: https://www.example.org

# Second entry, the 200 OK response
GET https://www.example.org
HTTP 200
```

Alternatively, one can use [`--location`] / [`--location-trusted`] options to force redirection
to be followed. In this case, asserts are executed on the last received response. Optionally, the number of
redirections can be limited with [`--max-redirs`].

```hurl
# Running hurl --location foo.hurl
GET https://example.org
HTTP 200
```

Finally, you can force redirection on a particular request with an [`[Options]` section][options] and the [`--location`] 
/ [`--location-trusted`] options:

```hurl
GET https://example.org
[Options]
location-trusted: true
HTTP 200
```

Redirections can be tested either by:

- running and asserting each step of redirection:

```hurl
GET https://example.org/step1
HTTP 301
[Asserts]
header "Location" == "https://example.org/step2"


GET https://example.org/step2
HTTP 301
[Asserts]
header "Location" == "https://example.org/step3"


GET https://example.org/step3
HTTP 200
```

- using [`--location`] / [`--location-trusted`], testing each step with [`redirects` query]:

```hurl
GET https://example.org/step1
[Options]
location: true
HTTP 200
[Asserts]
redirects count == 2
redirects nth 0 location == "https://example.org/step2"
redirects nth 1 location == "https://example.org/step3"
```

[`url` query] can also be used to get the final effective URL:

```hurl
GET https://example.org/step1
[Options]
location: true
HTTP 200
[Asserts]
url == "https://example.org/step3"
```

### Retry

Every entry can be retried upon asserts, captures or runtime errors. Retries allow polling scenarios and effective runs 
under flaky conditions. Asserts can be explicit (with an [`[Asserts]` section][asserts]), or implicit (like [headers] or [status code]).

Retries can be set globally for every request (see [`--retry`] and [`--retry-interval`]), 
or activated on a particular request with an [`[Options]` section][options].

For example, in this Hurl file, first we create a new job then we poll the new job until it's completed:

```hurl
# Create a new job
POST http://api.example.org/jobs
HTTP 201
[Captures]
job_id: jsonpath "$.id"
[Asserts]
jsonpath "$.state" == "RUNNING"


# Pull job status until it is completed
GET http://api.example.org/jobs/{{job_id}}
[Options]
retry: 10   # maximum number of retry, -1 for unlimited
retry-interval: 300ms
HTTP 200
[Asserts]
jsonpath "$.state" == "COMPLETED"
```

### Control flow

In `[Options]` section, `skip` and `repeat` can be used to control flow of execution:

- `skip: true/false` skip this request and execute the next one unconditionally,
- `repeat: N` loop the request N times. If there are assert or runtime errors, the requests execution is stopped.

```hurl
# This request will be played exactly 3 times
GET https://example.org/foo
[Options]
repeat: 3
HTTP 200

# This request is skipped
GET https://example.org/foo
[Options]
skip: true
HTTP 200
```

Additionally, a `delay` can be inserted between requests, to add a delay before execution of a request (aka sleep).

```hurl
# A 5 seconds delayed request 
GET https://example.org/foo
[Options]
delay: 5s
HTTP 200
```

[`delay`] and [`repeat`] can also be used globally as command line options:

```shell
$ hurl --delay 500ms --repeat 3 foo.hurl
```



For complete reference, below is a diagram for the executed entries.

<div class="picture">
    <img class="u-theme-light u-drop-shadow u-border u-max-width-100" src="/docs/assets/img/run-cycle-light.svg" alt="Run cycle explanation"/>
    <img class="u-theme-dark u-drop-shadow u-border u-max-width-100" src="/docs/assets/img/run-cycle-dark.svg" alt="Run cycle explanation"/>
</div>


[request]: /docs/request.md
[response]: /docs/response.md
[capture values]: /docs/capturing-response.md
[add asserts to HTTP responses]: /docs/asserting-response.md
[`--location`]: /docs/manual.md#location
[`--location` option]: /docs/manual.md#location
[`--location-trusted`]: /docs/manual.md#location-trusted
[`--max-redirs`]: /docs/manual.md#max-redirs
[Options]: /docs/manual.md#options
[options]: /docs/request.md#options
[headers]: /docs/response.md#headers
[status code]: /docs/response.md#version-status
[asserts]: /docs/response.md#asserts
[Asserts]: /docs/response.md#asserts
[`--retry`]: /docs/manual.md#retry
[`--retry-interval`]: /docs/manual.md#retry-interval
[`delay`]: /docs/manual.md#retry 
[`repeat`]: /docs/manual.md#repeat
[`redirects` query]: /docs/asserting-response.md#redirects-assert
[`url` query]: /docs/asserting-response.md#url-assert
[`--no-coookie-store`]: /docs/manual.md#no-cookie-store

---

### Filters (`docs/filters.md`)

# Filters

## Definition

[Captures] and [asserts] share a common structure: query. A query is used to extract data from an HTTP response; this data 
can come from the HTTP response body, the HTTP response headers or from the HTTP meta-information (like `duration` for instance)...

In this example, the query __`jsonpath "$.books[0].name"`__ is used in a capture to save data and in an assert to test 
the HTTP response body.

__Capture__:

<div class="schema-container schema-container u-font-size-2 u-font-size-3-md">
 <div class="schema">
   <span class="schema-token schema-color-1">name<span class="schema-label">variable</span></span>
   <span> : </span>
   <span class="schema-token schema-color-2">jsonpath "$.books[0].name"<span class="schema-label">query</span></span>
 </div>
</div>

__Assert__:

<div class="schema-container schema-container u-font-size-2 u-font-size-3-md">
 <div class="schema">
   <span class="schema-token schema-color-2">jsonpath "$.books[0].name"<span class="schema-label">query</span></span>
   <span class="schema-token schema-color-3">== "Dune"<span class="schema-label">predicate</span></span>
 </div>
</div>

In both case, the query is exactly the same: queries are the core structure of asserts and captures. Sometimes, you want
to process data extracted by queries: that's the purpose of __filters__.

Filters are used to transform value extracted by a query and can be used in asserts and captures to refine data. Filters 
__can be chained__, allowing for fine-grained data extraction. 


<div class="schema-container schema-container u-font-size-2 u-font-size-3-md">
 <div class="schema">
    <span class="schema-token schema-color-2">jsonpath "$.name"<span class="schema-label">query</span></span>
    <span class="schema-token schema-color-1">split "," nth 0<span class="schema-label">2 filters</span></span>
    <span class="schema-token schema-color-3">== "Herbert"<span class="schema-label">predicate</span></span>
 </div>
</div>


## Example

```hurl
GET https://example.org/api
HTTP 200
[Captures]
name: jsonpath "$.user.id" replaceRegex /\d/ "x"
[Asserts]
header "x-servers" split "," count == 2
header "x-servers" split "," nth 0 == "rec1"
header "x-servers" split "," nth 1 == "rec3"
jsonpath "$.books" count == 12
```

## Description

| Filter                                      | Description                                                                                                                            | Input            | Output |
|---------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|------------------|--------|
| [base64Decode](#base64decode)               | Decodes a [Base64 encoded string] into bytes.                                                                                          | string           | bytes  |
| [base64Encode](#base64encode)               | Encodes bytes into [Base64 encoded string].                                                                                            | bytes            | string |
| [base64UrlSafeDecode](#base64urlsafedecode) | Decodes a Base64 encoded string into bytes (using [Base64 URL safe encoding]).                                                         | string           | bytes  |
| [base64UrlSafeEncode](#base64urlsafeencode) | Encodes bytes into Base64 encoded string (using [Base64 URL safe encoding]).                                                           | bytes            | string |
| [charsetDecode](#charsetdecode)             | Decodes bytes to string using a charset encoding.                                                                                      | bytes            | string |
| [count](#count)                             | Counts the number of items in a collection.                                                                                            | collection       | number |
| [dateFormat](#dateformat)                   | Formats a date to a string given [a specification format].                                                                             | date             | string |
| [daysAfterNow](#daysafternow)               | Returns the number of days between now and a date in the future.                                                                       | date             | number |
| [daysBeforeNow](#daysbeforenow)             | Returns the number of days between now and a date in the past.                                                                         | date             | number |
| [first](#first)                             | Returns the first element from a collection.                                                                                           | collection       | any    |
| [htmlEscape](#htmlescape)                   | Converts the characters `&`, `<` and `>` to HTML-safe sequence.                                                                        | string           | string |
| [htmlUnescape](#htmlunescape)               | Converts all named and numeric character references (e.g. `&gt;`, `&#62;`, `&#x3e;`) to the corresponding Unicode characters.          | string           | string |
| [jsonpath](#jsonpath)                       | Evaluates a [JSONPath] expression.                                                                                                     | string           | any    |
| [last](#last)                               | Returns the last element from a collection.                                                                                            | collection       | any    |
| [location](#location)                       | Returns the target location URL of a redirection.                                                                                      | response         | string |
| [nth](#nth)                                 | Returns the element from a collection at a zero-based index, accepts negative indices for indexing from the end of the collection.     | collection       | any    |
| [regex](#regex)                             | Extracts regex capture group. Pattern must have at least one capture group.                                                            | string           | string |
| [replace](#replace)                         | Replaces all occurrences of old string with new string.                                                                                | string           | string |
| [replaceRegex](#replaceregex)               | Replaces all occurrences of a pattern with new string.                                                                                 | string           | string |
| [split](#split)                             | Splits to a list of strings around occurrences of the specified delimiter.                                                             | string           | string |
| [toDate](#toDate)                           | Converts a string to a date given [a specification format].                                                                            | string           | date   |
| [toFloat](#tofloat)                         | Converts value to float number.                                                                                                        | string \| number | number |
| [toHex](#tohex)                             | Converts bytes to hexadecimal string.                                                                                                  | bytes            | string |
| [toInt](#toint)                             | Converts value to integer number.                                                                                                      | string \| number | number |
| [toString](#tostring)                       | Converts value to string.                                                                                                              | any              | string |
| [urlDecode](#urldecode)                     | Replaces %xx escapes with their single-character equivalent.                                                                           | string           | string |
| [urlEncode](#urlencode)                     | Percent-encodes all the characters which are not included in unreserved chars (see [RFC3986]) with the exception of forward slash (/). | string           | string |
| [urlQueryParam](#urlqueryparam)             | Returns the value of a query parameter in a URL.                                                                                       | string           | string |
| [utf8Decode](#utf8Decode)                   | Decodes bytes to string using UTF-8 encoding.                                                                                          | bytes            | string |
| [utf8Encode](#utf8Encode)                   | Encodes a string to bytes using UTF-8 encoding.                                                                                        | string           | bytes  |
| [xpath](#xpath)                             | Evaluates a [XPath] expression.                                                                                                        | string           | string |

### base64Decode

Decodes a [Base64 encoded string] into bytes.

```hurl
GET https://example.org/api
HTTP 200
[Asserts]
jsonpath "$.token" base64Decode == hex,3c3c3f3f3f3e3e;
```

### base64Encode

Encodes bytes into [Base64 encoded string].

```hurl
GET https://example.org/api
HTTP 200
[Asserts]
bytes base64Encode == "PDw/Pz8+Pg=="
```

### base64UrlSafeDecode

Decodes a Base64 encoded string into bytes (using [Base64 URL safe encoding]).

```hurl
GET https://example.org/api
HTTP 200
[Asserts]
jsonpath "$.token" base64UrlSafeDecode == hex,3c3c3f3f3f3e3e;
```

### base64UrlSafeEncode

Encodes bytes into Base64 encoded string (using [Base64 URL safe encoding]).

```hurl
GET https://example.org/api
HTTP 200
[Asserts]
bytes base64UrlSafeEncode == "PDw_Pz8-Pg"
```

### charsetDecode

*Formerly known as `decode`, which is deprecated and will be removed in a future major version.*

Decodes bytes to string using a charset encoding. Encoding labels are defined in [Encoding Standard].

```hurl
# The 'Content-Type' HTTP response header does not precise the charset 'gb2312'
# so body must be decoded explicitly by Hurl before processing any text based assert
GET https://example.org/hello_china
HTTP 200
[Asserts]
header "Content-Type" == "text/html"
# Content-Type has no encoding clue, we must decode ourselves the body response.
bytes charsetDecode "gb2312" xpath "string(//body)" == "你好世界"
```

When the encoding is UTF-8 (i.e. `charsetDecode "utf-8"`), [an `utf8Decode` filter] can be used instead.

### count

Counts the number of items in a collection.

```hurl
GET https://example.org/api
HTTP 200
[Asserts]
jsonpath "$.books" count == 12
```

### dateFormat

*Formerly known as `format`, which is deprecated and will be removed in a future major version.*

Formats a date to a string given [a specification format].

```hurl
GET https://example.org
HTTP 200
[Asserts]
cookie "LSID[Expires]" dateFormat "%a, %d %b %Y %H:%M:%S" == "Wed, 13 Jan 2021 22:23:01"
```

### daysAfterNow

Returns the number of days between now and a date in the future.

```hurl
GET https://example.org
HTTP 200
[Asserts]
certificate "Expire-Date" daysAfterNow > 15
```

### daysBeforeNow

Returns the number of days between now and a date in the past.

```hurl
GET https://example.org
HTTP 200
[Asserts]
certificate "Start-Date" daysBeforeNow < 100
```

### first

Returns the first element from a collection.

```hurl
GET https://example.org
HTTP 200
[Asserts]
jsonpath "$.books" first == "Dune"
```

### htmlEscape

Converts the characters `&`, `<` and `>` to HTML-safe sequence.

```hurl
GET https://example.org/api
HTTP 200
[Asserts]
jsonpath "$.text" htmlEscape == "a &gt; b"
```

### htmlUnescape

Converts all named and numeric character references (e.g. `&gt;`, `&#62;`, `&#x3e;`) to the corresponding Unicode characters.

```hurl
GET https://example.org/api
HTTP 200
[Asserts]
jsonpath "$.escaped_html[1]" htmlUnescape == "Foo © bar 𝌆"
```

### jsonpath 

Evaluates a [JSONPath] expression.

```hurl
GET https://example.org/api
HTTP 200
[Captures]
books: xpath "string(//body/@data-books)" 
[Asserts]
variable "books" jsonpath "$[0].name" == "Dune"
variable "books" jsonpath "$[0].author" == "Franck Herbert"
```

### last

Returns the last element from a collection.

```hurl
GET https://example.org
HTTP 200
[Asserts]
jsonpath "$.books" last == "Les Misérables"
```

### location

Returns the target URL location of a redirection; the returned URL is always absolute, contrary to the `Location` header from
which it's originated that can be absolute or relative.

```hurl
GET https://example.org/step1
[Options]
location: true
HTTP 200
[Asserts]
redirects count == 2
redirects nth 0 location == "https://example.org/step2"
redirects nth 1 location == "https://example.org/step3"
```

### nth

Returns the element from a collection at a zero-based index, accepts negative indices for indexing from the end of the collection.

```hurl
GET https://example.org/api
HTTP 200
[Asserts]
jsonpath "$.books" nth 2 == "Children of Dune"
```

### regex

Extracts regex capture group. Pattern must have at least one capture group.

```hurl
GET https://example.org/foo
HTTP 200
[Captures]
param1: header "header1"
param2: header "header2" regex "Hello (.*)!"
param3: header "header2" regex /Hello (.*)!/
param3: header "header2" regex /(?i)Hello (.*)!/
```

The regex syntax is documented at <https://docs.rs/regex/latest/regex/#syntax>.

### replace

Replaces all occurrences of old string with new string.

```hurl
GET https://example.org/foo
HTTP 200
[Captures]
url: jsonpath "$.url" replace "http://" "https://"
[Asserts]
jsonpath "$.ips" replace ", " "|" == "192.168.2.1|10.0.0.20|10.0.0.10"
```

### replaceRegex

Replaces all occurrences of a pattern with new string.

```hurl
GET https://example.org/foo
HTTP 200
[Captures]
url: jsonpath "$.id" replaceRegex /\d/ "x"
[Asserts]
jsonpath "$.message" replaceRegex "B[aoi]b" "Dude" == "Welcome Dude!"
```

### split

Splits to a list of strings around occurrences of the specified delimiter.

```hurl
GET https://example.org/foo
HTTP 200
[Asserts]
jsonpath "$.ips" split ", " count == 3
```

### toDate

Converts a string to a date given [a specification format].

```hurl
GET https:///example.org
HTTP 200
[Asserts]
header "Expires" toDate "%a, %d %b %Y %H:%M:%S GMT" daysBeforeNow > 1000
```

ISO 8601 / RFC 3339 date and time format have shorthand format `%+`:

```hurl
GET https://example.org/api/books
HTTP 200
[Asserts]
jsonpath "$.published" == "2023-01-23T18:25:43.511Z"
jsonpath "$.published" toDate "%Y-%m-%dT%H:%M:%S%.fZ" dateFormat "%A" == "Monday"
jsonpath "$.published" toDate "%+" dateFormat "%A" == "Monday" # %+ can be used to parse ISO 8601 / RFC 3339
```

### toFloat

Converts value to float number.

```hurl
GET https://example.org/foo
HTTP 200
[Asserts]
jsonpath "$.pi" toFloat == 3.14
```

### toHex

Converts bytes to hexadecimal string.

```hurl
GET https://example.org/foo
HTTP 200
[Asserts]
bytes toHex == "d188d0b5d0bbd0bbd18b"
```

### toInt

Converts value to integer number.

```hurl
GET https://example.org/foo
HTTP 200
[Asserts]
jsonpath "$.id" toInt == 123
```

### toString

Converts value to string.

```hurl
GET https://example.org/foo
HTTP 200
[Asserts]
jsonpath "$.count" toString == "42"
```

### urlDecode

Replaces %xx escapes with their single-character equivalent.

```hurl
GET https://example.org/foo
HTTP 200
[Asserts]
jsonpath "$.encoded_url" urlDecode == "https://mozilla.org/?x=шеллы"
```

### urlEncode

Percent-encodes all the characters which are not included in unreserved chars (see [RFC3986]) except forward slash (/).

```hurl
GET https://example.org/foo
HTTP 200
[Asserts]
jsonpath "$.url" urlEncode == "https%3A//mozilla.org/%3Fx%3D%D1%88%D0%B5%D0%BB%D0%BB%D1%8B"
```

### urlQueryParam

Returns the value of a query parameter in a URL.

```hurl
GET https://example.org/foo
HTTP 200
[Asserts]
jsonpath "$.url" urlQueryParam "x" == "шеллы"
```

### utf8Decode

Decodes bytes to string using UTF-8 encoding.

```hurl
GET https://example.org/messages
HTTP 200
[Asserts]
# From a Base64 string to UTF-8 bytes to final string 
jsonpath "$.bytesInBase64" base64Decode utf8Decode == "Hello World" 
```

### utf8Encode

Encodes a string to bytes using UTF-8 encoding.

```hurl
GET https://example.org/drinks
HTTP 200
[Asserts]
jsonpath "$.beverage" utf8Encode toHex == "636166C3A9"
```

### xpath

Evaluates a [XPath] expression.

```hurl
GET https://example.org/hello_gb2312
HTTP 200
[Asserts]
bytes charsetDecode "gb2312" xpath "string(//body)" == "你好世界"
```

[Captures]: /docs/capturing-response.md
[asserts]: /docs/asserting-response.md
[RFC3986]: https://www.rfc-editor.org/rfc/rfc3986
[a specification format]: https://docs.rs/chrono/latest/chrono/format/strftime/index.html
[XPath]: https://en.wikipedia.org/wiki/XPath
[JSONPath]: https://goessner.net/articles/JsonPath/
[Base64 encoded string]: https://datatracker.ietf.org/doc/html/rfc4648#section-4
[Base64 URL safe encoding]: https://datatracker.ietf.org/doc/html/rfc4648#section-5
[Encoding Standard]: https://encoding.spec.whatwg.org/#concept-encoding-get
[an `utf8Decode` filter]: /docs/filters.md#utf8decode
[an `utf8Encode` filter]: /docs/filters.md#utf8encode

---

### Frequently Asked Questions (`docs/frequently-asked-questions.md`)

# Frequently Asked Questions

## General

### Why "Hurl"?

The name Hurl is a tribute to the awesome [curl], with a focus on the HTTP protocol.
While it may have an informal meaning not particularly elegant, [other eminent tools] have set a precedent in naming.

### Yet Another Tool, I already use X

We think that Hurl has some advantages compared to similar tools.

Hurl is foremost a command line tool and should be easy to use on a local computer, or in a CI/CD pipeline. Some
tools in the same space as Hurl ([Postman] for instance), are GUI oriented, and we find it
less attractive than CLI. As a command line tool, Hurl can be used to get HTTP data (like [curl]),
but also as a test tool for HTTP sessions, or even as documentation.

Having a text based [file format] is another advantage. The Hurl format is simple,
focused on the HTTP domain, can serve as documentation and can be read or written by non-technical people.

For instance putting JSON data with Hurl can be done with this simple file:

``` 
PUT http://localhost:3000/api/login
{
  "username": "xyz",
  "password": "xyz"
}
```

With [curl]:

```
curl --header "Content-Type: application/json" \
     --request PUT \
     --data '{"username": "xyz","password": "xyz"}' \
     http://localhost:3000/api/login
``` 


[Karate], a tool combining API test automation, mocking, performance-testing, has
similar features but offers also much more at a cost of an increased complexity.

Comparing Karate file format:

```
Scenario: create and retrieve a cat

Given url 'http://myhost.com/v1/cats'
And request { name: 'Billie' }
When method post
Then status 201
And match response == { id: '#notnull', name: 'Billie }

Given path response.id
When method get
Then status 200
``` 

And Hurl:

```
# Scenario: create and retrieve a cat

POST http://myhost.com/v1/cats
{ "name": "Billie" }
HTTP 201
[Captures]
cat_id: jsonpath "$.id"
[Asserts]
jsonpath "$.name" == "Billie"

GET http://myshost.com/v1/cats/{{cat_id}}
HTTP 200
```

A key point of Hurl is to work on the HTTP domain. In particular, there is no JavaScript runtime, Hurl works on the
raw HTTP requests/responses, and not on a DOM managed by a HTML engine. For security, this can be seen as a feature:
let's say you want to test backend validation, you want to be able to bypass the browser or javascript validations and
directly test a backend endpoint.

Finally, with no headless browser and working on the raw HTTP data, Hurl is also
really reliable with a very small probability of false positives. Integration tests with tools like
[Selenium] can, in this regard, be challenging to maintain.

Just use what is convenient for you. In our case, it's Hurl!

### Hurl is build on top of libcurl, but what is added?

Hurl has two main functionalities on top of [curl]:

1. Chain several requests:

   With its [captures], it enables to inject data received from a response into
   following requests. [CSRF tokens]
   are typical examples in a standard web session.

2. Test HTTP responses:

   With its [asserts], responses can be easily tested.

Hurl benefits from the features of the `libcurl` against it is linked. You can check `libcurl` version with `hurl --version`.

For instance on macOS:

```shell
$ hurl --version
hurl 2.0.0 libcurl/7.79.1 (SecureTransport) LibreSSL/3.3.6 zlib/1.2.11 nghttp2/1.45.1
Features (libcurl):  alt-svc AsynchDNS HSTS HTTP2 IPv6 Largefile libz NTLM NTLM_WB SPNEGO SSL UnixSockets
Features (built-in): brotli
```

You can also check which `libcurl` is used.

On macOS:

```shell
$ which hurl
/opt/homebrew/bin/hurl
$ otool -L /opt/homebrew/bin/hurl:
	/usr/lib/libxml2.2.dylib (compatibility version 10.0.0, current version 10.9.0)
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1858.112.0)
	/usr/lib/libcurl.4.dylib (compatibility version 7.0.0, current version 9.0.0)
	/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.100.3)
```

On Linux:

```shell
$ which hurl
/root/.cargo/bin/hurl
$ ldd /root/.cargo/bin/hurl
ldd /root/.cargo/bin/hurl
	linux-vdso.so.1 (0x0000ffff8656a000)
	libxml2.so.2 => /usr/lib/aarch64-linux-gnu/libxml2.so.2 (0x0000ffff85fe8000)
	libcurl.so.4 => /usr/lib/aarch64-linux-gnu/libcurl.so.4 (0x0000ffff85f45000)
	libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x0000ffff85f21000)
	...
	libkeyutils.so.1 => /lib/aarch64-linux-gnu/libkeyutils.so.1 (0x0000ffff82ed5000)
	libffi.so.7 => /usr/lib/aarch64-linux-gnu/libffi.so.7 (0x0000ffff82ebc000)
```

Note that some Hurl features are dependent on `libcurl` capacities: for instance, if your `libcurl` doesn't support
HTTP/2 Hurl won't be able to send HTTP/2 request. 


### Why shouldn't I use Hurl?

If you need a GUI. Currently, Hurl does not offer a GUI version (like [Postman]). While we
think that it can be useful, we prefer to focus for the time-being on the core, keeping something simple and fast.
Contributions to build a GUI are welcome.


### I have a large numbers of tests, how to run just specific tests?

By convention, you can organize Hurl files into different folders or prefix them.

For example, you can split your tests into two folders critical and additional.

```
critical/test1.hurl
critical/test2.hurl
additional/test1.hurl
additional/test2.hurl
```

You can simply run your critical tests with

```shell
$ hurl --test critical/*.hurl
```

### How can I use my Hurl files outside Hurl?

Hurl file can be exported to a JSON file with `hurlfmt`.
This JSON file can then be easily parsed for converting a different format, getting ad-hoc information,...

For example, the Hurl file

```hurl
GET https://example.org/api/users/1
User-Agent: Custom
HTTP 200
[Asserts]
jsonpath "$.name" == "Bob"
```

will be converted to JSON with the following command:

```shell
$ hurlfmt test.hurl --out json | jq
{
  "entries": [
    {
      "request": {
        "method": "GET",
        "url": "https://example.org/api/users/1",
        "headers": [
          {
            "name": "User-Agent",
            "value": "Custom"
          }
        ]
      },
      "response": {
        "version": "HTTP",
        "status": 200,
        "asserts": [
          {
            "query": {
              "type": "jsonpath",
              "expr": "$.name"
            },
            "predicate": {
              "type": "==",
              "value": "Bob"
            }
          }
        ]
      }
    }
  ]
}
```


### Can I do calculation within a Hurl file?

Currently, the templating is very simple, only accessing variables.
Calculations can be done beforehand, before running the Hurl File.

For example, with date calculations, variables `now` and `tomorrow` can be used as param or expected value.

```shell
$ TODAY=$(date '+%y%m%d')
$ TOMORROW=$(date '+%y%m%d' -d"+1days")
$ hurl --variable "today=$TODAY" --variable "tomorrow=$TOMORROW" test.hurl
```

You can also use environment variables that begins with `HURL_VARIABLE_` to inject data in an Hurl file.
For instance, to inject `today` and `tomorrow` variables:

```shell
$ export HURL_VARIABLE_today=$(date '+%y%m%d')
$ export HURL_VARIABLE_tomorrow=$(date '+%y%m%d' -d"+1days")
$ hurl test.hurl
```

You can also use [filters] to process HTTP responses in asserts and captures.

## macOS

### How can I use a custom libcurl (from Homebrew by instance)?

No matter how you've installed Hurl (using the precompiled binary for macOS or with [Homebrew])
Hurl is linked against the built-in system libcurl. If you want to use another libcurl (for instance,
if you've installed curl with Homebrew and want Hurl to use Homebrew's libcurl), you can patch Hurl with
the following command:

```shell
$ sudo install_name_tool -change /usr/lib/libcurl.4.dylib PATH_TO_CUSTOM_LIBCURL PATH_TO_HURL_BIN
```

For instance:

```shell
# /usr/local/opt/curl/lib/libcurl.4.dylib is installed by `brew install curl`
$ sudo install_name_tool -change /usr/lib/libcurl.4.dylib /usr/local/opt/curl/lib/libcurl.4.dylib /usr/local/bin/hurl
```

[curl]: https://curl.haxx.se
[other eminent tools]: https://git.wiki.kernel.org/index.php/GitFaq#Why_the_.27Git.27_name.3F
[Postman]: https://www.postman.com
[file format]: /docs/hurl-file.md
[Karate]: https://github.com/intuit/karate
[Selenium]: https://www.selenium.dev
[captures]: /docs/capturing-response.md
[CSRF tokens]: https://en.wikipedia.org/wiki/Cross-site_request_forgery
[asserts]: /docs/asserting-response.md
[Homebrew]: https://brew.sh
[filters]: /docs/filters.md

---

### Grammar (`docs/grammar.md`)

# Grammar

## Definitions

Short description:

- operator &#124; denotes alternative,
- operator * denotes iteration (zero or more),
- operator + denotes iteration (one or more),

## Syntax Grammar

<div class="grammar-ruleset"><h3 id="general">General</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="hurl-file">hurl-file</span></div><div class="grammar-rule-expression"><a href="#entry">entry</a><span class="grammar-symbol">*</span><br>
<a href="#lt">lt</a><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="entry">entry</span><span class="grammar-usedby">(used by <a href="#hurl-file">hurl-file</a>)</span></div><div class="grammar-rule-expression"><a href="#request">request</a><br>
<a href="#response">response</a><span class="grammar-symbol">?</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="request">request</span><span class="grammar-usedby">(used by <a href="#entry">entry</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<a href="#method">method</a>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#value-string">value-string</a>&nbsp;<a href="#lt">lt</a><br>
<a href="#header">header</a><span class="grammar-symbol">*</span><br>
<a href="#request-section">request-section</a><span class="grammar-symbol">*</span><br>
<a href="#body">body</a><span class="grammar-symbol">?</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="response">response</span><span class="grammar-usedby">(used by <a href="#entry">entry</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<a href="#version">version</a>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#status">status</a>&nbsp;<a href="#lt">lt</a><br>
<a href="#header">header</a><span class="grammar-symbol">*</span><br>
<a href="#response-section">response-section</a><span class="grammar-symbol">*</span><br>
<a href="#body">body</a><span class="grammar-symbol">?</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="method">method</span><span class="grammar-usedby">(used by <a href="#request">request</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[A-Z]+</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="version">version</span><span class="grammar-usedby">(used by <a href="#response">response</a>)</span></div><div class="grammar-rule-expression">&nbsp;<span class="grammar-literal">HTTP/1.0</span><br>
<span class="grammar-symbol">|</span><span class="grammar-literal">HTTP/1.1</span><br>
<span class="grammar-symbol">|</span><span class="grammar-literal">HTTP/2</span><br>
<span class="grammar-symbol">|</span><span class="grammar-literal">HTTP</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="status">status</span><span class="grammar-usedby">(used by <a href="#response">response</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[0-9]+</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="header">header</span><span class="grammar-usedby">(used by <a href="#request">request</a>,&nbsp;<a href="#response">response</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<a href="#key-value">key-value</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="body">body</span><span class="grammar-usedby">(used by <a href="#request">request</a>,&nbsp;<a href="#response">response</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<a href="#bytes">bytes</a>&nbsp;<a href="#lt">lt</a></div></div>
</div><div class="grammar-ruleset"><h3 id="sections">Sections</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="request-section">request-section</span><span class="grammar-usedby">(used by <a href="#request">request</a>)</span></div><div class="grammar-rule-expression">&nbsp;<a href="#basic-auth-section">basic-auth-section</a><br>
<span class="grammar-symbol">|</span><a href="#query-string-params-section">query-string-params-section</a><br>
<span class="grammar-symbol">|</span><a href="#form-params-section">form-params-section</a><br>
<span class="grammar-symbol">|</span><a href="#multipart-form-data-section">multipart-form-data-section</a><br>
<span class="grammar-symbol">|</span><a href="#cookies-section">cookies-section</a><br>
<span class="grammar-symbol">|</span><a href="#options-section">options-section</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="response-section">response-section</span><span class="grammar-usedby">(used by <a href="#response">response</a>)</span></div><div class="grammar-rule-expression">&nbsp;<a href="#captures-section">captures-section</a><br>
<span class="grammar-symbol">|</span><a href="#asserts-section">asserts-section</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="query-string-params-section">query-string-params-section</span><span class="grammar-usedby">(used by <a href="#request-section">request-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<span class="grammar-symbol">(</span><span class="grammar-literal">[QueryStringParams]</span><span class="grammar-symbol">|</span><span class="grammar-literal">[Query]</span><span class="grammar-symbol">)</span>&nbsp;<a href="#lt">lt</a><br>
<a href="#key-value">key-value</a><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="form-params-section">form-params-section</span><span class="grammar-usedby">(used by <a href="#request-section">request-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<span class="grammar-symbol">(</span><span class="grammar-literal">[FormParams]</span><span class="grammar-symbol">|</span><span class="grammar-literal">[Form]</span><span class="grammar-symbol">)</span>&nbsp;<a href="#lt">lt</a><br>
<a href="#key-value">key-value</a><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multipart-form-data-section">multipart-form-data-section</span><span class="grammar-usedby">(used by <a href="#request-section">request-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<span class="grammar-symbol">(</span><span class="grammar-literal">[MultipartFormData]</span><span class="grammar-symbol">|</span><span class="grammar-literal">[Multipart]</span><span class="grammar-symbol">)</span>&nbsp;<a href="#lt">lt</a><br>
<a href="#multipart-form-data-param">multipart-form-data-param</a><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="cookies-section">cookies-section</span><span class="grammar-usedby">(used by <a href="#request-section">request-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<span class="grammar-literal">[Cookies]</span>&nbsp;<a href="#lt">lt</a><br>
<a href="#key-value">key-value</a><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="captures-section">captures-section</span><span class="grammar-usedby">(used by <a href="#response-section">response-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<span class="grammar-literal">[Captures]</span>&nbsp;<a href="#lt">lt</a><br>
<a href="#capture">capture</a><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="asserts-section">asserts-section</span><span class="grammar-usedby">(used by <a href="#response-section">response-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<span class="grammar-literal">[Asserts]</span>&nbsp;<a href="#lt">lt</a><br>
<a href="#assert">assert</a><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="basic-auth-section">basic-auth-section</span><span class="grammar-usedby">(used by <a href="#request-section">request-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<span class="grammar-literal">[BasicAuth]</span>&nbsp;<a href="#lt">lt</a><br>
<a href="#key-value">key-value</a><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="options-section">options-section</span><span class="grammar-usedby">(used by <a href="#request-section">request-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<span class="grammar-literal">[Options]</span>&nbsp;<a href="#lt">lt</a><br>
<a href="#option">option</a><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="key-value">key-value</span><span class="grammar-usedby">(used by <a href="#header">header</a>,&nbsp;<a href="#query-string-params-section">query-string-params-section</a>,&nbsp;<a href="#form-params-section">form-params-section</a>,&nbsp;<a href="#cookies-section">cookies-section</a>,&nbsp;<a href="#basic-auth-section">basic-auth-section</a>,&nbsp;<a href="#multipart-form-data-param">multipart-form-data-param</a>)</span></div><div class="grammar-rule-expression"><a href="#key-string">key-string</a>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#value-string">value-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multipart-form-data-param">multipart-form-data-param</span><span class="grammar-usedby">(used by <a href="#multipart-form-data-section">multipart-form-data-section</a>)</span></div><div class="grammar-rule-expression"><a href="#filename-param">filename-param</a><span class="grammar-symbol">|</span><a href="#key-value">key-value</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-param">filename-param</span><span class="grammar-usedby">(used by <a href="#multipart-form-data-param">multipart-form-data-param</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<a href="#key-string">key-string</a>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#filename-value">filename-value</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-value">filename-value</span><span class="grammar-usedby">(used by <a href="#filename-param">filename-param</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">file,</span>&nbsp;<a href="#filename">filename</a>&nbsp;<span class="grammar-literal">;</span>&nbsp;<span class="grammar-symbol">(</span><a href="#filename-content-type">filename-content-type</a><span class="grammar-symbol">)</span><span class="grammar-symbol">?</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-content-type">filename-content-type</span><span class="grammar-usedby">(used by <a href="#filename-value">filename-value</a>)</span></div><div class="grammar-rule-expression"><a href="#value-string">value-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="capture">capture</span><span class="grammar-usedby">(used by <a href="#captures-section">captures-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<a href="#key-string">key-string</a>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#query">query</a>&nbsp;<span class="grammar-symbol">(</span><a href="#sp">sp</a>&nbsp;<a href="#filter">filter</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span>&nbsp;<span class="grammar-symbol">(</span><a href="#sp">sp</a>&nbsp;<span class="grammar-literal">redact</span><span class="grammar-symbol">)</span><span class="grammar-symbol">?</span>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="assert">assert</span><span class="grammar-usedby">(used by <a href="#asserts-section">asserts-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<a href="#query">query</a>&nbsp;<span class="grammar-symbol">(</span><a href="#sp">sp</a>&nbsp;<a href="#filter">filter</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#predicate">predicate</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="option">option</span><span class="grammar-usedby">(used by <a href="#options-section">options-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br>
<span class="grammar-symbol">(</span><a href="#aws-sigv4-option">aws-sigv4-option</a><span class="grammar-symbol">|</span><a href="#ca-certificate-option">ca-certificate-option</a><span class="grammar-symbol">|</span><a href="#client-certificate-option">client-certificate-option</a><span class="grammar-symbol">|</span><a href="#client-key-option">client-key-option</a><span class="grammar-symbol">|</span><a href="#compressed-option">compressed-option</a><span class="grammar-symbol">|</span><a href="#connect-to-option">connect-to-option</a><span class="grammar-symbol">|</span><a href="#connect-timeout-option">connect-timeout-option</a><span class="grammar-symbol">|</span><a href="#delay-option">delay-option</a><span class="grammar-symbol">|</span><a href="#digest-option">digest-option</a><span class="grammar-symbol">|</span><a href="#fail-with-body-option">fail-with-body-option</a><span class="grammar-symbol">|</span><a href="#follow-redirect-option">follow-redirect-option</a><span class="grammar-symbol">|</span><a href="#follow-redirect-trusted-option">follow-redirect-trusted-option</a><span class="grammar-symbol">|</span><a href="#header-option">header-option</a><span class="grammar-symbol">|</span><a href="#http10-option">http10-option</a><span class="grammar-symbol">|</span><a href="#http11-option">http11-option</a><span class="grammar-symbol">|</span><a href="#http2-option">http2-option</a><span class="grammar-symbol">|</span><a href="#http3-option">http3-option</a><span class="grammar-symbol">|</span><a href="#insecure-option">insecure-option</a><span class="grammar-symbol">|</span><a href="#ipv4-option">ipv4-option</a><span class="grammar-symbol">|</span><a href="#ipv6-option">ipv6-option</a><span class="grammar-symbol">|</span><a href="#limit-rate-option">limit-rate-option</a><span class="grammar-symbol">|</span><a href="#max-redirs-option">max-redirs-option</a><span class="grammar-symbol">|</span><a href="#max-time-option">max-time-option</a><span class="grammar-symbol">|</span><a href="#negotiate-option">negotiate-option</a><span class="grammar-symbol">|</span><a href="#netrc-option">netrc-option</a><span class="grammar-symbol">|</span><a href="#netrc-file-option">netrc-file-option</a><span class="grammar-symbol">|</span><a href="#netrc-optional-option">netrc-optional-option</a><span class="grammar-symbol">|</span><a href="#output-option">output-option</a><span class="grammar-symbol">|</span><a href="#path-as-is-option">path-as-is-option</a><span class="grammar-symbol">|</span><a href="#pinned-public-key-option">pinned-public-key-option</a><span class="grammar-symbol">|</span><a href="#proxy-option">proxy-option</a><span class="grammar-symbol">|</span><a href="#repeat-option">repeat-option</a><span class="grammar-symbol">|</span><a href="#resolve-option">resolve-option</a><span class="grammar-symbol">|</span><a href="#retry-option">retry-option</a><span class="grammar-symbol">|</span><a href="#retry-interval-option">retry-interval-option</a><span class="grammar-symbol">|</span><a href="#skip-option">skip-option</a><span class="grammar-symbol">|</span><a href="#unix-socket-option">unix-socket-option</a><span class="grammar-symbol">|</span><a href="#user-option">user-option</a><span class="grammar-symbol">|</span><a href="#variable-option">variable-option</a><span class="grammar-symbol">|</span><a href="#variables-file-option">variables-file-option</a><span class="grammar-symbol">|</span><a href="#verbose-option">verbose-option</a><span class="grammar-symbol">|</span><a href="#verbosity-option">verbosity-option</a><span class="grammar-symbol">|</span><a href="#very-verbose-option">very-verbose-option</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="aws-sigv4-option">aws-sigv4-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">aws-sigv4</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#value-string">value-string</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="ca-certificate-option">ca-certificate-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">cacert</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#filename">filename</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="client-certificate-option">client-certificate-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">cert</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#filename-password">filename-password</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="client-key-option">client-key-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">key</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#value-string">value-string</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="compressed-option">compressed-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">compressed</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="connect-to-option">connect-to-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">connect-to</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#value-string">value-string</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="connect-timeout-option">connect-timeout-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">connect-timeout</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#duration-option">duration-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="delay-option">delay-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">delay</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#duration-option">duration-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="digest-option">digest-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">digest</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="fail-with-body-option">fail-with-body-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">fail-with-body</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="follow-redirect-option">follow-redirect-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">location</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="follow-redirect-trusted-option">follow-redirect-trusted-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">location-trusted</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="header-option">header-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">header</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#value-string">value-string</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="http10-option">http10-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">http1.0</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="http11-option">http11-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">http1.1</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="http2-option">http2-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">http2</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="http3-option">http3-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">http3</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="insecure-option">insecure-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">insecure</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="ipv4-option">ipv4-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">ipv4</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="ipv6-option">ipv6-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">ipv6</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="limit-rate-option">limit-rate-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">limit-rate</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#integer-option">integer-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="max-redirs-option">max-redirs-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">max-redirs</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#integer-option">integer-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="max-time-option">max-time-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">max-time</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#integer-option">integer-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="negotiate-option">negotiate-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">negotiate</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="netrc-option">netrc-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">netrc</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="netrc-file-option">netrc-file-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">netrc-file</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#value-string">value-string</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="netrc-optional-option">netrc-optional-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">netrc-optional</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="output-option">output-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">output</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#value-string">value-string</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="path-as-is-option">path-as-is-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">path-as-is</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="pinned-public-key-option">pinned-public-key-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">pinnedpubkey</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#value-string">value-string</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="proxy-option">proxy-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">proxy</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#value-string">value-string</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="resolve-option">resolve-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">resolve</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#value-string">value-string</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="repeat-option">repeat-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">repeat</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#integer-option">integer-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="retry-option">retry-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">retry</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#integer-option">integer-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="retry-interval-option">retry-interval-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">retry-interval</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#duration-option">duration-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="skip-option">skip-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">skip</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="unix-socket-option">unix-socket-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">unix-socket</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#value-string">value-string</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="user-option">user-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">user</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#value-string">value-string</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="variable-option">variable-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">variable</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#variable-definition">variable-definition</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="variables-file-option">variables-file-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">variables-file</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#filename">filename</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="verbose-option">verbose-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">verbose</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="verbosity-option">verbosity-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">verbosity</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">brief</span><span class="grammar-symbol">|</span><span class="grammar-literal">verbose</span><span class="grammar-symbol">|</span><span class="grammar-literal">debug</span><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="very-verbose-option">very-verbose-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">very-verbose</span>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#boolean-option">boolean-option</a>&nbsp;<a href="#lt">lt</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="variable-definition">variable-definition</span><span class="grammar-usedby">(used by <a href="#variable-option">variable-option</a>)</span></div><div class="grammar-rule-expression"><a href="#variable-name">variable-name</a>&nbsp;<span class="grammar-literal">=</span>&nbsp;<a href="#variable-value">variable-value</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="boolean-option">boolean-option</span><span class="grammar-usedby">(used by <a href="#compressed-option">compressed-option</a>,&nbsp;<a href="#digest-option">digest-option</a>,&nbsp;<a href="#fail-with-body-option">fail-with-body-option</a>,&nbsp;<a href="#follow-redirect-option">follow-redirect-option</a>,&nbsp;<a href="#follow-redirect-trusted-option">follow-redirect-trusted-option</a>,&nbsp;<a href="#http10-option">http10-option</a>,&nbsp;<a href="#http11-option">http11-option</a>,&nbsp;<a href="#http2-option">http2-option</a>,&nbsp;<a href="#http3-option">http3-option</a>,&nbsp;<a href="#insecure-option">insecure-option</a>,&nbsp;<a href="#ipv4-option">ipv4-option</a>,&nbsp;<a href="#ipv6-option">ipv6-option</a>,&nbsp;<a href="#negotiate-option">negotiate-option</a>,&nbsp;<a href="#netrc-option">netrc-option</a>,&nbsp;<a href="#netrc-optional-option">netrc-optional-option</a>,&nbsp;<a href="#path-as-is-option">path-as-is-option</a>,&nbsp;<a href="#skip-option">skip-option</a>,&nbsp;<a href="#verbose-option">verbose-option</a>,&nbsp;<a href="#very-verbose-option">very-verbose-option</a>)</span></div><div class="grammar-rule-expression"><a href="#boolean">boolean</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="integer-option">integer-option</span><span class="grammar-usedby">(used by <a href="#limit-rate-option">limit-rate-option</a>,&nbsp;<a href="#max-redirs-option">max-redirs-option</a>,&nbsp;<a href="#max-time-option">max-time-option</a>,&nbsp;<a href="#repeat-option">repeat-option</a>,&nbsp;<a href="#retry-option">retry-option</a>)</span></div><div class="grammar-rule-expression"><a href="#integer">integer</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="duration-option">duration-option</span><span class="grammar-usedby">(used by <a href="#connect-timeout-option">connect-timeout-option</a>,&nbsp;<a href="#delay-option">delay-option</a>,&nbsp;<a href="#retry-interval-option">retry-interval-option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#integer">integer</a>&nbsp;<a href="#duration-unit">duration-unit</a><span class="grammar-symbol">?</span><span class="grammar-symbol">)</span><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="duration-unit">duration-unit</span><span class="grammar-usedby">(used by <a href="#duration-option">duration-option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">ms</span><span class="grammar-symbol">|</span><span class="grammar-literal">s</span><span class="grammar-symbol">|</span><span class="grammar-literal">m</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="variable-value">variable-value</span><span class="grammar-usedby">(used by <a href="#variable-definition">variable-definition</a>)</span></div><div class="grammar-rule-expression">&nbsp;<a href="#null">null</a><br>
<span class="grammar-symbol">|</span><a href="#boolean">boolean</a><br>
<span class="grammar-symbol">|</span><a href="#integer">integer</a><br>
<span class="grammar-symbol">|</span><a href="#float">float</a><br>
<span class="grammar-symbol">|</span><a href="#key-string">key-string</a><br>
<span class="grammar-symbol">|</span><a href="#quoted-string">quoted-string</a></div></div>
</div><div class="grammar-ruleset"><h3 id="query">Query</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="query">query</span><span class="grammar-usedby">(used by <a href="#capture">capture</a>,&nbsp;<a href="#assert">assert</a>)</span></div><div class="grammar-rule-expression">&nbsp;<a href="#status-query">status-query</a><br>
<span class="grammar-symbol">|</span><a href="#version-query">version-query</a><br>
<span class="grammar-symbol">|</span><a href="#url-query">url-query</a><br>
<span class="grammar-symbol">|</span><a href="#ip-query">ip-query</a><br>
<span class="grammar-symbol">|</span><a href="#header-query">header-query</a><br>
<span class="grammar-symbol">|</span><a href="#certificate-query">certificate-query</a><br>
<span class="grammar-symbol">|</span><a href="#cookie-query">cookie-query</a><br>
<span class="grammar-symbol">|</span><a href="#body-query">body-query</a><br>
<span class="grammar-symbol">|</span><a href="#xpath-query">xpath-query</a><br>
<span class="grammar-symbol">|</span><a href="#jsonpath-query">jsonpath-query</a><br>
<span class="grammar-symbol">|</span><a href="#regex-query">regex-query</a><br>
<span class="grammar-symbol">|</span><a href="#variable-query">variable-query</a><br>
<span class="grammar-symbol">|</span><a href="#duration-query">duration-query</a><br>
<span class="grammar-symbol">|</span><a href="#bytes-query">bytes-query</a><br>
<span class="grammar-symbol">|</span><a href="#sha256-query">sha256-query</a><br>
<span class="grammar-symbol">|</span><a href="#md5-query">md5-query</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="status-query">status-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">status</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="version-query">version-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">version</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="url-query">url-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">url</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="ip-query">ip-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">ip</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="header-query">header-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">header</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="certificate-query">certificate-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">certificate</span>&nbsp;<a href="#sp">sp</a>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">Subject</span><span class="grammar-symbol">|</span><span class="grammar-literal">Issuer</span><span class="grammar-symbol">|</span><span class="grammar-literal">Start-Date</span><span class="grammar-symbol">|</span><span class="grammar-literal">Expire-Date</span><span class="grammar-symbol">|</span><span class="grammar-literal">Serial-Number</span><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="cookie-query">cookie-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">cookie</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="body-query">body-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">body</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="xpath-query">xpath-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">xpath</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="jsonpath-query">jsonpath-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">jsonpath</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="regex-query">regex-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">regex</span>&nbsp;<a href="#sp">sp</a>&nbsp;<span class="grammar-symbol">(</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#regex">regex</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="variable-query">variable-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">variable</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="duration-query">duration-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">duration</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="sha256-query">sha256-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">sha256</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="md5-query">md5-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">md5</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="bytes-query">bytes-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">bytes</span></div></div>
</div><div class="grammar-ruleset"><h3 id="predicates">Predicates</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="predicate">predicate</span><span class="grammar-usedby">(used by <a href="#assert">assert</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><span class="grammar-literal">not</span>&nbsp;<a href="#sp">sp</a><span class="grammar-symbol">)</span><span class="grammar-symbol">?</span>&nbsp;<a href="#predicate-func">predicate-func</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="predicate-func">predicate-func</span><span class="grammar-usedby">(used by <a href="#predicate">predicate</a>)</span></div><div class="grammar-rule-expression">&nbsp;<a href="#equal-predicate">equal-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#boolean-predicate">boolean-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#contain-predicate">contain-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#end-with-predicate">end-with-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#exist-predicate">exist-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#greater-or-equal-predicate">greater-or-equal-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#greater-predicate">greater-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#include-predicate">include-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#is-collection-predicate">is-collection-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#is-date-predicate">is-date-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#is-float-predicate">is-float-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#is-empty-predicate">is-empty-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#is-integer-predicate">is-integer-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#is-ipv4-predicate">is-ipv4-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#is-ipv6-predicate">is-ipv6-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#is-iso-date-predicate">is-iso-date-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#is-list">is-list</a><br>
<span class="grammar-symbol">|</span><a href="#is-object">is-object</a><br>
<span class="grammar-symbol">|</span><a href="#is-string-predicate">is-string-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#is-uuid-predicate">is-uuid-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#less-or-equal-predicate">less-or-equal-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#less-predicate">less-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#match-predicate">match-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#not-equal-predicate">not-equal-predicate</a><br>
<span class="grammar-symbol">|</span><a href="#start-with-predicate">start-with-predicate</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="equal-predicate">equal-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">==</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#predicate-value">predicate-value</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="boolean-predicate">boolean-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isBoolean</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="contain-predicate">contain-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">contains</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="end-with-predicate">end-with-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">endsWith</span>&nbsp;<a href="#sp">sp</a>&nbsp;<span class="grammar-symbol">(</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#oneline-hex">oneline-hex</a><span class="grammar-symbol">|</span><a href="#oneline-base64">oneline-base64</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="exist-predicate">exist-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">exists</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="greater-or-equal-predicate">greater-or-equal-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">&gt;=</span>&nbsp;<a href="#sp">sp</a>&nbsp;<span class="grammar-symbol">(</span><a href="#number">number</a><span class="grammar-symbol">|</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="greater-predicate">greater-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">&gt;</span>&nbsp;<a href="#sp">sp</a>&nbsp;<span class="grammar-symbol">(</span><a href="#number">number</a><span class="grammar-symbol">|</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="include-predicate">include-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">includes</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#predicate-value">predicate-value</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-collection-predicate">is-collection-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isCollection</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-date-predicate">is-date-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isDate</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-empty-predicate">is-empty-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isEmpty</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-float-predicate">is-float-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isFloat</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-integer-predicate">is-integer-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isInteger</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-ipv4-predicate">is-ipv4-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isIpv4</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-ipv6-predicate">is-ipv6-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isIpv6</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-iso-date-predicate">is-iso-date-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isIsoDate</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-list">is-list</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isList</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-object">is-object</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isObject</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-string-predicate">is-string-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isString</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-uuid-predicate">is-uuid-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isUuid</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="less-or-equal-predicate">less-or-equal-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">&lt;=</span>&nbsp;<a href="#sp">sp</a>&nbsp;<span class="grammar-symbol">(</span><a href="#number">number</a><span class="grammar-symbol">|</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="less-predicate">less-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">&lt;</span>&nbsp;<a href="#sp">sp</a>&nbsp;<span class="grammar-symbol">(</span><a href="#number">number</a><span class="grammar-symbol">|</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="match-predicate">match-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">matches</span>&nbsp;<a href="#sp">sp</a>&nbsp;<span class="grammar-symbol">(</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#regex">regex</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="not-equal-predicate">not-equal-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">!=</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#predicate-value">predicate-value</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="start-with-predicate">start-with-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">startsWith</span>&nbsp;<a href="#sp">sp</a>&nbsp;<span class="grammar-symbol">(</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#oneline-hex">oneline-hex</a><span class="grammar-symbol">|</span><a href="#oneline-base64">oneline-base64</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="predicate-value">predicate-value</span><span class="grammar-usedby">(used by <a href="#equal-predicate">equal-predicate</a>,&nbsp;<a href="#include-predicate">include-predicate</a>,&nbsp;<a href="#not-equal-predicate">not-equal-predicate</a>)</span></div><div class="grammar-rule-expression">&nbsp;<a href="#boolean">boolean</a><br>
<span class="grammar-symbol">|</span><a href="#multiline-string">multiline-string</a><br>
<span class="grammar-symbol">|</span><a href="#null">null</a><br>
<span class="grammar-symbol">|</span><a href="#number">number</a><br>
<span class="grammar-symbol">|</span><a href="#oneline-string">oneline-string</a><br>
<span class="grammar-symbol">|</span><a href="#oneline-base64">oneline-base64</a><br>
<span class="grammar-symbol">|</span><a href="#oneline-file">oneline-file</a><br>
<span class="grammar-symbol">|</span><a href="#oneline-hex">oneline-hex</a><br>
<span class="grammar-symbol">|</span><a href="#quoted-string">quoted-string</a><br>
<span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a></div></div>
</div><div class="grammar-ruleset"><h3 id="bytes">Bytes</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="bytes">bytes</span><span class="grammar-usedby">(used by <a href="#body">body</a>)</span></div><div class="grammar-rule-expression">&nbsp;<a href="#json-value">json-value</a><br>
<span class="grammar-symbol">|</span><a href="#xml">xml</a><br>
<span class="grammar-symbol">|</span><a href="#multiline-string">multiline-string</a><br>
<span class="grammar-symbol">|</span><a href="#oneline-string">oneline-string</a><br>
<span class="grammar-symbol">|</span><a href="#oneline-base64">oneline-base64</a><br>
<span class="grammar-symbol">|</span><a href="#oneline-file">oneline-file</a><br>
<span class="grammar-symbol">|</span><a href="#oneline-hex">oneline-hex</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="xml">xml</span><span class="grammar-usedby">(used by <a href="#bytes">bytes</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">&lt;</span>&nbsp;<span class="grammar-literal">To Be Defined</span>&nbsp;<span class="grammar-literal">&gt;</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-base64">oneline-base64</span><span class="grammar-usedby">(used by <a href="#end-with-predicate">end-with-predicate</a>,&nbsp;<a href="#start-with-predicate">start-with-predicate</a>,&nbsp;<a href="#predicate-value">predicate-value</a>,&nbsp;<a href="#bytes">bytes</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">base64,</span>&nbsp;<span class="grammar-regex">[A-Z0-9+-= \n]+</span>&nbsp;<span class="grammar-literal">;</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-file">oneline-file</span><span class="grammar-usedby">(used by <a href="#predicate-value">predicate-value</a>,&nbsp;<a href="#bytes">bytes</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">file,</span>&nbsp;<a href="#filename">filename</a>&nbsp;<span class="grammar-literal">;</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-hex">oneline-hex</span><span class="grammar-usedby">(used by <a href="#end-with-predicate">end-with-predicate</a>,&nbsp;<a href="#start-with-predicate">start-with-predicate</a>,&nbsp;<a href="#predicate-value">predicate-value</a>,&nbsp;<a href="#bytes">bytes</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">hex,</span>&nbsp;<a href="#hexdigit">hexdigit</a><span class="grammar-symbol">*</span>&nbsp;<span class="grammar-literal">;</span></div></div>
</div><div class="grammar-ruleset"><h3 id="strings">Strings</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="quoted-string">quoted-string</span><span class="grammar-usedby">(used by <a href="#variable-value">variable-value</a>,&nbsp;<a href="#header-query">header-query</a>,&nbsp;<a href="#cookie-query">cookie-query</a>,&nbsp;<a href="#xpath-query">xpath-query</a>,&nbsp;<a href="#jsonpath-query">jsonpath-query</a>,&nbsp;<a href="#regex-query">regex-query</a>,&nbsp;<a href="#variable-query">variable-query</a>,&nbsp;<a href="#contain-predicate">contain-predicate</a>,&nbsp;<a href="#end-with-predicate">end-with-predicate</a>,&nbsp;<a href="#greater-or-equal-predicate">greater-or-equal-predicate</a>,&nbsp;<a href="#greater-predicate">greater-predicate</a>,&nbsp;<a href="#less-or-equal-predicate">less-or-equal-predicate</a>,&nbsp;<a href="#less-predicate">less-predicate</a>,&nbsp;<a href="#match-predicate">match-predicate</a>,&nbsp;<a href="#start-with-predicate">start-with-predicate</a>,&nbsp;<a href="#predicate-value">predicate-value</a>,&nbsp;<a href="#charset-decode-filter">charset-decode-filter</a>,&nbsp;<a href="#date-format-filter">date-format-filter</a>,&nbsp;<a href="#jsonpath-filter">jsonpath-filter</a>,&nbsp;<a href="#regex-filter">regex-filter</a>,&nbsp;<a href="#replace-filter">replace-filter</a>,&nbsp;<a href="#replace-regex-filter">replace-regex-filter</a>,&nbsp;<a href="#split-filter">split-filter</a>,&nbsp;<a href="#to-date-filter">to-date-filter</a>,&nbsp;<a href="#url-query-param-filter">url-query-param-filter</a>,&nbsp;<a href="#xpath-filter">xpath-filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">"</span>&nbsp;<span class="grammar-symbol">(</span><a href="#quoted-string-content">quoted-string-content</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span>&nbsp;<span class="grammar-literal">"</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="quoted-string-content">quoted-string-content</span><span class="grammar-usedby">(used by <a href="#quoted-string">quoted-string</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#quoted-string-text">quoted-string-text</a><span class="grammar-symbol">|</span><a href="#quoted-string-escaped-char">quoted-string-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="quoted-string-text">quoted-string-text</span><span class="grammar-usedby">(used by <a href="#quoted-string-content">quoted-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~["\\]+</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="quoted-string-escaped-char">quoted-string-escaped-char</span><span class="grammar-usedby">(used by <a href="#quoted-string-content">quoted-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">"</span><span class="grammar-symbol">|</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">\b</span><span class="grammar-symbol">|</span><span class="grammar-literal">\f</span><span class="grammar-symbol">|</span><span class="grammar-literal">\n</span><span class="grammar-symbol">|</span><span class="grammar-literal">\r</span><span class="grammar-symbol">|</span><span class="grammar-literal">\t</span><span class="grammar-symbol">|</span><span class="grammar-literal">\u</span>&nbsp;<a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="key-string">key-string</span><span class="grammar-usedby">(used by <a href="#key-value">key-value</a>,&nbsp;<a href="#filename-param">filename-param</a>,&nbsp;<a href="#capture">capture</a>,&nbsp;<a href="#variable-value">variable-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#key-string-content">key-string-content</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span><span class="grammar-symbol">+</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="key-string-content">key-string-content</span><span class="grammar-usedby">(used by <a href="#key-string">key-string</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#key-string-text">key-string-text</a><span class="grammar-symbol">|</span><a href="#key-string-escaped-char">key-string-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="key-string-text">key-string-text</span><span class="grammar-usedby">(used by <a href="#key-string-content">key-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#alphanum">alphanum</a><span class="grammar-symbol">|</span><span class="grammar-literal">_</span><span class="grammar-symbol">|</span><span class="grammar-literal">-</span><span class="grammar-symbol">|</span><span class="grammar-literal">.</span><span class="grammar-symbol">|</span><span class="grammar-literal">[</span><span class="grammar-symbol">|</span><span class="grammar-literal">]</span><span class="grammar-symbol">|</span><span class="grammar-literal">@</span><span class="grammar-symbol">|</span><span class="grammar-literal">$</span><span class="grammar-symbol">)</span><span class="grammar-symbol">+</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="key-string-escaped-char">key-string-escaped-char</span><span class="grammar-usedby">(used by <a href="#key-string-content">key-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">#</span><span class="grammar-symbol">|</span><span class="grammar-literal">:</span><span class="grammar-symbol">|</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">\b</span><span class="grammar-symbol">|</span><span class="grammar-literal">\f</span><span class="grammar-symbol">|</span><span class="grammar-literal">\n</span><span class="grammar-symbol">|</span><span class="grammar-literal">\r</span><span class="grammar-symbol">|</span><span class="grammar-literal">\t</span><span class="grammar-symbol">|</span><span class="grammar-literal">\u</span>&nbsp;<a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="value-string">value-string</span><span class="grammar-usedby">(used by <a href="#request">request</a>,&nbsp;<a href="#key-value">key-value</a>,&nbsp;<a href="#filename-content-type">filename-content-type</a>,&nbsp;<a href="#aws-sigv4-option">aws-sigv4-option</a>,&nbsp;<a href="#client-key-option">client-key-option</a>,&nbsp;<a href="#connect-to-option">connect-to-option</a>,&nbsp;<a href="#header-option">header-option</a>,&nbsp;<a href="#netrc-file-option">netrc-file-option</a>,&nbsp;<a href="#output-option">output-option</a>,&nbsp;<a href="#pinned-public-key-option">pinned-public-key-option</a>,&nbsp;<a href="#proxy-option">proxy-option</a>,&nbsp;<a href="#resolve-option">resolve-option</a>,&nbsp;<a href="#unix-socket-option">unix-socket-option</a>,&nbsp;<a href="#user-option">user-option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#value-string-content">value-string-content</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="value-string-content">value-string-content</span><span class="grammar-usedby">(used by <a href="#value-string">value-string</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#value-string-text">value-string-text</a><span class="grammar-symbol">|</span><a href="#value-string-escaped-char">value-string-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="value-string-text">value-string-text</span><span class="grammar-usedby">(used by <a href="#value-string-content">value-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[#\n\\]+</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="value-string-escaped-char">value-string-escaped-char</span><span class="grammar-usedby">(used by <a href="#value-string-content">value-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">#</span><span class="grammar-symbol">|</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">\b</span><span class="grammar-symbol">|</span><span class="grammar-literal">\f</span><span class="grammar-symbol">|</span><span class="grammar-literal">\n</span><span class="grammar-symbol">|</span><span class="grammar-literal">\r</span><span class="grammar-symbol">|</span><span class="grammar-literal">\t</span><span class="grammar-symbol">|</span><span class="grammar-literal">\u</span>&nbsp;<a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-string">oneline-string</span><span class="grammar-usedby">(used by <a href="#predicate-value">predicate-value</a>,&nbsp;<a href="#bytes">bytes</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">`</span>&nbsp;<span class="grammar-symbol">(</span><a href="#oneline-string-content">oneline-string-content</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span>&nbsp;<span class="grammar-literal">`</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-string-content">oneline-string-content</span><span class="grammar-usedby">(used by <a href="#oneline-string">oneline-string</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#oneline-string-text">oneline-string-text</a><span class="grammar-symbol">|</span><a href="#oneline-string-escaped-char">oneline-string-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-string-text">oneline-string-text</span><span class="grammar-usedby">(used by <a href="#oneline-string-content">oneline-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[#\n\\]</span>&nbsp;<span class="grammar-symbol">~</span><span class="grammar-literal">`</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-string-escaped-char">oneline-string-escaped-char</span><span class="grammar-usedby">(used by <a href="#oneline-string-content">oneline-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">`</span><span class="grammar-symbol">|</span><span class="grammar-literal">#</span><span class="grammar-symbol">|</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">b</span><span class="grammar-symbol">|</span><span class="grammar-literal">f</span><span class="grammar-symbol">|</span><span class="grammar-literal">u</span>&nbsp;<a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multiline-string">multiline-string</span><span class="grammar-usedby">(used by <a href="#predicate-value">predicate-value</a>,&nbsp;<a href="#bytes">bytes</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">```</span>&nbsp;<a href="#multiline-string-type">multiline-string-type</a><span class="grammar-symbol">?</span>&nbsp;<a href="#lt">lt</a><br>
<span class="grammar-symbol">(</span><a href="#multiline-string-content">multiline-string-content</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span>&nbsp;<a href="#lt">lt</a><br>
<span class="grammar-literal">```</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multiline-string-type">multiline-string-type</span><span class="grammar-usedby">(used by <a href="#multiline-string">multiline-string</a>)</span></div><div class="grammar-rule-expression">&nbsp;<span class="grammar-literal">base64</span><br>
<span class="grammar-symbol">|</span><span class="grammar-literal">hex</span><br>
<span class="grammar-symbol">|</span><span class="grammar-literal">json</span><br>
<span class="grammar-symbol">|</span><span class="grammar-literal">xml</span><br>
<span class="grammar-symbol">|</span><span class="grammar-literal">graphql</span><br>
<span class="grammar-symbol">|</span><span class="grammar-literal">raw</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multiline-string-content">multiline-string-content</span><span class="grammar-usedby">(used by <a href="#multiline-string">multiline-string</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#multiline-string-text">multiline-string-text</a><span class="grammar-symbol">|</span><a href="#multiline-string-escaped-char">multiline-string-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multiline-string-text">multiline-string-text</span><span class="grammar-usedby">(used by <a href="#multiline-string-content">multiline-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[\\]+</span>&nbsp;<span class="grammar-symbol">~</span><span class="grammar-literal">```</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multiline-string-escaped-char">multiline-string-escaped-char</span><span class="grammar-usedby">(used by <a href="#multiline-string-content">multiline-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">b</span><span class="grammar-symbol">|</span><span class="grammar-literal">f</span><span class="grammar-symbol">|</span><span class="grammar-literal">n</span><span class="grammar-symbol">|</span><span class="grammar-literal">r</span><span class="grammar-symbol">|</span><span class="grammar-literal">t</span><span class="grammar-symbol">|</span><span class="grammar-literal">`</span><span class="grammar-symbol">|</span><span class="grammar-literal">u</span>&nbsp;<a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename">filename</span><span class="grammar-usedby">(used by <a href="#filename-value">filename-value</a>,&nbsp;<a href="#ca-certificate-option">ca-certificate-option</a>,&nbsp;<a href="#variables-file-option">variables-file-option</a>,&nbsp;<a href="#oneline-file">oneline-file</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#filename-content">filename-content</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-content">filename-content</span><span class="grammar-usedby">(used by <a href="#filename">filename</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#filename-text">filename-text</a><span class="grammar-symbol">|</span><a href="#filename-escaped-char">filename-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-text">filename-text</span><span class="grammar-usedby">(used by <a href="#filename-content">filename-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[#;{} \n\r\\]+</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-escaped-char">filename-escaped-char</span><span class="grammar-usedby">(used by <a href="#filename-content">filename-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">b</span><span class="grammar-symbol">|</span><span class="grammar-literal">f</span><span class="grammar-symbol">|</span><span class="grammar-literal">n</span><span class="grammar-symbol">|</span><span class="grammar-literal">r</span><span class="grammar-symbol">|</span><span class="grammar-literal">t</span><span class="grammar-symbol">|</span><span class="grammar-literal">#</span><span class="grammar-symbol">|</span><span class="grammar-literal">;</span><span class="grammar-symbol">|</span><span class="grammar-literal"> </span><span class="grammar-symbol">|</span><span class="grammar-literal">{</span><span class="grammar-symbol">|</span><span class="grammar-literal">}</span><span class="grammar-symbol">|</span><span class="grammar-literal">u</span>&nbsp;<a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password">filename-password</span><span class="grammar-usedby">(used by <a href="#client-certificate-option">client-certificate-option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#filename-password-content">filename-password-content</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password-content">filename-password-content</span><span class="grammar-usedby">(used by <a href="#filename-password">filename-password</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#filename-password-text">filename-password-text</a><span class="grammar-symbol">|</span><a href="#filename-password-escaped-char">filename-password-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password-text">filename-password-text</span><span class="grammar-usedby">(used by <a href="#filename-password-content">filename-password-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[#;{} \n\r\\]+</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password-escaped-char">filename-password-escaped-char</span><span class="grammar-usedby">(used by <a href="#filename-password-content">filename-password-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">b</span><span class="grammar-symbol">|</span><span class="grammar-literal">f</span><span class="grammar-symbol">|</span><span class="grammar-literal">n</span><span class="grammar-symbol">|</span><span class="grammar-literal">r</span><span class="grammar-symbol">|</span><span class="grammar-literal">t</span><span class="grammar-symbol">|</span><span class="grammar-literal">#</span><span class="grammar-symbol">|</span><span class="grammar-literal">;</span><span class="grammar-symbol">|</span><span class="grammar-literal"> </span><span class="grammar-symbol">|</span><span class="grammar-literal">{</span><span class="grammar-symbol">|</span><span class="grammar-literal">}</span><span class="grammar-symbol">|</span><span class="grammar-literal">:</span><span class="grammar-symbol">|</span><span class="grammar-literal">u</span>&nbsp;<a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="unicode-char">unicode-char</span><span class="grammar-usedby">(used by <a href="#quoted-string-escaped-char">quoted-string-escaped-char</a>,&nbsp;<a href="#key-string-escaped-char">key-string-escaped-char</a>,&nbsp;<a href="#value-string-escaped-char">value-string-escaped-char</a>,&nbsp;<a href="#oneline-string-escaped-char">oneline-string-escaped-char</a>,&nbsp;<a href="#multiline-string-escaped-char">multiline-string-escaped-char</a>,&nbsp;<a href="#filename-escaped-char">filename-escaped-char</a>,&nbsp;<a href="#filename-password-escaped-char">filename-password-escaped-char</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">{</span>&nbsp;<a href="#hexdigit">hexdigit</a><span class="grammar-symbol">+</span>&nbsp;<span class="grammar-literal">}</span></div></div>
</div><div class="grammar-ruleset"><h3 id="json">JSON</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-value">json-value</span><span class="grammar-usedby">(used by <a href="#bytes">bytes</a>,&nbsp;<a href="#json-key-value">json-key-value</a>,&nbsp;<a href="#json-array">json-array</a>)</span></div><div class="grammar-rule-expression">&nbsp;<a href="#placeholder">placeholder</a><br>
<span class="grammar-symbol">|</span><a href="#json-object">json-object</a><br>
<span class="grammar-symbol">|</span><a href="#json-array">json-array</a><br>
<span class="grammar-symbol">|</span><a href="#json-string">json-string</a><br>
<span class="grammar-symbol">|</span><a href="#json-number">json-number</a><br>
<span class="grammar-symbol">|</span><a href="#boolean">boolean</a><br>
<span class="grammar-symbol">|</span><a href="#null">null</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-object">json-object</span><span class="grammar-usedby">(used by <a href="#json-value">json-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">{</span>&nbsp;<a href="#json-key-value">json-key-value</a>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">,</span>&nbsp;<a href="#json-key-value">json-key-value</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span>&nbsp;<span class="grammar-literal">}</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-key-value">json-key-value</span><span class="grammar-usedby">(used by <a href="#json-object">json-object</a>)</span></div><div class="grammar-rule-expression"><a href="#json-string">json-string</a>&nbsp;<span class="grammar-literal">:</span>&nbsp;<a href="#json-value">json-value</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-array">json-array</span><span class="grammar-usedby">(used by <a href="#json-value">json-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">[</span>&nbsp;<a href="#json-value">json-value</a>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">,</span>&nbsp;<a href="#json-value">json-value</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span>&nbsp;<span class="grammar-literal">]</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-string">json-string</span><span class="grammar-usedby">(used by <a href="#json-value">json-value</a>,&nbsp;<a href="#json-key-value">json-key-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">"</span>&nbsp;<span class="grammar-symbol">(</span><a href="#json-string-content">json-string-content</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span>&nbsp;<span class="grammar-literal">"</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-string-content">json-string-content</span><span class="grammar-usedby">(used by <a href="#json-string">json-string</a>)</span></div><div class="grammar-rule-expression"><a href="#json-string-text">json-string-text</a><span class="grammar-symbol">|</span><a href="#json-string-escaped-char">json-string-escaped-char</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-string-text">json-string-text</span><span class="grammar-usedby">(used by <a href="#json-string-content">json-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~["\\]</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-string-escaped-char">json-string-escaped-char</span><span class="grammar-usedby">(used by <a href="#json-string-content">json-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">"</span><span class="grammar-symbol">|</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">b</span><span class="grammar-symbol">|</span><span class="grammar-literal">f</span><span class="grammar-symbol">|</span><span class="grammar-literal">n</span><span class="grammar-symbol">|</span><span class="grammar-literal">r</span><span class="grammar-symbol">|</span><span class="grammar-literal">t</span><span class="grammar-symbol">|</span><span class="grammar-literal">u</span>&nbsp;<a href="#hexdigit">hexdigit</a>&nbsp;<a href="#hexdigit">hexdigit</a>&nbsp;<a href="#hexdigit">hexdigit</a>&nbsp;<a href="#hexdigit">hexdigit</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-number">json-number</span><span class="grammar-usedby">(used by <a href="#json-value">json-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[-]?</span>&nbsp;<a href="#json-integer">json-integer</a>&nbsp;<a href="#fraction">fraction</a><span class="grammar-symbol">?</span>&nbsp;<a href="#exponent">exponent</a><span class="grammar-symbol">?</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-integer">json-integer</span><span class="grammar-usedby">(used by <a href="#json-number">json-number</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">0</span><span class="grammar-symbol">|</span><span class="grammar-regex">[1-9]</span>&nbsp;<a href="#digit">digit</a><span class="grammar-symbol">*</span></div></div>
</div><div class="grammar-ruleset"><h3 id="expression">Expression</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="placeholder">placeholder</span><span class="grammar-usedby">(used by <a href="#boolean-option">boolean-option</a>,&nbsp;<a href="#integer-option">integer-option</a>,&nbsp;<a href="#duration-option">duration-option</a>,&nbsp;<a href="#greater-or-equal-predicate">greater-or-equal-predicate</a>,&nbsp;<a href="#greater-predicate">greater-predicate</a>,&nbsp;<a href="#less-or-equal-predicate">less-or-equal-predicate</a>,&nbsp;<a href="#less-predicate">less-predicate</a>,&nbsp;<a href="#predicate-value">predicate-value</a>,&nbsp;<a href="#quoted-string">quoted-string</a>,&nbsp;<a href="#key-string">key-string</a>,&nbsp;<a href="#value-string">value-string</a>,&nbsp;<a href="#oneline-string">oneline-string</a>,&nbsp;<a href="#multiline-string">multiline-string</a>,&nbsp;<a href="#filename">filename</a>,&nbsp;<a href="#filename-password">filename-password</a>,&nbsp;<a href="#json-value">json-value</a>,&nbsp;<a href="#json-string">json-string</a>,&nbsp;<a href="#nth-filter">nth-filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">{{</span>&nbsp;<a href="#expr">expr</a>&nbsp;<span class="grammar-literal">}}</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="expr">expr</span><span class="grammar-usedby">(used by <a href="#placeholder">placeholder</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#variable-name">variable-name</a><span class="grammar-symbol">|</span><a href="#function">function</a><span class="grammar-symbol">)</span>&nbsp;<span class="grammar-symbol">(</span><a href="#sp">sp</a>&nbsp;<a href="#filter">filter</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="variable-name">variable-name</span><span class="grammar-usedby">(used by <a href="#variable-definition">variable-definition</a>,&nbsp;<a href="#expr">expr</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[A-Za-z]</span>&nbsp;<span class="grammar-regex">[A-Za-z_-0-9]*</span></div></div>
</div><div class="grammar-ruleset"><h3 id="function">Function</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="function">function</span><span class="grammar-usedby">(used by <a href="#expr">expr</a>)</span></div><div class="grammar-rule-expression">&nbsp;<a href="#env-function">env-function</a><br>
<span class="grammar-symbol">|</span><a href="#now-function">now-function</a><br>
<span class="grammar-symbol">|</span><a href="#uuid-function">uuid-function</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="env-function">env-function</span><span class="grammar-usedby">(used by <a href="#function">function</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">getEnv</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="now-function">now-function</span><span class="grammar-usedby">(used by <a href="#function">function</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">newDate</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="uuid-function">uuid-function</span><span class="grammar-usedby">(used by <a href="#function">function</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">newUuid</span></div></div>
</div><div class="grammar-ruleset"><h3 id="filter">Filter</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filter">filter</span><span class="grammar-usedby">(used by <a href="#capture">capture</a>,&nbsp;<a href="#assert">assert</a>,&nbsp;<a href="#expr">expr</a>)</span></div><div class="grammar-rule-expression">&nbsp;<a href="#base64-decode-filter">base64-decode-filter</a><br>
<span class="grammar-symbol">|</span><a href="#base64-encode-filter">base64-encode-filter</a><br>
<span class="grammar-symbol">|</span><a href="#base64-url-safe-decode-filter">base64-url-safe-decode-filter</a><br>
<span class="grammar-symbol">|</span><a href="#base64-url-safe-encode-filter">base64-url-safe-encode-filter</a><br>
<span class="grammar-symbol">|</span><a href="#charset-decode-filter">charset-decode-filter</a><br>
<span class="grammar-symbol">|</span><a href="#count-filter">count-filter</a><br>
<span class="grammar-symbol">|</span><a href="#days-after-now-filter">days-after-now-filter</a><br>
<span class="grammar-symbol">|</span><a href="#days-before-now-filter">days-before-now-filter</a><br>
<span class="grammar-symbol">|</span><a href="#first-filter">first-filter</a><br>
<span class="grammar-symbol">|</span><a href="#date-format-filter">date-format-filter</a><br>
<span class="grammar-symbol">|</span><a href="#html-escape-filter">html-escape-filter</a><br>
<span class="grammar-symbol">|</span><a href="#html-unescape-filter">html-unescape-filter</a><br>
<span class="grammar-symbol">|</span><a href="#jsonpath-filter">jsonpath-filter</a><br>
<span class="grammar-symbol">|</span><a href="#last-filter">last-filter</a><br>
<span class="grammar-symbol">|</span><a href="#location-filter">location-filter</a><br>
<span class="grammar-symbol">|</span><a href="#nth-filter">nth-filter</a><br>
<span class="grammar-symbol">|</span><a href="#regex-filter">regex-filter</a><br>
<span class="grammar-symbol">|</span><a href="#replace-filter">replace-filter</a><br>
<span class="grammar-symbol">|</span><a href="#replace-regex-filter">replace-regex-filter</a><br>
<span class="grammar-symbol">|</span><a href="#split-filter">split-filter</a><br>
<span class="grammar-symbol">|</span><a href="#to-date-filter">to-date-filter</a><br>
<span class="grammar-symbol">|</span><a href="#to-float-filter">to-float-filter</a><br>
<span class="grammar-symbol">|</span><a href="#to-hex-filter">to-hex-filter</a><br>
<span class="grammar-symbol">|</span><a href="#to-int-filter">to-int-filter</a><br>
<span class="grammar-symbol">|</span><a href="#to-string-filter">to-string-filter</a><br>
<span class="grammar-symbol">|</span><a href="#url-decode-filter">url-decode-filter</a><br>
<span class="grammar-symbol">|</span><a href="#url-encode-filter">url-encode-filter</a><br>
<span class="grammar-symbol">|</span><a href="#url-query-param-filter">url-query-param-filter</a><br>
<span class="grammar-symbol">|</span><a href="#utf8-decode-filter">utf8-decode-filter</a><br>
<span class="grammar-symbol">|</span><a href="#utf8-encode-filter">utf8-encode-filter</a><br>
<span class="grammar-symbol">|</span><a href="#xpath-filter">xpath-filter</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="base64-decode-filter">base64-decode-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">base64Decode</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="base64-encode-filter">base64-encode-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">base64Encode</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="base64-url-safe-decode-filter">base64-url-safe-decode-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">base64UrlSafeDecode</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="base64-url-safe-encode-filter">base64-url-safe-encode-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">base64UrlSafeEncode</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="charset-decode-filter">charset-decode-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">charsetDecode</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="count-filter">count-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">count</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="days-after-now-filter">days-after-now-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">daysAfterNow</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="days-before-now-filter">days-before-now-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">daysBeforeNow</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="first-filter">first-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">first</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="date-format-filter">date-format-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">dateFormat</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="html-escape-filter">html-escape-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">htmlEscape</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="html-unescape-filter">html-unescape-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">htmlUnescape</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="jsonpath-filter">jsonpath-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">jsonpath</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="last-filter">last-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">last</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="location-filter">location-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">location</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="nth-filter">nth-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">nth</span>&nbsp;<a href="#sp">sp</a>&nbsp;<span class="grammar-symbol">(</span><a href="#integer">integer</a><span class="grammar-symbol">|</span><a href="#placeholder">placeholder</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="regex-filter">regex-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">regex</span>&nbsp;<a href="#sp">sp</a>&nbsp;<span class="grammar-symbol">(</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#regex">regex</a><span class="grammar-symbol">)</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="replace-filter">replace-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">replace</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="replace-regex-filter">replace-regex-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">replaceRegex</span>&nbsp;<a href="#sp">sp</a>&nbsp;<span class="grammar-symbol">(</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#regex">regex</a><span class="grammar-symbol">)</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="split-filter">split-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">split</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="to-date-filter">to-date-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">toDate</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="to-float-filter">to-float-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">toFloat</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="to-hex-filter">to-hex-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">toHex</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="to-int-filter">to-int-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">toInt</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="to-string-filter">to-string-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">toString</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="url-decode-filter">url-decode-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">urlDecode</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="url-encode-filter">url-encode-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">urlEncode</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="url-query-param-filter">url-query-param-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">urlQueryParam</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="utf8-decode-filter">utf8-decode-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">utf8Decode</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="utf8-encode-filter">utf8-encode-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">utf8Encode</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="xpath-filter">xpath-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">xpath</span>&nbsp;<a href="#sp">sp</a>&nbsp;<a href="#quoted-string">quoted-string</a></div></div>
</div><div class="grammar-ruleset"><h3 id="lexical-grammar">Lexical Grammar</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="boolean">boolean</span><span class="grammar-usedby">(used by <a href="#boolean-option">boolean-option</a>,&nbsp;<a href="#variable-value">variable-value</a>,&nbsp;<a href="#predicate-value">predicate-value</a>,&nbsp;<a href="#json-value">json-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">true</span><span class="grammar-symbol">|</span><span class="grammar-literal">false</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="null">null</span><span class="grammar-usedby">(used by <a href="#variable-value">variable-value</a>,&nbsp;<a href="#predicate-value">predicate-value</a>,&nbsp;<a href="#json-value">json-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">null</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="alphanum">alphanum</span><span class="grammar-usedby">(used by <a href="#key-string-text">key-string-text</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[A-Za-z0-9]</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="integer">integer</span><span class="grammar-usedby">(used by <a href="#integer-option">integer-option</a>,&nbsp;<a href="#duration-option">duration-option</a>,&nbsp;<a href="#variable-value">variable-value</a>,&nbsp;<a href="#nth-filter">nth-filter</a>,&nbsp;<a href="#float">float</a>,&nbsp;<a href="#number">number</a>)</span></div><div class="grammar-rule-expression"><a href="#digit">digit</a><span class="grammar-symbol">+</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="float">float</span><span class="grammar-usedby">(used by <a href="#variable-value">variable-value</a>,&nbsp;<a href="#number">number</a>)</span></div><div class="grammar-rule-expression"><a href="#integer">integer</a>&nbsp;<a href="#fraction">fraction</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="number">number</span><span class="grammar-usedby">(used by <a href="#greater-or-equal-predicate">greater-or-equal-predicate</a>,&nbsp;<a href="#greater-predicate">greater-predicate</a>,&nbsp;<a href="#less-or-equal-predicate">less-or-equal-predicate</a>,&nbsp;<a href="#less-predicate">less-predicate</a>,&nbsp;<a href="#predicate-value">predicate-value</a>)</span></div><div class="grammar-rule-expression"><a href="#integer">integer</a><span class="grammar-symbol">|</span><a href="#float">float</a></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="digit">digit</span><span class="grammar-usedby">(used by <a href="#json-integer">json-integer</a>,&nbsp;<a href="#integer">integer</a>,&nbsp;<a href="#fraction">fraction</a>,&nbsp;<a href="#exponent">exponent</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[0-9]</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="hexdigit">hexdigit</span><span class="grammar-usedby">(used by <a href="#oneline-hex">oneline-hex</a>,&nbsp;<a href="#unicode-char">unicode-char</a>,&nbsp;<a href="#json-string-escaped-char">json-string-escaped-char</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[0-9A-Fa-f]</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="fraction">fraction</span><span class="grammar-usedby">(used by <a href="#json-number">json-number</a>,&nbsp;<a href="#float">float</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">.</span>&nbsp;<a href="#digit">digit</a><span class="grammar-symbol">+</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="exponent">exponent</span><span class="grammar-usedby">(used by <a href="#json-number">json-number</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><span class="grammar-literal">e</span><span class="grammar-symbol">|</span><span class="grammar-literal">E</span><span class="grammar-symbol">)</span>&nbsp;<span class="grammar-symbol">(</span><span class="grammar-literal">+</span><span class="grammar-symbol">|</span><span class="grammar-literal">-</span><span class="grammar-symbol">)</span><span class="grammar-symbol">?</span>&nbsp;<a href="#digit">digit</a><span class="grammar-symbol">+</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="sp">sp</span><span class="grammar-usedby">(used by <a href="#request">request</a>,&nbsp;<a href="#response">response</a>,&nbsp;<a href="#capture">capture</a>,&nbsp;<a href="#assert">assert</a>,&nbsp;<a href="#header-query">header-query</a>,&nbsp;<a href="#certificate-query">certificate-query</a>,&nbsp;<a href="#cookie-query">cookie-query</a>,&nbsp;<a href="#xpath-query">xpath-query</a>,&nbsp;<a href="#jsonpath-query">jsonpath-query</a>,&nbsp;<a href="#regex-query">regex-query</a>,&nbsp;<a href="#variable-query">variable-query</a>,&nbsp;<a href="#predicate">predicate</a>,&nbsp;<a href="#equal-predicate">equal-predicate</a>,&nbsp;<a href="#contain-predicate">contain-predicate</a>,&nbsp;<a href="#end-with-predicate">end-with-predicate</a>,&nbsp;<a href="#greater-or-equal-predicate">greater-or-equal-predicate</a>,&nbsp;<a href="#greater-predicate">greater-predicate</a>,&nbsp;<a href="#include-predicate">include-predicate</a>,&nbsp;<a href="#less-or-equal-predicate">less-or-equal-predicate</a>,&nbsp;<a href="#less-predicate">less-predicate</a>,&nbsp;<a href="#match-predicate">match-predicate</a>,&nbsp;<a href="#not-equal-predicate">not-equal-predicate</a>,&nbsp;<a href="#start-with-predicate">start-with-predicate</a>,&nbsp;<a href="#expr">expr</a>,&nbsp;<a href="#charset-decode-filter">charset-decode-filter</a>,&nbsp;<a href="#date-format-filter">date-format-filter</a>,&nbsp;<a href="#jsonpath-filter">jsonpath-filter</a>,&nbsp;<a href="#nth-filter">nth-filter</a>,&nbsp;<a href="#regex-filter">regex-filter</a>,&nbsp;<a href="#replace-filter">replace-filter</a>,&nbsp;<a href="#replace-regex-filter">replace-regex-filter</a>,&nbsp;<a href="#split-filter">split-filter</a>,&nbsp;<a href="#to-date-filter">to-date-filter</a>,&nbsp;<a href="#url-query-param-filter">url-query-param-filter</a>,&nbsp;<a href="#xpath-filter">xpath-filter</a>,&nbsp;<a href="#lt">lt</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[ \t]</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="lt">lt</span><span class="grammar-usedby">(used by <a href="#hurl-file">hurl-file</a>,&nbsp;<a href="#request">request</a>,&nbsp;<a href="#response">response</a>,&nbsp;<a href="#header">header</a>,&nbsp;<a href="#body">body</a>,&nbsp;<a href="#query-string-params-section">query-string-params-section</a>,&nbsp;<a href="#form-params-section">form-params-section</a>,&nbsp;<a href="#multipart-form-data-section">multipart-form-data-section</a>,&nbsp;<a href="#cookies-section">cookies-section</a>,&nbsp;<a href="#captures-section">captures-section</a>,&nbsp;<a href="#asserts-section">asserts-section</a>,&nbsp;<a href="#basic-auth-section">basic-auth-section</a>,&nbsp;<a href="#options-section">options-section</a>,&nbsp;<a href="#filename-param">filename-param</a>,&nbsp;<a href="#capture">capture</a>,&nbsp;<a href="#assert">assert</a>,&nbsp;<a href="#option">option</a>,&nbsp;<a href="#aws-sigv4-option">aws-sigv4-option</a>,&nbsp;<a href="#ca-certificate-option">ca-certificate-option</a>,&nbsp;<a href="#client-certificate-option">client-certificate-option</a>,&nbsp;<a href="#client-key-option">client-key-option</a>,&nbsp;<a href="#compressed-option">compressed-option</a>,&nbsp;<a href="#connect-to-option">connect-to-option</a>,&nbsp;<a href="#connect-timeout-option">connect-timeout-option</a>,&nbsp;<a href="#delay-option">delay-option</a>,&nbsp;<a href="#digest-option">digest-option</a>,&nbsp;<a href="#fail-with-body-option">fail-with-body-option</a>,&nbsp;<a href="#follow-redirect-option">follow-redirect-option</a>,&nbsp;<a href="#follow-redirect-trusted-option">follow-redirect-trusted-option</a>,&nbsp;<a href="#header-option">header-option</a>,&nbsp;<a href="#http10-option">http10-option</a>,&nbsp;<a href="#http11-option">http11-option</a>,&nbsp;<a href="#http2-option">http2-option</a>,&nbsp;<a href="#http3-option">http3-option</a>,&nbsp;<a href="#insecure-option">insecure-option</a>,&nbsp;<a href="#ipv4-option">ipv4-option</a>,&nbsp;<a href="#ipv6-option">ipv6-option</a>,&nbsp;<a href="#limit-rate-option">limit-rate-option</a>,&nbsp;<a href="#max-redirs-option">max-redirs-option</a>,&nbsp;<a href="#max-time-option">max-time-option</a>,&nbsp;<a href="#negotiate-option">negotiate-option</a>,&nbsp;<a href="#netrc-option">netrc-option</a>,&nbsp;<a href="#netrc-file-option">netrc-file-option</a>,&nbsp;<a href="#netrc-optional-option">netrc-optional-option</a>,&nbsp;<a href="#output-option">output-option</a>,&nbsp;<a href="#path-as-is-option">path-as-is-option</a>,&nbsp;<a href="#pinned-public-key-option">pinned-public-key-option</a>,&nbsp;<a href="#proxy-option">proxy-option</a>,&nbsp;<a href="#resolve-option">resolve-option</a>,&nbsp;<a href="#repeat-option">repeat-option</a>,&nbsp;<a href="#retry-option">retry-option</a>,&nbsp;<a href="#retry-interval-option">retry-interval-option</a>,&nbsp;<a href="#skip-option">skip-option</a>,&nbsp;<a href="#unix-socket-option">unix-socket-option</a>,&nbsp;<a href="#user-option">user-option</a>,&nbsp;<a href="#variable-option">variable-option</a>,&nbsp;<a href="#variables-file-option">variables-file-option</a>,&nbsp;<a href="#verbose-option">verbose-option</a>,&nbsp;<a href="#very-verbose-option">very-verbose-option</a>,&nbsp;<a href="#multiline-string">multiline-string</a>)</span></div><div class="grammar-rule-expression"><a href="#sp">sp</a><span class="grammar-symbol">*</span>&nbsp;<a href="#comment">comment</a><span class="grammar-symbol">?</span>&nbsp;<span class="grammar-regex">[\n]?</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="comment">comment</span><span class="grammar-usedby">(used by <a href="#lt">lt</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">#</span>&nbsp;<span class="grammar-regex">~[\n]*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="regex">regex</span><span class="grammar-usedby">(used by <a href="#regex-query">regex-query</a>,&nbsp;<a href="#match-predicate">match-predicate</a>,&nbsp;<a href="#regex-filter">regex-filter</a>,&nbsp;<a href="#replace-regex-filter">replace-regex-filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">/</span>&nbsp;<a href="#regex-content">regex-content</a>&nbsp;<span class="grammar-literal">/</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="regex-content">regex-content</span><span class="grammar-usedby">(used by <a href="#regex">regex</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#regex-text">regex-text</a><span class="grammar-symbol">|</span><a href="#regex-escaped-char">regex-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="regex-text">regex-text</span><span class="grammar-usedby">(used by <a href="#regex-content">regex-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[\n\/]+</span></div></div>
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="regex-escaped-char">regex-escaped-char</span><span class="grammar-usedby">(used by <a href="#regex-content">regex-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span>&nbsp;<span class="grammar-regex">~[\n]</span></div></div>
</div>

---

### Home (`docs/home.md`)

<div class="home-logo">
    <img class="u-theme-light" src="/docs/assets/img/logo-light.svg" width="277px" height="72px" alt="Hurl logo"/>
    <img class="u-theme-dark" src="/docs/assets/img/logo-dark.svg" width="277px" height="72px" alt="Hurl logo"/>
</div>

# What's Hurl?

Hurl is a command line tool that runs <b>HTTP requests</b> defined in a simple <b>plain text format</b>.

It can chain requests, capture values and evaluate queries on headers and body response. Hurl is very
versatile: it can be used for both <b>fetching data</b> and <b>testing HTTP</b> sessions.

Hurl makes it easy to work with <b>HTML</b> content, <b>REST / SOAP / GraphQL</b> APIs, or any other <b>XML / JSON</b> based APIs. 

```hurl
# Go home and capture token
GET https://example.org
HTTP 200
[Captures]
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"


# Do login!
POST https://example.org/login
[Form]
user: toto
password: 1234
token: {{csrf_token}}
HTTP 302
```

Chaining multiple requests is easy:

```hurl
GET https://example.org/api/health
GET https://example.org/api/step1
GET https://example.org/api/step2
GET https://example.org/api/step3
```

# Also an HTTP Test Tool

Hurl can run HTTP requests but can also be used to <b>test HTTP responses</b>.
Different types of queries and predicates are supported, from [XPath] and [JSONPath] on body response,
to assert on status code and response headers.

<div id="home-demo"></div>

It is well adapted for <b>REST / JSON APIs</b>

```hurl
POST https://example.org/api/tests
{
    "id": "4568",
    "evaluate": true
}
HTTP 200
[Asserts]
header "X-Frame-Options" == "SAMEORIGIN"
jsonpath "$.status" == "RUNNING"    # Check the status code
jsonpath "$.tests" count == 25      # Check the number of items
jsonpath "$.id" matches /\d{4}/     # Check the format of the id
```

<b>HTML content</b>

```hurl
GET https://example.org
HTTP 200
[Asserts]
xpath "normalize-space(//head/title)" == "Hello world!"
```

<b>GraphQL</b> 

~~~hurl
POST https://example.org/graphql
```graphql
{
  human(id: "1000") {
    name
    height(unit: FOOT)
  }
}
```
HTTP 200
~~~

and even <b>SOAP APIs</b>

```hurl
POST https://example.org/InStock
Content-Type: application/soap+xml; charset=utf-8
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="https://example.org">
  <soap:Header></soap:Header>
  <soap:Body>
    <m:GetStockPrice>
      <m:StockName>GOOG</m:StockName>
    </m:GetStockPrice>
  </soap:Body>
</soap:Envelope>
HTTP 200
```

Hurl can also be used to test the <b>performance</b> of HTTP endpoints

```hurl
GET https://example.org/api/v1/pets
HTTP 200
[Asserts]
duration < 1000  # Duration in ms
```

And check response bytes

```hurl
GET https://example.org/data.tar.gz
HTTP 200
[Asserts]
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
```

Finally, Hurl is easy to <b>integrate in CI/CD</b>, with text, JUnit, TAP and HTML reports

<div class="picture">
    <picture>
        <source srcset="/docs/assets/img/home-waterfall-light.avif" type="image/avif">
        <source srcset="/docs/assets/img/home-waterfall-light.webp" type="image/webp">
        <source srcset="/docs/assets/img/home-waterfall-light.png" type="image/png">
        <img class="u-theme-light u-drop-shadow u-border u-max-width-100" src="/docs/assets/img/home-waterfall-light.png" width="480" alt="HTML report"/>
    </picture>
    <picture>
        <source srcset="/docs/assets/img/home-waterfall-dark.avif" type="image/avif">
        <source srcset="/docs/assets/img/home-waterfall-dark.webp" type="image/webp">
        <source srcset="/docs/assets/img/home-waterfall-dark.png" type="image/png">
        <img class="u-theme-dark u-drop-shadow u-border u-max-width-100" src="/docs/assets/img/home-waterfall-dark.png" width="480" alt="HTML report"/>
    </picture>
</div>

# Why Hurl?

<ul class="showcase-container">
    <li class="showcase-item"><h2 class="showcase-item-title">Text Format</h2>For both devops and developers</li>
    <li class="showcase-item"><h2 class="showcase-item-title">Fast CLI</h2>A command line for local dev and continuous integration</li>
    <li class="showcase-item"><h2 class="showcase-item-title">Single Binary</h2>Easy to install, with no runtime required</li>
</ul>

# Powered by curl

Hurl is a lightweight binary written in [Rust]. Under the hood, Hurl HTTP engine is
powered by [libcurl], one of the most powerful and reliable file transfer libraries.
With its text file format, Hurl adds syntactic sugar to run and test HTTP requests,
but it's still the [curl] that we love: __fast__, __efficient__ and __IPv6 / HTTP/3 ready__.

# Feedbacks

To support its development, [star Hurl on GitHub]!

[Feedback, suggestion, bugs or improvements] are welcome.

```hurl
POST https://hurl.dev/api/feedback
{
  "name": "John Doe",
  "feedback": "Hurl is awesome!"
}
HTTP 200
```

# Resources

[License]

[Blog]

[Tutorial]

[Documentation] (download [HTML], [PDF], [Markdown]) 

[GitHub]

[XPath]: https://en.wikipedia.org/wiki/XPath
[JSONPath]: https://goessner.net/articles/JsonPath/
[Rust]: https://www.rust-lang.org
[curl]: https://curl.se
[the installation section]: /docs/installation.md
[Feedback, suggestion, bugs or improvements]: https://github.com/Orange-OpenSource/hurl/issues
[License]: /docs/license.md
[Tutorial]: /docs/tutorial/your-first-hurl-file.md
[Documentation]: /docs/installation.md
[Blog]: blog.md
[GitHub]: https://github.com/Orange-OpenSource/hurl
[libcurl]: https://curl.se/libcurl/
[star Hurl on GitHub]: https://github.com/Orange-OpenSource/hurl/stargazers
[HTML]: /docs/standalone/hurl-8.0.0.html
[PDF]: /docs/standalone/hurl-8.0.0.pdf
[Markdown]: /docs/standalone/hurl-8.0.0.md

---

### Hurl File (`docs/hurl-file.md`)

# Hurl File

## Character Encoding

Hurl file should be encoded in UTF-8, without a byte order mark at the beginning
(while Hurl ignores the presence of a byte order mark rather than treating it as an error)

## File Extension

Hurl file extension is `.hurl`

## Comments

Comments begin with `#` and continue until the end of line. Hurl file can serve as
a documentation for HTTP based workflows so it can be useful to be very descriptive.

```hurl
# A very simple Hurl file
# with tasty comments...
GET https://www.sample.net
x-app: MY_APP  # Add a dummy header
HTTP 302       # Check that we have a redirection
[Asserts]
header "Location" exists
header "Location" contains "login"  # Check that we are redirected to the login page
```

## Special Characters in Strings

String can include the following special characters:

- The escaped special characters \" (double quotation mark), \\ (backslash), \b (backspace), \f (form feed),
 \n (line feed), \r (carriage return), and \t (horizontal tab)
- An arbitrary Unicode scalar value, written as \u{n}, where n is a 1–8 digit hexadecimal number

```hurl
GET https://example.org/api
HTTP 200
# The following assert are equivalent:
[Asserts]
jsonpath "$.slideshow.title" == "A beautiful ✈!"
jsonpath "$.slideshow.title" == "A beautiful \u{2708}!"
```

In some case, (in headers value, etc..), you will also need to escape # to distinguish it from a comment.
In the following example:

```hurl
GET https://example.org/api
x-token: BEEF \#STEAK # Some comment
HTTP 200
```

We're sending a header `x-token` with value `BEEF #STEAK`

---

### Installation (`docs/installation.md`)

# Installation

## Binaries Installation

### Linux

Precompiled binary (depending on libc >=2.35) is available at [Hurl latest GitHub release]:

```shell
$ INSTALL_DIR=/tmp
$ VERSION=8.0.1
$ curl --silent --location https://github.com/Orange-OpenSource/hurl/releases/download/$VERSION/hurl-$VERSION-x86_64-unknown-linux-gnu.tar.gz | tar xvz -C $INSTALL_DIR
$ export PATH=$INSTALL_DIR/hurl-$VERSION-x86_64-unknown-linux-gnu/bin:$PATH
```

#### Debian / Ubuntu

For Debian >=12 / Ubuntu 22.04 and 24.04, Hurl can be installed using a binary .deb file provided in each Hurl release.

```shell
$ VERSION=8.0.1
$ curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/$VERSION/hurl_${VERSION}_amd64.deb
$ sudo apt update && sudo apt install ./hurl_${VERSION}_amd64.deb
```

For Ubuntu >=22.04, Hurl can be installed from `ppa:lepapareil/hurl`

```shell
$ VERSION=8.0.1
$ sudo apt-add-repository -y ppa:lepapareil/hurl
$ sudo apt install hurl="${VERSION}"*
```

#### Alpine

Hurl is available on `testing` channel.

```shell
$ apk add --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing hurl
```

#### Arch Linux / Manjaro

Hurl is available on [extra] channel.

```shell
$ pacman -Sy hurl
```

#### NixOS / Nix

[NixOS / Nix package] is available on stable channel.

#### Guix

```shell
$ guix install hurl
```

### macOS

Precompiled binaries for Intel and ARM CPUs are available at [Hurl latest GitHub release].

#### Homebrew

```shell
$ brew install hurl
```

#### MacPorts

```shell
$ sudo port install hurl
```

### FreeBSD

```shell
$ sudo pkg install hurl
```

### Windows

Windows requires the [Visual C++ Redistributable Package] to be installed manually, as this is not included in the installer.

#### Zip File

Hurl can be installed from a standalone zip file at [Hurl latest GitHub release]. You will need to update your `PATH` variable.

#### Installer

An executable installer is also available at [Hurl latest GitHub release].

#### Chocolatey

```shell
$ choco install hurl
```

#### Scoop

```shell
$ scoop install hurl
```

#### Windows Package Manager

```shell
$ winget install hurl
```

### Cargo

If you're a Rust programmer, Hurl can be installed with cargo.

```shell
$ cargo install --locked hurl
```

### conda-forge

```shell
$ conda install -c conda-forge hurl
```

Hurl can also be installed with [`conda-forge`] powered package manager like [`pixi`].

### Docker

```shell
$ docker pull ghcr.io/orange-opensource/hurl:latest
```

### npm

```shell
$ npm install --save-dev @orangeopensource/hurl
```

## Building From Sources

Hurl sources are available in [GitHub].

### Build on Linux

Hurl depends on libssl, libcurl and libxml2 native libraries. You will need their development files in your platform.

#### Debian based distributions

```shell
$ apt install build-essential pkg-config libssl-dev libcurl4-openssl-dev libxml2-dev libclang-dev
```

#### Fedora based distributions

```shell
$ dnf install pkgconf-pkg-config gcc openssl-devel libxml2-devel clang-devel
```

#### Red Hat based distributions

```shell
$ yum install pkg-config gcc openssl-devel libxml2-devel clang-devel
```

#### Arch based distributions

```shell
$ pacman -S pkgconf gcc glibc openssl libxml2 clang
```

#### Alpine based distributions

```shell
$ apk add curl-dev gcc libxml2-dev musl-dev openssl-dev clang-dev
```

### Build on macOS

```shell
$ xcode-select --install
$ brew install pkg-config openssl
```

Hurl is written in [Rust]. You should [install] the latest stable release.

```shell
$ curl https://sh.rustup.rs -sSf | sh -s -- -y
$ source $HOME/.cargo/env
$ rustc --version
$ cargo --version
```

Then build hurl:

```shell
$ git clone https://github.com/Orange-OpenSource/hurl
$ cd hurl
$ cargo build --release
$ ./target/release/hurl --version
```

### Build on Windows

Please follow the [contrib on Windows section].

[GitHub]: https://github.com/Orange-OpenSource/hurl
[Hurl latest GitHub release]: https://github.com/Orange-OpenSource/hurl/releases/latest
[Visual C++ Redistributable Package]: https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version
[install]: https://www.rust-lang.org/tools/install
[Rust]: https://www.rust-lang.org
[contrib on Windows section]: https://github.com/Orange-OpenSource/hurl/blob/master/contrib/windows/README.md
[NixOS / Nix package]: https://search.nixos.org/packages?from=0&size=1&sort=relevance&type=packages&query=hurl
[`conda-forge`]: https://conda-forge.org
[`pixi`]: https://prefix.dev
[extra]: https://archlinux.org/packages/extra/x86_64/hurl/

---

### License (`docs/license.md`)

# License

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

### Manual (`docs/manual.md`)

# Manual

## Name

hurl - run and test HTTP requests.

## Synopsis

**hurl** [OPTIONS] [FILES...]

**hurl** --test [OPTIONS] [FILES...]

## Description

**Hurl** is a command line tool that runs HTTP requests defined in a simple plain text format.

It can chain requests, capture values and evaluate queries on headers and body response. Hurl is very versatile, it can be used for fetching data and testing HTTP sessions: HTML content, REST / SOAP / GraphQL APIs, or any other XML / JSON based APIs.

```shell
$ hurl session.hurl
```

If no input files are specified, input is read from stdin.

```shell
$ echo GET http://httpbin.org/get | hurl
    {
      "args": {},
      "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip",
        "Content-Length": "0",
        "Host": "httpbin.org",
        "User-Agent": "hurl/0.99.10",
        "X-Amzn-Trace-Id": "Root=1-5eedf4c7-520814d64e2f9249ea44e0"
      },
      "origin": "1.2.3.4",
      "url": "http://httpbin.org/get"
    }
```

Hurl can take files as input, or directories. In the latter case, Hurl will search files with `.hurl` extension recursively.

Output goes to stdout by default. To have output go to a file, use the [`-o, --output`](#output) option:

```shell
$ hurl -o output input.hurl
```

By default, Hurl executes all HTTP requests and outputs the response body of the last HTTP call.

To have a test oriented output, you can use [`--test`](#test) option:

```shell
$ hurl --test *.hurl
```


## Hurl File Format

The Hurl file format is fully documented in [https://hurl.dev/docs/hurl-file.html](https://hurl.dev/docs/hurl-file.html)

It consists of one or several HTTP requests

```hurl
GET http://example.org/endpoint1
GET http://example.org/endpoint2
```


### Capturing values

A value from an HTTP response can be-reused for successive HTTP requests.

A typical example occurs with CSRF tokens.

```hurl
GET https://example.org
HTTP 200
# Capture the CSRF token value from html body.
[Captures]
csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"

# Do the login !
POST https://example.org/login?user=toto&password=1234
X-CSRF-TOKEN: {{csrf_token}}
```

More information on captures can be found here [https://hurl.dev/docs/capturing-response.html](https://hurl.dev/docs/capturing-response.html)

### Asserts

The HTTP response defined in the Hurl file are used to make asserts. Responses are optional.

At the minimum, response includes assert on the HTTP status code.

```hurl
GET http://example.org
HTTP 301
```

It can also include asserts on the response headers

```hurl
GET http://example.org
HTTP 301
Location: http://www.example.org
```

Explicit asserts can be included by combining a query and a predicate

```hurl
GET http://example.org
HTTP 301
[Asserts]
xpath "string(//title)" == "301 Moved"
```

With the addition of asserts, Hurl can be used as a testing tool to run scenarios.

More information on asserts can be found here [https://hurl.dev/docs/asserting-response.html](https://hurl.dev/docs/asserting-response.html)

## Configuration

Options that exist in curl have exactly the same semantics.

Options specified on the command line are defined for every Hurl file's entry, except if they are tagged as cli-only 
(can not be defined in the Hurl request `[Options]` entry)

For instance:

```shell
$ hurl --location foo.hurl
```

will follow redirection for each entry in `foo.hurl`. You can also define an option only for a particular entry with an `[Options]` section. For instance, this Hurl file:

```hurl
GET https://example.org
HTTP 301

GET https://example.org
[Options]
location: true
HTTP 200
```

will follow a redirection only for the second entry.

Hurl looks also for a configuration file at the following places `$XDG_CONFIG_HOME/hurl/config` if `$XDG_CONFIG_HOME` exists,
or `$HOME/.config/hurl/config`. The configuration file is a list of options added to each Hurl run.

```shell
$ cat ~/.config/hurl/config
# Hurl config file
--header x-identifier:quux
--verbose
--delay=1s
--fail-with-body
```

Most of the options can also be defined with environment variables (like `HURL_INSECURE` for [`--insecure`](#insecure)). So, in order
to configure Hurl, there are four sources from the lowest priority (most easily overridden) to highest (overrides all others):

- Configuration file (ex: `~/.config/hurl/config`)
- Environment variables (ex: `export HURL_INSECURE=true`)
- Command-line options (ex: `hurl --insecure`)
- Options section options (ex: `insecure: true` in file)

## All Options

### HTTP options

| Option                                                                                                            | Description                                                                                                                                                                                                                                                                                                                                                                                                                   |
|-------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#aws-sigv4" id="aws-sigv4"><code>--aws-sigv4 &lt;PROVIDER1[:PROVIDER2[:REGION[:SERVICE]]]&gt;</code></a> | Generate an `Authorization` header with an AWS SigV4 signature.<br><br>Use [`-u, --user`](#user) to specify Access Key Id (username) and Secret Key (password).<br><br>To use temporary session credentials (e.g. for an AWS IAM Role), add the `X-Amz-Security-Token` header containing the session token.<br>                                                                                                               |
| <a href="#cacert" id="cacert"><code>--cacert &lt;FILE&gt;</code></a>                                              | Specifies the certificate file for peer verification. The file may contain multiple CA certificates and must be in PEM format.<br>Normally Hurl is built to use a default file for this, so this option is typically used to alter that default file.<br>                                                                                                                                                                     |
| <a href="#cert" id="cert"><code>-E, --cert &lt;CERTIFICATE[:PASSWORD]&gt;</code></a>                              | Client certificate file and password.<br><br>See also [`--key`](#key).<br>                                                                                                                                                                                                                                                                                                                                                    |
| <a href="#compressed" id="compressed"><code>--compressed</code></a>                                               | Request a compressed response using one of the algorithms br, gzip, deflate and automatically decompress the content.<br><br>Environment variables: HURL_COMPRESSED<br>                                                                                                                                                                                                                                                       |
| <a href="#connect-timeout" id="connect-timeout"><code>--connect-timeout &lt;SECONDS&gt;</code></a>                | Maximum time in seconds that you allow Hurl's connection to take.<br><br>You can specify time units in the connect timeout expression. Set Hurl to use a connect timeout of 20 seconds with `--connect-timeout 20s` or set it to 35,000 milliseconds with `--connect-timeout 35000ms`. No spaces allowed.<br><br>See also [`-m, --max-time`](#max-time).<br><br>Environment variables: HURL_CONNECT_TIMEOUT<br>               |
| <a href="#connect-to" id="connect-to"><code>--connect-to &lt;HOST1:PORT1:HOST2:PORT2&gt;</code></a>               | For a request to the given HOST1:PORT1 pair, connect to HOST2:PORT2 instead. This option can be used several times in a command line.<br><br>See also [`--resolve`](#resolve).<br>                                                                                                                                                                                                                                            |
| <a href="#digest" id="digest"><code>--digest</code></a>                                                           | Tell Hurl to use HTTP Digest authentication<br>                                                                                                                                                                                                                                                                                                                                                                               |
| <a href="#header" id="header"><code>-H, --header &lt;NAME:VALUE&gt;</code></a>                                    | Add an extra header to include in information sent. Can be used several times in a command.<br><br>Do not add newlines or carriage returns.<br><br>Environment variables: HURL_HEADER='name1:value1&#124;name2:value2' (headers are separated by &#124;)<br>                                                                                                                                                                  |
| <a href="#http10" id="http10"><code>-0, --http1.0</code></a>                                                      | Tells Hurl to use HTTP version 1.0 instead of using its internally preferred HTTP version.<br><br>Environment variables: HURL_HTTP10<br>                                                                                                                                                                                                                                                                                      |
| <a href="#http11" id="http11"><code>--http1.1</code></a>                                                          | Tells Hurl to use HTTP version 1.1.<br><br>Environment variables: HURL_HTTP11<br>                                                                                                                                                                                                                                                                                                                                             |
| <a href="#http2" id="http2"><code>--http2</code></a>                                                              | Tells Hurl to use HTTP version 2.<br>For HTTPS, this means Hurl negotiates HTTP/2 in the TLS handshake. Hurl does this by default.<br>For HTTP, this means Hurl attempts to upgrade the request to HTTP/2 using the Upgrade: request header.<br><br>Environment variables: HURL_HTTP2<br>                                                                                                                                     |
| <a href="#http2-prior-knowledge" id="http2-prior-knowledge"><code>--http2-prior-knowledge</code></a>              | Tells Hurl to issue a non-TLS HTTP request using HTTP/2 directly without HTTP/1.1 Upgrade. It requires prior knowledge that the server supports HTTP/2 straight away. HTTPS requests still do HTTP/2 the standard way with negotiated protocol versions in the TLS handshake.<br><br>Environment variables: HURL_HTTP2_PRIOR_KNOWLEDGE<br>                                                                                    |
| <a href="#http3" id="http3"><code>--http3</code></a>                                                              | Tells Hurl to try HTTP version 3 to the host in the URL, but fallback to earlier HTTP versions if the HTTP/3 connection establishment fails. HTTP/3 is only available for HTTPS and not for HTTP URLs.<br><br>Environment variables: HURL_HTTP3<br>                                                                                                                                                                           |
| <a href="#insecure" id="insecure"><code>-k, --insecure</code></a>                                                 | This option explicitly allows Hurl to perform "insecure" SSL connections and transfers.<br><br>Environment variables: HURL_INSECURE<br>                                                                                                                                                                                                                                                                                       |
| <a href="#ipv4" id="ipv4"><code>-4, --ipv4</code></a>                                                             | This option tells Hurl to use IPv4 addresses only when resolving host names, and not for example try IPv6.<br><br>Environment variables: HURL_IPV4<br>                                                                                                                                                                                                                                                                        |
| <a href="#ipv6" id="ipv6"><code>-6, --ipv6</code></a>                                                             | This option tells Hurl to use IPv6 addresses only when resolving host names, and not for example try IPv4.<br><br>Environment variables: HURL_IPV6<br>                                                                                                                                                                                                                                                                        |
| <a href="#key" id="key"><code>--key &lt;KEY&gt;</code></a>                                                        | Private key file name.<br>                                                                                                                                                                                                                                                                                                                                                                                                    |
| <a href="#limit-rate" id="limit-rate"><code>--limit-rate &lt;SPEED&gt;</code></a>                                 | Specify the maximum transfer rate you want Hurl to use, for both downloads and uploads. This feature is useful if you have a limited pipe and you would like your transfer not to use your entire bandwidth. To make it slower than it otherwise would be.<br>The given speed is measured in bytes/second.<br><br>Environment variables: HURL_LIMIT_RATE<br>                                                                  |
| <a href="#location" id="location"><code>-L, --location</code></a>                                                 | Follow redirect. To limit the amount of redirects to follow use the [`--max-redirs`](#max-redirs) option<br><br>Environment variables: HURL_LOCATION<br>                                                                                                                                                                                                                                                                      |
| <a href="#location-trusted" id="location-trusted"><code>--location-trusted</code></a>                             | Like [`-L, --location`](#location), but allows sending the name + password to all hosts that the site may redirect to.<br>This may or may not introduce a security breach if the site redirects you to a site to which you send your authentication info (which is plaintext in the case of HTTP Basic authentication).<br><br>Environment variables: HURL_LOCATION_TRUSTED<br>                                               |
| <a href="#max-filesize" id="max-filesize"><code>--max-filesize &lt;BYTES&gt;</code></a>                           | Specify the maximum size in bytes of a file to download. If the file requested is larger than this value, the transfer does not start.<br><br>Environment variables: HURL_MAX_FILESIZE<br><br>This is a cli-only option.<br>                                                                                                                                                                                                  |
| <a href="#max-redirs" id="max-redirs"><code>--max-redirs &lt;NUM&gt;</code></a>                                   | Set maximum number of redirection-followings allowed<br><br>By default, the limit is set to 50 redirections. Set this option to -1 to make it unlimited.<br><br>Environment variables: HURL_MAX_REDIRS<br>                                                                                                                                                                                                                    |
| <a href="#max-time" id="max-time"><code>-m, --max-time &lt;SECONDS&gt;</code></a>                                 | Maximum time in seconds that you allow a request/response to take. This is the standard timeout.<br><br>You can specify time units in the maximum time expression. Set Hurl to use a maximum time of 20 seconds with `--max-time 20s` or set it to 35,000 milliseconds with `--max-time 35000ms`. No spaces allowed.<br><br>See also [`--connect-timeout`](#connect-timeout).<br><br>Environment variables: HURL_MAX_TIME<br> |
| <a href="#negotiate" id="negotiate"><code>--negotiate</code></a>                                                  | Tell Hurl to use Negotiate (SPNEGO) authentication.<br>                                                                                                                                                                                                                                                                                                                                                                       |
| <a href="#no-cookie-store" id="no-cookie-store"><code>--no-cookie-store</code></a>                                | Do not use cookie storage for requests/responses in a file. By default, requests in the same Hurl file share cookie storage, this option deactivates cookie engine.<br><br>Environment variables: HURL_NO_COOKIE_STORE<br><br>This is a cli-only option.<br>                                                                                                                                                                  |
| <a href="#no-header" id="no-header"><code>--no-header &lt;NAME&gt;</code></a>                                     | Remove a header from information sent. Can be used several times in a command.<br><br>Environment variables: HURL_NO_HEADER='name1&#124;name2' (names are separated by &#124;)<br>                                                                                                                                                                                                                                            |
| <a href="#no-proxy" id="no-proxy"><code>--no-proxy &lt;HOST(S)&gt;</code></a>                                     | Comma-separated list of hosts which do not use a proxy.<br><br>Environment variables: no_proxy<br>                                                                                                                                                                                                                                                                                                                            |
| <a href="#ntlm" id="ntlm"><code>--ntlm</code></a>                                                                 | Tell Hurl to use NTLM authentication<br>                                                                                                                                                                                                                                                                                                                                                                                      |
| <a href="#path-as-is" id="path-as-is"><code>--path-as-is</code></a>                                               | Tell Hurl to not handle sequences of /../ or /./ in the given URL path. Normally Hurl will squash or merge them according to standards but with this option set you tell it not to do that.<br>                                                                                                                                                                                                                               |
| <a href="#pinnedpubkey" id="pinnedpubkey"><code>--pinnedpubkey &lt;HASHES&gt;</code></a>                          | When negotiating a TLS or SSL connection, the server sends a certificate indicating its identity. A public key is extracted from this certificate and if it does not exactly match the public key provided to this option, Hurl aborts the connection before sending or receiving any data.<br>                                                                                                                               |
| <a href="#proxy" id="proxy"><code>-x, --proxy &lt;[PROTOCOL://]HOST[:PORT]&gt;</code></a>                         | Use the specified proxy.<br><br>Environment variables: http_proxy https_proxy all_proxy<br>                                                                                                                                                                                                                                                                                                                                   |
| <a href="#proxy-header" id="proxy-header"><code>--proxy-header &lt;HEADER&gt;</code></a>                          | Extra header to include in the request when sending to a proxy. These headers are only applied when a proxy is involved; if Hurl connects directly to the target server, they are ignored.<br><br>Environment variables: HURL_PROXY_HEADER='name1:value1&#124;name2:value2' (headers are separated by &#124;)<br><br>This is a cli-only option.<br>                                                                           |
| <a href="#resolve" id="resolve"><code>--resolve &lt;HOST:PORT:ADDR&gt;</code></a>                                 | Provide a custom address for a specific host and port pair. Using this, you can make the Hurl requests(s) use a specified address and prevent the otherwise normally resolved address to be used. Consider it a sort of /etc/hosts alternative provided on the command line.<br>                                                                                                                                              |
| <a href="#ssl-no-revoke" id="ssl-no-revoke"><code>--ssl-no-revoke</code></a>                                      | (Windows) This option tells Hurl to disable certificate revocation checks. WARNING: this option loosens the SSL security, and by using this flag you ask for exactly that.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                              |
| <a href="#tls-max" id="tls-max"><code>--tls-max &lt;VERSION&gt;</code></a>                                        | Set the maximum allowed TLS version. If the connection is done without TLS, this option has no effect. This includes QUIC-using (HTTP/3) transfers.<br><br>default   Use up to the recommended TLS version.<br>1.0       Use up to TLSv1.0.<br>1.1       Use up to TLSv1.1.<br>1.2       Use up to TLSv1.2.<br>1.3       Use up to TLSv1.3.<br><br>Environment variables: HURL_TLS_MAX<br>                                    |
| <a href="#unix-socket" id="unix-socket"><code>--unix-socket &lt;PATH&gt;</code></a>                               | (HTTP) Connect through this Unix domain socket, instead of using the network.<br>                                                                                                                                                                                                                                                                                                                                             |
| <a href="#user" id="user"><code>-u, --user &lt;USER:PASSWORD&gt;</code></a>                                       | Add basic Authentication header to each request.<br><br>Environment variables: HURL_USER<br>                                                                                                                                                                                                                                                                                                                                  |
| <a href="#user-agent" id="user-agent"><code>-A, --user-agent &lt;NAME&gt;</code></a>                              | Specify the User-Agent string to send to the HTTP server.<br><br>Environment variables: HURL_USER_AGENT<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                 |

### Output options

| Option                                                                                   | Description                                                                                                                                                                                                                                                                                                                                                                                                                           |
|------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#color" id="color"><code>--color</code></a>                                     | Colorize standard output and standard error.<br><br>By default, Hurl outputs a prettified and colorized response. When redirected through pipes, standard streams are not colorized and color can be forced with this option.<br><br>Environment variables: HURL_COLOR<br><br>This is a cli-only option.<br>                                                                                                                          |
| <a href="#curl" id="curl"><code>--curl &lt;FILE&gt;</code></a>                           | Export each request to a list of curl commands.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                                                 |
| <a href="#error-format" id="error-format"><code>--error-format &lt;FORMAT&gt;</code></a> | Control the format of error message (short by default or long).  When using long, the response body is logged when there are errors.<br><br>Environment variables: HURL_ERROR_FORMAT<br><br>This is a cli-only option.<br>                                                                                                                                                                                                            |
| <a href="#fail-with-body" id="fail-with-body"><code>--fail-with-body</code></a>          | Output body response on standard output if there are any errors. By default, Hurl outputs the last body response on standard output only when a run is successful.<br><br>Environment variables: HURL_FAIL_WITH_BODY<br>                                                                                                                                                                                                              |
| <a href="#include" id="include"><code>-i, --include</code></a>                           | Include the HTTP headers in the output<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                                                          |
| <a href="#json" id="json"><code>--json</code></a>                                        | Output each Hurl file result to JSON. The format is very closed to HAR format.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                  |
| <a href="#no-color" id="no-color"><code>--no-color</code></a>                            | Do not colorize standard output nor standard error.<br><br>Environment variables: HURL_NO_COLOR NO_COLOR<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                        |
| <a href="#no-output" id="no-output"><code>--no-output</code></a>                         | Suppress output. By default, Hurl outputs the body of the last response.<br><br>Environment variables: HURL_NO_OUTPUT<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                           |
| <a href="#no-pretty" id="no-pretty"><code>--no-pretty</code></a>                         | Do not prettify response output for supported content type (JSON only for the moment). By default, output is prettified if<br>standard output is a terminal.<br><br>Environment variables: HURL_NO_PRETTY<br><br>This is a cli-only option.<br>                                                                                                                                                                                       |
| <a href="#output" id="output"><code>-o, --output &lt;FILE&gt;</code></a>                 | Write output to FILE instead of stdout. Use '-' for stdout in [Options] sections.<br>                                                                                                                                                                                                                                                                                                                                                 |
| <a href="#pretty" id="pretty"><code>--pretty</code></a>                                  | Prettify response output for supported content type (JSON only for the moment). By default, JSON response is prettified if standard output is a terminal, and colorized, see[`--no-color`](#no-color) to format without color.<br><br>Environment variables: HURL_PRETTY<br><br>This is a cli-only option.<br>                                                                                                                        |
| <a href="#progress-bar" id="progress-bar"><code>--progress-bar</code></a>                | Display a progress bar in test mode. The progress bar is displayed only in interactive TTYs. This option forces the progress bar to be displayed even in non-interactive TTYs.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                  |
| <a href="#verbose" id="verbose"><code>-v, --verbose</code></a>                           | Turn on verbose output on standard error stream.<br>Useful for debugging.<br><br>A line starting with '>' means data sent by Hurl.<br>A line staring with '<' means data received by Hurl.<br>A line starting with '*' means additional info provided by Hurl.<br><br>If you only want HTTP headers in the output, [`-i, --include`](#include) might be the option you're looking for.<br><br>Environment variables: HURL_VERBOSE<br> |
| <a href="#verbosity" id="verbosity"><code>--verbosity &lt;LEVEL&gt;</code></a>           | Set the verbosity level for debug logs on standard error stream (brief, verbose or debug)<br><br>If you only want HTTP headers in the output, [`-i, --include`](#include) might be the option you're looking for.<br>[`-v, --verbose`](#verbose) is an alias for `--verbosity verbose`<br>[`--very-verbose`](#very-verbose) is an alias for `--verbosity debug`<br><br>Environment variables: HURL_VERBOSITY<br>                      |
| <a href="#very-verbose" id="very-verbose"><code>--very-verbose</code></a>                | Turn on more verbose output on standard error stream.<br><br>In contrast to  [`--verbose`](#verbose) option, this option outputs the full HTTP body request and response on standard error. In addition, lines starting with '**' are libcurl debug logs.<br><br>Environment variables: HURL_VERY_VERBOSE<br>                                                                                                                         |

### Run options

| Option                                                                                               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#continue-on-error" id="continue-on-error"><code>--continue-on-error</code></a>             | Continue executing requests to the end of the Hurl file even when an assert error occurs. By default, Hurl exits after an assert error in the HTTP response.<br><br>Note that this option does not affect the behavior with multiple input Hurl files.<br><br>All the input files are executed independently. The result of one file does not affect the execution of the other Hurl files.<br><br>Environment variables: HURL_CONTINUE_ON_ERROR<br><br>This is a cli-only option.<br> |
| <a href="#delay" id="delay"><code>--delay &lt;MILLISECONDS&gt;</code></a>                            | Sets delay before each request (aka sleep). The delay is not applied to requests that have been retried because of [`--retry`](#retry). See [`--retry-interval`](#retry-interval) to space retried requests.<br><br>You can specify time units in the delay expression. Set Hurl to use a delay of 2 seconds with `--delay 2s` or set it to 500 milliseconds with `--delay 500ms`. Supported time units: ms, s, m, h. No spaces allowed.<br><br>Environment variables: HURL_DELAY<br>  |
| <a href="#from-entry" id="from-entry"><code>--from-entry &lt;ENTRY_NUMBER&gt;</code></a>             | Execute Hurl file from ENTRY_NUMBER (starting at 1).<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                                                                                             |
| <a href="#jobs" id="jobs"><code>--jobs &lt;NUM&gt;</code></a>                                        | Maximum number of parallel jobs in parallel mode. Default value corresponds (in most cases) to the current amount of CPUs. Set to 1 to disable parallel execution of files.<br><br>See also [`--parallel`](#parallel).<br><br>Environment variables: HURL_JOBS<br><br>This is a cli-only option.<br>                                                                                                                                                                                   |
| <a href="#no-assert" id="no-assert"><code>--no-assert</code></a>                                     | Ignore all asserts defined in the Hurl file.<br><br>Environment variables: HURL_NO_ASSERT<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                                                        |
| <a href="#no-jsonpath-coercion" id="no-jsonpath-coercion"><code>--no-jsonpath-coercion</code></a>    | Disable JSONPath result coercion.<br><br>By default, when JSONPath coercion is enabled, empty JSONPath results are returned as no value and single JSONPath results are returned as a scalar value. With this option, JSONPath results are always returned as arrays.<br><br>Environment variables: HURL_NO_JSONPATH_COERCION<br>                                                                                                                                                      |
| <a href="#parallel" id="parallel"><code>--parallel</code></a>                                        | Run files in parallel.<br><br>Each Hurl file is executed in its own worker thread, without sharing anything with the other workers. The default run mode is sequential. Parallel execution is by default in [`--test`](#test) mode.<br><br>See also [`--jobs`](#jobs).<br><br>This is a cli-only option.<br>                                                                                                                                                                           |
| <a href="#repeat" id="repeat"><code>--repeat &lt;NUM&gt;</code></a>                                  | Repeat the input files sequence NUM times, -1 for infinite loop. Given a.hurl, b.hurl, c.hurl as input, repeat two<br>times will run a.hurl, b.hurl, c.hurl, a.hurl, b.hurl, c.hurl.<br>                                                                                                                                                                                                                                                                                               |
| <a href="#retry" id="retry"><code>--retry &lt;NUM&gt;</code></a>                                     | Maximum number of retries, 0 for no retries, -1 for unlimited retries. Retry happens if any error occurs (asserts, captures, runtimes etc...).<br><br>Environment variables: HURL_RETRY<br>                                                                                                                                                                                                                                                                                            |
| <a href="#retry-interval" id="retry-interval"><code>--retry-interval &lt;MILLISECONDS&gt;</code></a> | Duration in milliseconds between each retry. Default is 1000 ms.<br><br>You can specify time units in the retry interval expression. Set Hurl to use a retry interval of 2 seconds with `--retry-interval 2s` or set it to 500 milliseconds with `--retry-interval 500ms`. No spaces allowed.<br><br>Environment variables: HURL_RETRY_INTERVAL<br>                                                                                                                                    |
| <a href="#secret" id="secret"><code>--secret &lt;NAME=VALUE&gt;</code></a>                           | Define secret value to be redacted from logs and report. When defined, secrets can be used as variable everywhere variables are used.<br><br>Environment variables: HURL_SECRET_name<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                             |
| <a href="#secrets-file" id="secrets-file"><code>--secrets-file &lt;FILE&gt;</code></a>               | Define a secrets file in which you define your secrets<br><br>Each secret is defined as name=value exactly as with [`--secret`](#secret) option.<br><br>Note that defining a secret twice produces an error.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                     |
| <a href="#test" id="test"><code>--test</code></a>                                                    | Activate test mode: with this, the HTTP response is not outputted anymore, progress is reported for each Hurl file tested, and a text summary is displayed when all files have been run.<br><br>In test mode, files are executed in parallel. To run test in a sequential way use `--jobs 1`.<br><br>See also [`--jobs`](#jobs).<br><br>Environment variables: HURL_TEST<br><br>This is a cli-only option.<br>                                                                         |
| <a href="#to-entry" id="to-entry"><code>--to-entry &lt;ENTRY_NUMBER&gt;</code></a>                   | Execute Hurl file to ENTRY_NUMBER (starting at 1).<br>Ignore the remaining of the file. It is useful for debugging a session.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                                                                                                                    |
| <a href="#variable" id="variable"><code>--variable &lt;NAME=VALUE&gt;</code></a>                     | Define variable (name/value) to be used in Hurl templates.<br><br>Environment variables: HURL_VARIABLE_name<br>                                                                                                                                                                                                                                                                                                                                                                        |
| <a href="#variables-file" id="variables-file"><code>--variables-file &lt;FILE&gt;</code></a>         | Set properties file in which your define your variables.<br><br>Each variable is defined as name=value exactly as with [`--variable`](#variable) option.<br><br>Note that defining a variable twice produces an error.<br><br>This is a cli-only option.<br>                                                                                                                                                                                                                           |

### Report options

| Option                                                                                 | Description                                                                                                                                                |
|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#report-html" id="report-html"><code>--report-html &lt;DIR&gt;</code></a>     | Generate HTML report in DIR.<br><br>If the HTML report already exists, it will be updated with the new test results.<br><br>This is a cli-only option.<br> |
| <a href="#report-json" id="report-json"><code>--report-json &lt;DIR&gt;</code></a>     | Generate JSON report in DIR.<br><br>If the JSON report already exists, it will be updated with the new test results.<br><br>This is a cli-only option.<br> |
| <a href="#report-junit" id="report-junit"><code>--report-junit &lt;FILE&gt;</code></a> | Generate JUnit File.<br><br>If the FILE report already exists, it will be updated with the new test results.<br><br>This is a cli-only option.<br>         |
| <a href="#report-tap" id="report-tap"><code>--report-tap &lt;FILE&gt;</code></a>       | Generate TAP report.<br><br>If the FILE report already exists, it will be updated with the new test results.<br><br>This is a cli-only option.<br>         |

### Other options

| Option                                                                               | Description                                                                                                                                                                                                                                                                                                                                                         |
|--------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <a href="#cookie" id="cookie"><code>-b, --cookie &lt;FILE&gt;</code></a>             | Read cookies from FILE (using the Netscape cookie file format).<br><br>Combined with [`-c, --cookie-jar`](#cookie-jar), you can simulate a cookie storage between successive Hurl runs.<br><br>This is a cli-only option.<br>                                                                                                                                       |
| <a href="#cookie-jar" id="cookie-jar"><code>-c, --cookie-jar &lt;FILE&gt;</code></a> | Write cookies to FILE after running the session.<br>The file will be written using the Netscape cookie file format.<br><br>Combined with [`-b, --cookie`](#cookie), you can simulate a cookie storage between successive Hurl runs.<br><br>This is a cli-only option.<br>                                                                                           |
| <a href="#file-root" id="file-root"><code>--file-root &lt;DIR&gt;</code></a>         | Set root directory to import files in Hurl. This is used for files in multipart form data, request body and response output.<br>When it is not explicitly defined, files are relative to the Hurl file's directory.<br><br>This is a cli-only option.<br>                                                                                                           |
| <a href="#glob" id="glob"><code>--glob &lt;GLOB&gt;</code></a>                       | Specify input files that match the given glob pattern.<br><br>Multiple glob flags may be used. This flag supports common Unix glob patterns like *, ? and [].<br>However, to avoid your shell accidentally expanding glob patterns before Hurl handles them, you must use single quotes or double quotes around each pattern.<br><br>This is a cli-only option.<br> |
| <a href="#netrc" id="netrc"><code>-n, --netrc</code></a>                             | Scan the .netrc file in the user's home directory for the username and password.<br><br>See also [`--netrc-file`](#netrc-file) and [`--netrc-optional`](#netrc-optional).<br>                                                                                                                                                                                       |
| <a href="#netrc-file" id="netrc-file"><code>--netrc-file &lt;FILE&gt;</code></a>     | Like [`--netrc`](#netrc), but provide the path to the netrc file.<br><br>See also [`--netrc-optional`](#netrc-optional).<br>                                                                                                                                                                                                                                        |
| <a href="#netrc-optional" id="netrc-optional"><code>--netrc-optional</code></a>      | Similar to [`--netrc`](#netrc), but make the .netrc usage optional.<br><br>See also [`--netrc-file`](#netrc-file).<br>                                                                                                                                                                                                                                              |
| <a href="#help" id="help"><code>-h, --help</code></a>                                | Usage help. This lists all current command line options with a short description.<br>                                                                                                                                                                                                                                                                               |
| <a href="#version" id="version"><code>-V, --version</code></a>                       | Prints version information<br>                                                                                                                                                                                                                                                                                                                                      |

## Exit Codes

| Value | Description                                             |
|-------|---------------------------------------------------------|
| `0`   | Success.<br>                                            |
| `1`   | Failed to parse command-line options.<br>               |
| `2`   | Input file parsing error.<br>                           |
| `3`   | Runtime error (such as failure to connect to host).<br> |
| `4`   | Assert error.<br>                                       |

## WWW

[https://hurl.dev](https://hurl.dev)


## See Also

curl(1)  hurlfmt(1)

---

--- METRICS ---
- Files Extracted: 38
- Estimated Token Budget: ~125375 tokens
- Canonical Reference: https://codewiki.google/github.com/Orange-OpenSource/hurl
