hurl – Orange-OpenSource
Hurl,用纯文本运行和测试 HTTP 请求。
关键指标一览
主题标签
README 详细介绍
<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>
<img src="https://github.com/Orange-OpenSource/hurl/workflows/test/badge.svg" alt="deploy status" class="ra0-md-img" loading="lazy" />
<img src="https://Orange-OpenSource.github.io/hurl/coverage/badges/flat.svg" alt="coverage" class="ra0-md-img" loading="lazy" />
<img src="https://img.shields.io/crates/v/hurl.svg" alt="Crates.io" class="ra0-md-img" loading="lazy" />
<img src="https://img.shields.io/badge/-documentation-ff0288" alt="documentation" class="ra0-md-img" loading="lazy" />
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.
# 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:
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>
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>
GET https://example.org
HTTP 200
[Asserts]
xpath "normalize-space(//head/title)" == "Hello world!"
<b>GraphQL</b>
~~~hurl
POST https://example.org/graphql
{
human(id: "1000") {
name
height(unit: FOOT)
}
}HTTP 200
~~~
and even <b>SOAP APIs</b>
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
GET https://example.org/api/v1/pets
HTTP 200
[Asserts]
duration < 1000 # Duration in ms
And check response bytes
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.
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
- Getting Data
- HTTP Headers
- Query Params
- Basic Authentication
- Passing Data between Requests
- Sending Data
- Sending HTML Form Data
- Sending Multipart Form Data
- Posting a JSON Body
- Templating a JSON Body
- Templating a XML Body
- Using GraphQL Query
- Using Dynamic Datas
- Testing Response
- Testing Status Code
- Testing Response Headers
- Testing REST APIs
- Testing HTML Response
- Testing Set-Cookie Attributes
- Testing Bytes Content
- SSL Certificate
- Checking Full Body
- Testing Redirections
- Debug Tips
- Verbose Mode
- Error Format
- Output Response Body
- Export curl Commands
- Using Proxy
- Reports
- HTML Report
- JSON Report
- JUnit Report
- TAP Report
- JSON Output
- Others
- HTTP Version
- IP Address
- Polling and Retry
- Delaying Requests
- Skipping Requests
- Testing Endpoint Performance
- Using SOAP APIs
- Capturing and Using a CSRF Token
- Redacting Secrets
- Checking Byte Order Mark (BOM) in Response Body
- AWS Signature Version 4 Requests
- Using curl Options
- Manual
- Name
- Synopsis
- Description
- Hurl File Format
- Capturing values
- Asserts
- Configuration
- All Options
- HTTP options
- Output options
- Run options
- Report options
- Other options
- Exit Codes
- WWW
- See Also
- Installation
- Binaries Installation
- Linux
- Debian / Ubuntu
- Alpine
- Arch Linux / Manjaro
- NixOS / Nix
- macOS
- Homebrew
- MacPorts
- FreeBSD
- Windows
- Zip File
- Installer
- Chocolatey
- Scoop
- Windows Package Manager
- Cargo
- conda-forge
- Docker
- npm
- Building From Sources
- Build on Linux
- Debian based distributions
- Fedora based distributions
- Red Hat based distributions
- Arch based distributions
- Alpine based distributions
- Build on macOS
- Build on Windows
Samples
To run a sample, edit a file with the sample content, and run Hurl:
$ 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]:
$ hurl --test sample.hurl
A particular response can be saved with [[Options] section](https://hurl.dev/docs/request.html#options):
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.
$ hurl --test integration/*.hurl
$ hurl --test .
You can check [Hurl tests suite] for more samples.
Getting Data
A simple GET:
GET https://example.org
Requests can be chained:
GET https://example.org/a
GET https://example.org/b
HEAD https://example.org/c
GET https://example.org/c
HTTP Headers
A simple GET with headers:
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
Query Params
GET https://example.org/news
[Query]
order: newest
search: something to search
count: 100
Or:
GET https://example.org/news?order=newest&search=something%20to%20search&count=100
> With [Query] section, params don't need to be URL escaped.
Basic Authentication
GET https://example.org/protected
[BasicAuth]
bob: secret
This is equivalent to construct the request with a [Authorization] header:
# 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]:
$ hurl --user bob:secret login.hurl
[--user] option can also be set per request:
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:
POST https://sample.org/orders
HTTP 201
[Captures]
order_id: jsonpath "$.order.id"
GET https://sample.org/orders/{{order_id}}
HTTP 200
Sending Data
Sending HTML Form Data
POST https://example.org/contact
[Form]
default: false
token: {{token}}
email: john.doe@rookie.org
number: 33611223344
Sending Multipart Form Data
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
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.
Posting a JSON Body
With an inline JSON:
POST https://example.org/api/tests
{
"id": "456",
"evaluate": true
}
With a local file:
POST https://example.org/api/tests
Content-Type: application/json
file,data.json;
Templating a JSON Body
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:
$ 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
}
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 version="1.0" encoding="utf-8"?>
<Request>
<Login>{{login}}</Login>
<Password>{{password}}</Password>
</Request>~~~
Using GraphQL Query
A simple GraphQL query:
~~~hurl
POST https://example.org/starwars/graphql
{
human(id: "1000") {
name
height(unit: FOOT)
}
}~~~
A GraphQL query with variables:
~~~hurl
POST https://example.org/starwars/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].
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):
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):
GET https://example.org/api/foo
[Query]
date: {{newDate}}
HTTP 200
Testing Response
Responses are optional, everything after HTTP is part of the response asserts.
# 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
GET https://example.org/order/435
HTTP 200
GET https://example.org/order/435
# Testing status code is in a 200-300 range
HTTP *
[Asserts]
status >= 200
status < 300
Testing Response Headers
Use implicit response asserts to test header values:
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
Or use explicit response asserts with [predicates]:
GET https://example.org
HTTP 302
[Asserts]
header "Location" contains "www.example.net"
Implicit and explicit asserts can be combined:
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]:
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
Testing HTML Response
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.*/
Testing Set-Cookie Attributes
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"
Testing Bytes Content
Check the SHA-256 response body hash:
GET https://example.org/data.tar.gz
HTTP 200
[Asserts]
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
SSL Certificate
Check the properties of a SSL certificate:
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-----"
Checking Full Body
Use implicit body to test an exact JSON body match:
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"
}
Or an explicit assert file:
GET https://example.org/index.html
HTTP 200
[Asserts]
body == file,cat.json;
Implicit asserts supports XML body:
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>
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~~~
One line:
POST https://example.org/helloworld
HTTP 200
`Hello world!`
File:
GET https://example.org
HTTP 200
file,data.bin;
Testing Redirections
By default, Hurl doesn't follow redirection so each step of a redirect must be run manually and can be analysed:
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] and [--location-trusted] (either with command line option or per request), Hurl follows
redirection and each step of the redirection can be checked.
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"
GET https://example.org/step1
[Options]
location-trusted: true
HTTP 200
[Asserts]
redirects last location == "https://example.org/step2"
Debug Tips
Verbose Mode
To get more info on a given request/response, use [[Options] section](https://hurl.dev/docs/request.html#options):
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.
Error Format
$ hurl --test --error-format long *.hurl
Output Response Body
Use --output on a specific request to get the response body (- can be used as standard output):
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
Export curl Commands
$ hurl ---curl /tmp/curl.txt *.hurl
Using Proxy
Use --proxy on a specific request or globally as command line option:
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
$ hurl --test --report-html build/report/ *.hurl
JSON Report
$ hurl --test --report-json build/report/ *.hurl
JUnit Report
$ hurl --test --report-junit build/report.xml *.hurl
TAP Report
$ hurl --test --report-tap build/report.txt *.hurl
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.
$ 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:
GET https://foo.com
HTTP/3 200
GET https://bar.com
HTTP/2 200
Or explicit:
GET https://foo.com
HTTP 200
[Asserts]
version == "3"
GET https://bar.com
HTTP 200
[Asserts]
version == "2"
version toFloat > 1.1
IP Address
Testing the IP address of the response, as a string. This string may be IPv6 address:
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...):
# 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"
Delaying Requests
Add delay for every request, or a particular request:
# 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
Skipping Requests
# 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
Testing Endpoint Performance
GET https://sample.org/helloworld
HTTP *
[Asserts]
duration < 1000 # Check that response time is less than one second
Using SOAP APIs
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
Capturing and Using a CSRF Token
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
Redacting Secrets
Using command-line for known values:
$ hurl --secret token=1234 file.hurl
POST https://example.org
X-Token: {{token}}
{
"name": "Alice",
"value": 100
}
HTTP 200
Using redact for dynamic values:
# 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
Checking Byte Order Mark (BOM) in Response Body
GET https://example.org/data.bin
HTTP 200
[Asserts]
bytes startsWith hex,efbbbf;
AWS Signature Version 4 Requests
Generate signed API requests with [AWS Signature Version 4], as used by several cloud providers.
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:
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
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.
$ 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:
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!`
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.
$ hurl session.hurl
If no input files are specified, input is read from stdin.
$ 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 <code class="ra0-md-code">-o, --output</code> option:
$ 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 <code class="ra0-md-code">--test</code> option:
$ hurl --test *.hurl
Hurl File Format
The Hurl file format is fully documented in https://hurl.dev/docs/hurl-file.html
It consists of one or several HTTP requests
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.
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
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.
GET http://example.org
HTTP 301
It can also include asserts on the response headers
GET http://example.org
HTTP 301
Location: http://www.example.org
Explicit asserts can be included by combining a query and a predicate
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
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:
$ 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:
GET https://example.org
HTTP 301
GET https://example.org
[Options]
location: true
HTTP 200
will follow a redirection only for the second entry.
Most of the options can also be defined with environment variables (like HURL_INSECURE for <code class="ra0-md-code">--insecure</code>). So, in order
to configure Hurl, there are three sources from the lowest priority (most easily overridden) to highest (overrides all others):
- Environment variables (ex:
HURL_INSECURE) - Command-line options (ex:
--insecure) - Options section options (ex:
insecure: truein file)
All Options
HTTP options
| Option | Description |
|---|---|
| <a href="#aws-sigv4" id="aws-sigv4"><code>--aws-sigv4 <PROVIDER1[:PROVIDER2[:REGION[:SERVICE]]]></code></a> | Generate an Authorization header with an AWS SigV4 signature.<br><br>Use <code class="ra0-md-code">-u, --user</code> 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 <FILE></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 <CERTIFICATE[:PASSWORD]></code></a> | Client certificate file and password.<br><br>See also <code class="ra0-md-code">--key</code>.<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 <SECONDS></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 <code class="ra0-md-code">-m, --max-time</code>.<br><br>Environment variables: HURL_CONNECT_TIMEOUT<br> |
| <a href="#connect-to" id="connect-to"><code>--connect-to <HOST1:PORT1:HOST2:PORT2></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 <code class="ra0-md-code">--resolve</code>.<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 <NAME:VALUE></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|name2:value2' (headers are separated by |)<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 <KEY></code></a> | Private key file name.<br> |
| <a href="#limit-rate" id="limit-rate"><code>--limit-rate <SPEED></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 <code class="ra0-md-code">--max-redirs</code> option<br><br>Environment variables: HURL_LOCATION<br> |
| <a href="#location-trusted" id="location-trusted"><code>--location-trusted</code></a> | Like <code class="ra0-md-code">-L, --location</code>, 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 <BYTES></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 <NUM></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 <SECONDS></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 <code class="ra0-md-code">--connect-timeout</code>.<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 <NAME></code></a> | Remove a header from information sent. Can be used several times in a command.<br><br>Environment variables: HURL_NO_HEADER='name1|name2' (names are separated by |)<br> |
| <a href="#no-proxy" id="no-proxy"><code>--no-proxy <HOST(S)></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>
<!-- README 已截断 -->