hurl/README.md

1032 lines
32 KiB
Markdown
Raw Normal View History

<img src="https://raw.githubusercontent.com/Orange-OpenSource/hurl/master/art/logo-full-dark.svg?sanitize=true#gh-dark-mode-only" alt="Hurl Logo" width="264px"><img src="https://raw.githubusercontent.com/Orange-OpenSource/hurl/master/art/logo-full-light.svg?sanitize=true#gh-light-mode-only" alt="Hurl Logo" width="264px">
2020-08-27 10:07:46 +03:00
<br/>
[![deploy status](https://github.com/Orange-OpenSource/hurl/workflows/CI/badge.svg)](https://github.com/Orange-OpenSource/hurl/actions)
2022-08-11 23:51:17 +03:00
[![coverage](https://Orange-OpenSource.github.io/hurl/coverage/badges/flat.svg)](https://Orange-OpenSource.github.io/hurl/coverage)
2021-07-03 15:17:29 +03:00
[![Crates.io](https://img.shields.io/crates/v/hurl.svg)](https://crates.io/crates/hurl)
2022-08-19 12:04:16 +03:00
[![documentation](https://img.shields.io/badge/-documentation-ff0288)](https://hurl.dev)
2020-08-27 10:07:46 +03:00
2021-11-12 18:25:13 +03:00
# What's Hurl?
2020-08-27 10:07:46 +03:00
2021-10-22 16:04:50 +03:00
Hurl is a command line tool that runs <b>HTTP requests</b> defined in a simple <b>plain text format</b>.
2022-10-24 21:58:56 +03:00
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>, <b>testing HTTP</b> sessions and testing <b>XML / JSON APIs</b>.
2020-08-27 10:07:46 +03:00
```hurl
# Get home:
2022-05-31 15:38:37 +03:00
GET https://example.org
2020-08-27 10:07:46 +03:00
HTTP/1.1 200
[Captures]
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
# Do login!
2022-05-31 15:38:37 +03:00
POST https://example.org/login?user=toto&password=1234
2020-08-27 10:07:46 +03:00
X-CSRF-TOKEN: {{csrf_token}}
HTTP/1.1 302
```
Chaining multiple requests is easy:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/api/health
GET https://example.org/api/step1
GET https://example.org/api/step2
GET https://example.org/api/step3
2020-08-27 10:07:46 +03:00
```
2021-11-12 18:25:13 +03:00
# Also an HTTP Test Tool
2020-08-27 10:07:46 +03:00
2021-10-22 16:04:50 +03:00
Hurl can run HTTP requests but can also be used to <b>test HTTP responses</b>.
2022-05-31 15:38:37 +03:00
Different types of queries and predicates are supported, from [XPath] and [JSONPath] on body response,
2021-10-22 16:04:50 +03:00
to assert on status code and response headers.
2020-08-27 10:07:46 +03:00
2022-10-26 23:47:04 +03:00
<a href="https://hurl.dev/player.html?id=hurl&speed=3"><img src="https://raw.githubusercontent.com/Orange-OpenSource/hurl/master/docs/assets/img/poster-hurl.png" width="100%" alt="Hurl Demo"/></a>
2022-10-10 18:42:28 +03:00
2022-09-28 11:34:00 +03:00
It is well adapted for <b>REST / JSON APIs</b>
2020-08-27 10:07:46 +03:00
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/api/tests
2020-08-27 10:07:46 +03:00
{
2022-02-11 16:29:06 +03:00
"id": "4568",
2020-08-27 10:07:46 +03:00
"evaluate": true
}
HTTP/1.1 200
[Asserts]
2022-02-15 20:28:49 +03:00
header "X-Frame-Options" == "SAMEORIGIN"
2021-10-22 16:04:50 +03:00
jsonpath "$.status" == "RUNNING" # Check the status code
jsonpath "$.tests" count == 25 # Check the number of items
2022-02-11 16:29:06 +03:00
jsonpath "$.id" matches /\d{4}/ # Check the format of the id
2020-08-27 10:07:46 +03:00
```
2021-10-22 16:04:50 +03:00
<b>HTML content</b>
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org
2021-10-22 16:04:50 +03:00
HTTP/1.1 200
[Asserts]
xpath "normalize-space(//head/title)" == "Hello world!"
```
2022-09-28 11:34:00 +03:00
and even SOAP APIs
2020-08-27 10:07:46 +03:00
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/InStock
2020-08-27 10:07:46 +03:00
Content-Type: application/soap+xml; charset=utf-8
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
<?xml version="1.0" encoding="UTF-8"?>
2022-05-31 15:38:37 +03:00
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="https://example.org">
2020-08-27 10:07:46 +03:00
<soap:Header></soap:Header>
<soap:Body>
<m:GetStockPrice>
<m:StockName>GOOG</m:StockName>
</m:GetStockPrice>
</soap:Body>
</soap:Envelope>
HTTP/1.1 200
```
2022-09-28 11:24:24 +03:00
Hurl can also be used to performance test HTTP endpoints:
2021-02-12 10:52:29 +03:00
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/api/v1/pets
2021-02-12 10:52:29 +03:00
HTTP/1.0 200
[Asserts]
duration < 1000 # Duration in ms
2021-02-12 10:52:29 +03:00
```
2022-09-28 11:24:24 +03:00
And response bytes
2021-10-22 16:04:50 +03:00
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/data.tar.gz
2021-10-22 16:04:50 +03:00
HTTP/1.0 200
[Asserts]
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
```
2021-02-12 10:52:29 +03:00
2021-11-12 18:25:13 +03:00
# Why Hurl?
2021-02-12 10:52:29 +03:00
2021-10-22 16:04:50 +03:00
<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>
2021-11-12 18:25:13 +03:00
# Powered by curl
2021-10-22 16:04:50 +03:00
2022-05-31 15:38:37 +03:00
Hurl is a lightweight binary written in [Rust]. Under the hood, Hurl HTTP engine is
2022-09-28 11:24:24 +03:00
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,
2021-10-22 16:04:50 +03:00
but it's still the [curl] that we love.
2021-11-12 18:25:13 +03:00
# Feedbacks
2021-10-22 16:04:50 +03:00
2021-12-08 20:19:44 +03:00
[Feedback, suggestion, bugs or improvements] are welcome!
2021-10-22 16:04:50 +03:00
```hurl
POST https://hurl.dev/api/feedback
{
"name": "John Doe",
"feedback": "Hurl is awesome !"
}
HTTP/1.1 200
```
2021-11-12 18:25:13 +03:00
# Resources
2021-02-12 10:52:29 +03:00
2021-10-22 16:04:50 +03:00
[License]
2020-08-27 10:07:46 +03:00
2022-02-10 23:51:21 +03:00
[Blog]
2022-06-13 09:06:13 +03:00
[Tutorial]
2021-10-22 16:04:50 +03:00
[Documentation]
2020-08-27 10:07:46 +03:00
2021-10-22 16:04:50 +03:00
[GitHub]
2020-08-27 10:07:46 +03:00
2021-11-08 17:51:59 +03:00
Table of Contents
=================
* [Samples](#samples)
* [Getting Data](#getting-data)
2021-11-20 22:27:44 +03:00
* [HTTP Headers](#http-headers)
2021-11-08 17:51:59 +03:00
* [Query Params](#query-params)
2022-08-29 00:26:11 +03:00
* [Basic Authentication](#basic-authentication)
2021-11-08 17:51:59 +03:00
* [Sending Data](#sending-data)
2022-09-25 13:52:24 +03:00
* [Sending HTML Form Data](#sending-html-form-data)
* [Sending Multipart Form Data](#sending-multipart-form-data)
2021-11-08 17:51:59 +03:00
* [Posting a JSON Body](#posting-a-json-body)
* [Templating a JSON / XML Body](#templating-a-json--xml-body)
* [Testing Response](#testing-response)
* [Testing Response Headers](#testing-response-headers)
2022-09-28 11:34:00 +03:00
* [Testing REST APIs](#testing-rest-apis)
2021-11-08 17:51:59 +03:00
* [Testing HTML Response](#testing-html-response)
* [Testing Set-Cookie Attributes](#testing-set-cookie-attributes)
2022-05-12 17:25:29 +03:00
* [Testing Bytes Content](#testing-bytes-content)
2021-11-08 17:51:59 +03:00
* [Others](#others)
2022-10-24 21:58:56 +03:00
* [Polling and Retry](#polling-and-retry)
2021-11-08 17:51:59 +03:00
* [Testing Endpoint Performance](#testing-endpoint-performance)
2022-09-28 11:34:00 +03:00
* [Using SOAP APIs](#using-soap-apis)
2021-11-08 17:51:59 +03:00
* [Capturing and Using a CSRF Token](#capturing-and-using-a-csrf-token)
* [Checking Byte Order Mark (BOM) in Response Body](#checking-byte-order-mark-bom-in-response-body)
* [Manual](#manual)
2021-11-08 17:51:59 +03:00
* [Name](#name)
* [Synopsis](#synopsis)
* [Description](#description)
* [Hurl File Format](#hurl-file-format)
* [Capturing values](#capturing-values)
* [Asserts](#asserts)
* [Options](#options)
* [Environment](#environment)
* [Exit Codes](#exit-codes)
* [WWW](#www)
* [See Also](#see-also)
* [Installation](#installation)
* [Binaries Installation](#binaries-installation)
* [Linux](#linux)
* [Debian / Ubuntu](#debian--ubuntu)
* [Arch Linux / Manjaro](#arch-linux--manjaro)
2022-04-13 23:09:33 +03:00
* [NixOS / Nix](#nixos--nix)
2021-11-08 17:51:59 +03:00
* [macOS](#macos)
2022-10-10 18:42:28 +03:00
* [Homebrew](#homebrew)
* [MacPorts](#macports)
2021-11-08 17:51:59 +03:00
* [Windows](#windows)
* [Zip File](#zip-file)
* [Installer](#installer)
2021-11-12 18:25:13 +03:00
* [Chocolatey](#chocolatey)
* [Scoop](#scoop)
* [Windows Package Manager](#windows-package-manager)
2021-11-08 17:51:59 +03:00
* [Cargo](#cargo)
2021-12-16 12:32:00 +03:00
* [Docker](#docker)
2022-05-31 15:38:37 +03:00
* [npm](#npm)
2021-11-08 17:51:59 +03:00
* [Building From Sources](#building-from-sources)
2022-08-29 00:26:11 +03:00
* [Build on Linux](#build-on-linux)
2022-04-01 15:27:56 +03:00
* [Debian based distributions](#debian-based-distributions)
* [Red Hat based distributions](#red-hat-based-distributions)
2022-05-31 15:38:37 +03:00
* [Arch based distributions](#arch-based-distributions)
2022-08-29 00:26:11 +03:00
* [Build on macOS](#build-on-macos)
2021-11-08 17:51:59 +03:00
* [Build on Windows](#build-on-windows)
# Samples
2021-12-08 16:27:22 +03:00
To run a sample, edit a file with the sample content, and run Hurl:
2021-02-12 10:52:29 +03:00
2021-11-20 22:27:44 +03:00
```shell
2021-02-12 10:52:29 +03:00
$ vi sample.hurl
2022-05-31 15:38:37 +03:00
GET https://example.org
2021-02-12 10:52:29 +03:00
$ hurl sample.hurl
```
2022-06-13 09:06:13 +03:00
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
```
2022-05-31 15:38:37 +03:00
You can check [Hurl tests suite] for more samples.
2021-10-22 16:04:50 +03:00
## Getting Data
A simple GET:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org
```
[Doc](https://hurl.dev/docs/request.html#method)
2021-11-20 22:27:44 +03:00
### HTTP Headers
A simple GET with headers:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/news
2021-10-22 16:04:50 +03:00
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
2022-05-31 15:38:37 +03:00
GET https://example.org/news
[QueryStringParams]
order: newest
search: something to search
count: 100
```
Or:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/news?order=newest&search=something%20to%20search&count=100
```
[Doc](https://hurl.dev/docs/request.html#query-parameters)
2022-08-29 00:26:11 +03:00
### Basic Authentication
2022-02-11 16:29:06 +03:00
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/protected
2022-02-11 16:29:06 +03:00
[BasicAuth]
bob: secret
```
2022-09-02 16:48:41 +03:00
[Doc](https://hurl.dev/docs/request.html#basic-authentication)
2022-02-11 16:29:06 +03:00
This is equivalent to construct the request with a [Authorization] header:
```hurl
# Authorization header value can be computed with `echo -n 'bob:secret' | base64`
2022-05-31 15:38:37 +03:00
GET https://example.org/protected
2022-02-11 16:29:06 +03:00
Authorization: Basic Ym9iOnNlY3JldA==
```
2022-09-02 16:48:41 +03:00
Basic authentication allows per request authentication.
2022-09-28 11:24:24 +03:00
If you want to add basic authentication to all the requests of a Hurl file
2022-02-11 16:29:06 +03:00
you could use [`-u/--user` option].
## Sending Data
2022-09-25 13:52:24 +03:00
### Sending HTML Form Data
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/contact
[FormParams]
default: false
token: {{token}}
email: john.doe@rookie.org
number: 33611223344
```
[Doc](https://hurl.dev/docs/request.html#form-parameters)
2022-09-25 13:52:24 +03:00
### Sending Multipart Form Data
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/upload
[MultipartFormData]
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)
### Posting a JSON Body
With an inline JSON:
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/api/tests
{
"id": "456",
"evaluate": true
}
```
[Doc](https://hurl.dev/docs/request.html#json-body)
With a local file:
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/api/tests
Content-Type: application/json
file,data.json;
```
[Doc](https://hurl.dev/docs/request.html#file-body)
2021-10-22 16:04:50 +03:00
### Templating a JSON / XML Body
2022-05-31 15:38:37 +03:00
Using templates with [JSON body] or [XML body] is not currently supported in Hurl.
Besides, you can use templates in [multiline string body] with variables to send a JSON or XML body:
2020-11-10 09:22:48 +03:00
~~~hurl
2022-05-31 15:38:37 +03:00
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:
2021-11-20 22:27:44 +03:00
```shell
2022-02-11 16:29:06 +03:00
$ hurl --variable a_string=apple \
--variable a_bool=true \
--variable a_null=null \
--variable a_number=42 \
2021-10-22 16:04:50 +03:00
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/request.html#multiline-string-body)
## Testing Response
2021-02-12 10:52:29 +03:00
### Testing Response Headers
Use implicit response asserts to test header values:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/index.html
2021-02-12 10:52:29 +03:00
HTTP/1.0 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)
2021-10-22 16:04:50 +03:00
Or use explicit response asserts with [predicates]:
2021-02-12 10:52:29 +03:00
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org
2021-02-12 10:52:29 +03:00
HTTP/1.1 302
[Asserts]
header "Location" contains "www.example.net"
```
2021-10-22 16:04:50 +03:00
[Doc](https://hurl.dev/docs/asserting-response.html#header-assert)
2021-02-12 10:52:29 +03:00
2022-09-28 11:34:00 +03:00
### Testing REST APIs
2021-11-20 22:27:44 +03:00
Asserting JSON body response (node values, collection count etc...) with [JSONPath]:
2021-02-12 10:52:29 +03:00
```hurl
2021-11-20 22:27:44 +03:00
GET https://example.org/order
screencapability: low
HTTP/1.1 200
[Asserts]
jsonpath "$.validated" == true
jsonpath "$.userInfo.firstName" == "Franck"
jsonpath "$.userInfo.lastName" == "Herbert"
jsonpath "$.hasDevice" == false
jsonpath "$.links" count == 12
jsonpath "$.state" != null
2022-02-11 16:29:06 +03:00
jsonpath "$.order" matches "^order-\\d{8}$"
2022-09-25 13:52:24 +03:00
jsonpath "$.order" matches /^order-\d{8}$/ # Alternative syntax with regex literal
```
[Doc](https://hurl.dev/docs/asserting-response.html#jsonpath-assert)
2021-12-08 16:27:22 +03:00
2021-02-12 10:52:29 +03:00
Testing status code:
```hurl
2021-11-20 22:27:44 +03:00
GET https://example.org/order/435
2021-02-12 10:52:29 +03:00
HTTP/1.1 200
```
[Doc](https://hurl.dev/docs/asserting-response.html#version-status)
```hurl
2021-11-20 22:27:44 +03:00
GET https://example.org/order/435
2021-02-12 10:52:29 +03:00
# Testing status code is in a 200-300 range
HTTP/1.1 *
[Asserts]
status >= 200
status < 300
2021-02-12 10:52:29 +03:00
```
[Doc](https://hurl.dev/docs/asserting-response.html#status-assert)
### Testing HTML Response
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org
HTTP/1.1 200
Content-Type: text/html; charset=UTF-8
[Asserts]
xpath "string(/html/head/title)" contains "Example" # Check title
2021-10-22 16:04:50 +03:00
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
2022-02-11 16:29:06 +03:00
xpath "string(//div[1])" matches /Hello.*/
```
[Doc](https://hurl.dev/docs/asserting-response.html#xpath-assert)
2021-02-12 10:52:29 +03:00
### Testing Set-Cookie Attributes
```hurl
GET http://myserver.com/home
HTTP/1.0 200
[Asserts]
cookie "JSESSIONID" == "8400BAFE2F66443613DC38AE3D9D6239"
cookie "JSESSIONID[Value]" == "8400BAFE2F66443613DC38AE3D9D6239"
2021-02-12 10:52:29 +03:00
cookie "JSESSIONID[Expires]" contains "Wed, 13 Jan 2021"
cookie "JSESSIONID[Secure]" exists
cookie "JSESSIONID[HttpOnly]" exists
cookie "JSESSIONID[SameSite]" == "Lax"
2021-02-12 10:52:29 +03:00
```
[Doc](https://hurl.dev/docs/asserting-response.html#cookie-assert)
2022-05-12 17:25:29 +03:00
### Testing Bytes Content
Check the SHA-256 response body hash:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/data.tar.gz
2022-05-12 17:25:29 +03:00
HTTP/* *
[Asserts]
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
```
[Doc](https://hurl.dev/docs/asserting-response.html#sha-256-assert)
## Others
2022-10-24 21:58:56 +03:00
### 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: true
HTTP/* 200
[Asserts]
jsonpath "$.state" == "COMPLETED"
```
[Doc](https://hurl.dev/docs/entry.html#retry)
2021-02-12 10:52:29 +03:00
### Testing Endpoint Performance
```hurl
GET https://sample.org/helloworld
HTTP/* *
[Asserts]
duration < 1000 # Check that response time is less than one second
2021-02-12 10:52:29 +03:00
```
[Doc](https://hurl.dev/docs/asserting-response.html#duration-assert)
2022-09-28 11:34:00 +03:00
### Using SOAP APIs
```hurl
2022-05-31 15:38:37 +03:00
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"?>
2022-05-31 15:38:37 +03:00
<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/1.1 200
```
[Doc](https://hurl.dev/docs/request.html#xml-body)
### Capturing and Using a CSRF Token
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org
HTTP/* 200
[Captures]
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
2022-05-31 15:38:37 +03:00
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)
2021-10-22 16:04:50 +03:00
### Checking Byte Order Mark (BOM) in Response Body
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/data.bin
2021-10-22 16:04:50 +03:00
HTTP/* 200
[Asserts]
bytes startsWith hex,efbbbf;
```
[Doc](https://hurl.dev/docs/asserting-response.html#bytes-assert)
# Manual
2021-10-22 16:04:50 +03:00
## Name
hurl - run and test HTTP requests.
## Synopsis
**hurl** [options] [FILE...]
## Description
**Hurl** is an HTTP client that performs HTTP requests defined in a simple plain text format.
Hurl is very versatile. It enables chaining HTTP requests, capturing values from HTTP responses, and making assertions.
2022-09-03 01:32:04 +03:00
```shell
2021-10-22 16:04:50 +03:00
$ hurl session.hurl
```
2022-08-16 13:08:14 +03:00
If no input files are specified, input is read from stdin.
2021-10-22 16:04:50 +03:00
2022-09-03 01:32:04 +03:00
```shell
2021-10-22 16:04:50 +03:00
$ 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"
}
```
Output goes to stdout by default. To have output go to a file, use the [`-o, --output`](#output) option:
2021-10-22 16:04:50 +03:00
2022-09-03 01:32:04 +03:00
```shell
2021-10-22 16:04:50 +03:00
$ hurl -o output input.hurl
```
By default, Hurl executes all HTTP requests and outputs the response body of the last HTTP call.
2022-08-16 13:08:14 +03:00
To have a test oriented output, you can use [`--test`](#test) option:
2022-06-23 16:22:16 +03:00
2022-09-03 01:32:04 +03:00
```shell
2022-06-23 16:22:16 +03:00
$ hurl --test *.hurl
```
2021-10-22 16:04:50 +03:00
## Hurl File Format
2022-08-16 13:08:14 +03:00
The Hurl file format is fully documented in [https://hurl.dev/docs/hurl-file.html](https://hurl.dev/docs/hurl-file.html)
2021-10-22 16:04:50 +03:00
It consists of one or several HTTP requests
```hurl
2022-06-13 09:06:13 +03:00
GET http:/example.org/endpoint1
GET http:/example.org/endpoint2
2021-10-22 16:04:50 +03:00
```
### Capturing values
A value from an HTTP response can be-reused for successive HTTP requests.
A typical example occurs with csrf tokens.
```hurl
2022-06-13 09:06:13 +03:00
GET https://example.org
2021-10-22 16:04:50 +03:00
HTTP/1.1 200
# Capture the CSRF token value from html body.
[Captures]
csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"
# Do the login !
2022-06-13 09:06:13 +03:00
POST https://example.org/login?user=toto&password=1234
2021-10-22 16:04:50 +03:00
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)
2022-06-23 16:22:16 +03:00
2021-10-22 16:04:50 +03:00
### Asserts
The HTTP response defined in the Hurl session are used to make asserts.
At the minimum, the response includes the asserts on the HTTP version and status code.
```hurl
GET http:/google.com
2022-02-15 20:28:49 +03:00
HTTP/1.1 301
2021-10-22 16:04:50 +03:00
```
It can also include asserts on the response headers
```hurl
GET http:/google.com
2022-02-15 20:28:49 +03:00
HTTP/1.1 301
2021-10-22 16:04:50 +03:00
Location: http://www.google.com
```
Explicit asserts can be included by combining a query and a predicate
2021-10-22 16:04:50 +03:00
```hurl
GET http:/google.com
2022-02-15 20:28:49 +03:00
HTTP/1.1 301
2021-10-22 16:04:50 +03:00
[Asserts]
2022-02-15 20:28:49 +03:00
xpath "string(//title)" == "301 Moved"
2021-10-22 16:04:50 +03:00
```
With the addition of asserts, Hurl can be used as a testing tool to run scenarios.
2021-10-22 16:04:50 +03:00
More information on asserts can be found here [https://hurl.dev/docs/asserting-response.html](https://hurl.dev/docs/asserting-response.html)
2021-02-13 22:01:47 +03:00
## Options
2022-09-28 11:24:24 +03:00
Options that exist in curl have exactly the same semantics.
2022-08-16 13:08:14 +03:00
Options specified on the command line are defined for every Hurl file's entry.
For instance:
2022-09-03 01:32:04 +03:00
```shell
2022-08-16 13:08:14 +03:00
$ 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:
2022-08-16 13:08:14 +03:00
```hurl
GET https://google.com
HTTP/* 301
GET https://google.com
[Options]
location: true
HTTP/* 200
```
will follow a redirection only for the second entry.
2021-02-13 22:01:47 +03:00
Option | Description
--- | ---
2022-10-24 21:58:56 +03:00
<a href="#cacert" id="cacert"><code>--cacert</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="#color" id="color"><code>--color</code></a> | Colorize Output.<br/>
2021-10-22 16:04:50 +03:00
<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/>
2022-10-24 21:58:56 +03:00
<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/>See also [`-m, --max-time`](#max-time) option.<br/>
<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/>
<a href="#cookie-jar" id="cookie-jar"><code>-c, --cookie-jar &lt;FILE&gt;</code></a> | Write cookies to FILE after running the session (only for one 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/>
2021-10-22 16:04:50 +03:00
<a href="#fail-at-end" id="fail-at-end"><code>--fail-at-end</code></a> | Continue executing requests to the end of the Hurl file even when an assert error occurs.<br/>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/>
2022-10-24 21:58:56 +03:00
<a href="#file-root" id="file-root"><code>--file-root &lt;DIR&gt;</code></a> | Set root file system to import files in Hurl. This is used for both files in multipart form data and request body.<br/>When this is not explicitly defined, the files are relative to the current directory in which Hurl is running.<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/>
2022-10-24 21:58:56 +03:00
<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/>
2021-10-22 16:04:50 +03:00
<a href="#include" id="include"><code>-i, --include</code></a> | Include the HTTP headers in the output (last entry).<br/>
2022-02-15 20:28:49 +03:00
<a href="#ignore-asserts" id="ignore-asserts"><code>--ignore-asserts</code></a> | Ignore all asserts defined in the Hurl file.<br/>
<a href="#insecure" id="insecure"><code>-k, --insecure</code></a> | This option explicitly allows Hurl to perform "insecure" SSL connections and transfers.<br/>
2021-10-22 16:04:50 +03:00
<a href="#interactive" id="interactive"><code>--interactive</code></a> | Stop between requests.<br/>This is similar to a break point, You can then continue (Press C) or quit (Press Q).<br/>
2021-12-08 20:25:15 +03:00
<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/>
2022-10-24 21:58:56 +03:00
<a href="#max-redirs" id="max-redirs"><code>--max-redirs &lt;NUM&gt;</code></a> | Set maximum number of redirection-followings allowed<br/>By default, the limit is set to 50 redirections. Set this option to -1 to make it unlimited.<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/>See also [`--connect-timeout`](#connect-timeout) option.<br/>
<a href="#no-color" id="no-color"><code>--no-color</code></a> | Do not colorize output.<br/>
2021-12-08 20:25:15 +03:00
<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/>
2022-10-24 21:58:56 +03:00
<a href="#noproxy" id="noproxy"><code>--noproxy &lt;HOST(S)&gt;</code></a> | Comma-separated list of hosts which do not use a proxy.<br/>Override value from Environment variable no_proxy.<br/>
<a href="#output" id="output"><code>-o, --output &lt;FILE&gt;</code></a> | Write output to FILE instead of stdout.<br/>
2022-02-15 20:28:49 +03:00
<a href="#proxy" id="proxy"><code>-x, --proxy [protocol://]host[:port]</code></a> | Use the specified proxy.<br/>
2022-10-24 21:58:56 +03:00
<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/>
<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/>
<a href="#retry" id="retry"><code>--retry</code></a> | Retry requests if any error occurs (asserts, captures, runtimes etc...).<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/>
<a href="#retry-max-count" id="retry-max-count"><code>--retry-max-count &lt;NUM&gt;</code></a> | Maximum number of retries. Set this option to -1 to make it unlimited. Default is 10.<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/>
2022-10-24 21:58:56 +03:00
<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/>
<a href="#user" id="user"><code>-u, --user &lt;USER:PASSWORD&gt;</code></a> | Add basic Authentication header to each request.<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/>
<a href="#variable" id="variable"><code>--variable &lt;NAME=VALUE&gt;</code></a> | Define variable (name/value) to be used in Hurl templates.<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/>
<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/>
<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/>
2022-02-15 20:28:49 +03:00
<a href="#help" id="help"><code>-h, --help</code></a> | Usage help. This lists all current command line options with a short description.<br/>
2021-10-22 16:04:50 +03:00
<a href="#version" id="version"><code>-V, --version</code></a> | Prints version information<br/>
2021-02-13 22:01:47 +03:00
## Environment
Environment variables can only be specified in lowercase.
2022-08-16 13:08:14 +03:00
Using an environment variable to set the proxy has the same effect as using the [`-x, --proxy`](#proxy) option.
2021-02-13 22:01:47 +03:00
Variable | Description
2021-10-22 16:04:50 +03:00
--- | ---
`http_proxy [protocol://]<host>[:port]` | Sets the proxy server to use for HTTP.<br/>
`https_proxy [protocol://]<host>[:port]` | Sets the proxy server to use for HTTPS.<br/>
`all_proxy [protocol://]<host>[:port]` | Sets the proxy server to use if no protocol-specific proxy is set.<br/>
2022-08-16 13:08:14 +03:00
`no_proxy <comma-separated list of hosts>` | List of host names that shouldn't go through any proxy.<br/>
`HURL_name value` | Define variable (name/value) to be used in Hurl templates. This is similar than [`--variable`](#variable) and [`--variables-file`](#variables-file) options.<br/>
`NO_COLOR` | When set to a non-empty string, do not colorize output (see [`--no-color`](#no-color) option).<br/>
2021-02-13 22:01:47 +03:00
2021-10-22 16:04:50 +03:00
## Exit Codes
2021-02-13 22:01:47 +03:00
Value | Description
2021-10-22 16:04:50 +03:00
--- | ---
`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)
2021-02-13 22:01:47 +03:00
2020-11-29 18:55:26 +03:00
2021-10-22 16:04:50 +03:00
## See Also
curl(1) hurlfmt(1)
# Installation
## Binaries Installation
### Linux
2022-11-07 16:11:48 +03:00
Precompiled binary is available at [hurl-1.9.0-SNAPSHOT-x86_64-linux.tar.gz]:
2021-10-22 16:04:50 +03:00
```shell
2021-11-20 22:27:44 +03:00
$ INSTALL_DIR=/tmp
2022-11-07 16:11:48 +03:00
$ curl -sL https://github.com/Orange-OpenSource/hurl/releases/download/1.9.0-SNAPSHOT/hurl-1.9.0-SNAPSHOT-x86_64-linux.tar.gz | tar xvz -C $INSTALL_DIR
$ export PATH=$INSTALL_DIR/hurl-1.9.0-SNAPSHOT:$PATH
2021-10-22 16:04:50 +03:00
```
#### Debian / Ubuntu
For Debian / Ubuntu, Hurl can be installed using a binary .deb file provided in each Hurl release.
```shell
2022-11-07 16:11:48 +03:00
$ curl -LO https://github.com/Orange-OpenSource/hurl/releases/download/1.9.0-SNAPSHOT/hurl_1.9.0-SNAPSHOT_amd64.deb
$ sudo dpkg -i hurl_1.9.0-SNAPSHOT_amd64.deb
2021-10-22 16:04:50 +03:00
```
#### Arch Linux / Manjaro
2022-04-13 23:09:33 +03:00
[`hurl-bin` package] for Arch Linux and derived distros is available via [AUR].
#### NixOS / Nix
[NixOS / Nix package] is available on stable channel.
2021-10-22 16:04:50 +03:00
### macOS
2022-11-07 16:11:48 +03:00
Precompiled binary is available at [hurl-1.9.0-SNAPSHOT-x86_64-macos.tar.gz] for x86 CPUs and [hurl-1.9.0-SNAPSHOT-arm64-macos.tar.gz] for ARM CPUS.
2021-10-22 16:04:50 +03:00
2022-10-10 18:42:28 +03:00
#### Homebrew
2021-10-22 16:04:50 +03:00
```shell
2021-11-20 22:27:44 +03:00
$ brew install hurl
2021-10-22 16:04:50 +03:00
```
2022-10-10 18:42:28 +03:00
#### MacPorts
```shell
$ sudo port install hurl
```
2021-10-22 16:04:50 +03:00
### Windows
#### Zip File
2022-11-07 16:11:48 +03:00
Hurl can be installed from a standalone zip file [hurl-1.9.0-SNAPSHOT-win64.zip]. You will need to update your `PATH` variable.
2021-10-22 16:04:50 +03:00
#### Installer
2022-11-07 16:11:48 +03:00
An installer [hurl-1.9.0-SNAPSHOT-win64-installer.exe] is also available.
2021-11-12 18:25:13 +03:00
#### Chocolatey
2021-11-20 22:27:44 +03:00
```shell
$ choco install hurl
2021-11-12 18:25:13 +03:00
```
#### Scoop
2021-11-20 22:27:44 +03:00
```shell
$ scoop install hurl
2021-11-12 18:25:13 +03:00
```
2021-10-22 16:04:50 +03:00
2021-11-12 18:25:13 +03:00
#### Windows Package Manager
2021-11-20 22:27:44 +03:00
```shell
$ winget install hurl
2021-11-12 18:25:13 +03:00
```
2021-10-22 16:04:50 +03:00
### Cargo
If you're a Rust programmer, Hurl can be installed with cargo.
2021-11-20 22:27:44 +03:00
```shell
$ cargo install hurl
2021-10-22 16:04:50 +03:00
```
2021-12-16 12:32:00 +03:00
### Docker
2022-02-10 23:51:21 +03:00
```shell
2021-12-16 12:32:00 +03:00
$ docker pull orangeopensource/hurl
```
2022-05-31 15:38:37 +03:00
### npm
```shell
$ npm install --save-dev @orangeopensource/hurl
```
2021-10-22 16:04:50 +03:00
## Building From Sources
Hurl sources are available in [GitHub].
2022-08-29 00:26:11 +03:00
### Build on Linux
2020-11-29 18:55:26 +03:00
2021-02-04 16:04:17 +03:00
Hurl depends on libssl, libcurl and libxml2 native libraries. You will need their development files in your platform.
2020-11-29 18:55:26 +03:00
2022-04-01 15:27:56 +03:00
#### Debian based distributions
2021-02-04 16:04:17 +03:00
```shell
$ apt install -y build-essential pkg-config libssl-dev libcurl4-openssl-dev libxml2-dev
2022-04-01 15:27:56 +03:00
```
2021-02-04 16:04:17 +03:00
2022-04-01 15:27:56 +03:00
#### Red Hat based distributions
```shell
$ yum install -y pkg-config gcc openssl-devel libxml2-devel
```
2021-02-04 16:04:17 +03:00
2022-05-31 15:38:37 +03:00
#### Arch based distributions
2022-03-20 02:31:57 +03:00
2022-04-01 15:27:56 +03:00
```shell
2022-08-17 20:00:07 +03:00
$ pacman -Sy --noconfirm pkgconf gcc glibc openssl libxml2
2022-04-01 15:27:56 +03:00
```
2022-08-29 00:26:11 +03:00
### Build on macOS
2022-04-01 15:27:56 +03:00
```shell
$ xcode-select --install
$ brew install pkg-config
2020-11-29 18:55:26 +03:00
```
2021-02-04 16:04:17 +03:00
2021-10-22 16:04:50 +03:00
Hurl is written in [Rust]. You should [install] the latest stable release.
2021-02-04 16:04:17 +03:00
```shell
2021-11-20 22:27:44 +03:00
$ curl https://sh.rustup.rs -sSf | sh -s -- -y
$ source $HOME/.cargo/env
$ rustc --version
$ cargo --version
2020-11-29 18:55:26 +03:00
```
2022-04-01 15:27:56 +03:00
Then build hurl:
2021-02-04 16:04:17 +03:00
```shell
2021-11-20 22:27:44 +03:00
$ git clone https://github.com/Orange-OpenSource/hurl
$ cd hurl
$ cargo build --release
$ ./target/release/hurl --version
2020-11-29 18:55:26 +03:00
```
2021-01-05 11:06:14 +03:00
2021-10-22 16:04:50 +03:00
### 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
2021-12-08 20:19:44 +03:00
[Feedback, suggestion, bugs or improvements]: https://github.com/Orange-OpenSource/hurl/issues
2021-10-22 16:04:50 +03:00
[License]: https://hurl.dev/docs/license.html
2022-06-13 09:06:13 +03:00
[Tutorial]: https://hurl.dev/docs/tutorial/your-first-hurl-file.html
2021-12-11 18:34:16 +03:00
[Documentation]: https://hurl.dev/docs/installation.html
2022-02-10 23:51:21 +03:00
[Blog]: https://hurl.dev/blog/
2021-10-22 16:04:50 +03:00
[GitHub]: https://github.com/Orange-OpenSource/hurl
[libcurl]: https://curl.se/libcurl/
[JSON body]: https://hurl.dev/docs/request.html#json-body
[XML body]: https://hurl.dev/docs/request.html#xml-body
[multiline string body]: https://hurl.dev/docs/request.html#multiline-string-body
2021-10-22 16:04:50 +03:00
[predicates]: https://hurl.dev/docs/asserting-response.html#predicates
[JSONPath]: https://goessner.net/articles/JsonPath/
2021-11-20 22:27:44 +03:00
[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
2022-05-31 15:38:37 +03:00
[Hurl tests suite]: https://github.com/Orange-OpenSource/hurl/tree/master/integration/tests_ok
2022-02-11 16:29:06 +03:00
[Authorization]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
2022-09-02 15:45:54 +03:00
[`-u/--user` option]: https://hurl.dev/docs/manual.html#user
2022-06-13 09:06:13 +03:00
[curl]: https://curl.se
[entry]: https://hurl.dev/docs/entry.html
2022-09-02 15:45:54 +03:00
[`--test` option]: https://hurl.dev/docs/manual.html#test
2021-10-22 16:04:50 +03:00
[GitHub]: https://github.com/Orange-OpenSource/hurl
2022-11-07 16:11:48 +03:00
[hurl-1.9.0-SNAPSHOT-win64.zip]: https://github.com/Orange-OpenSource/hurl/releases/download/1.9.0-SNAPSHOT/hurl-1.9.0-SNAPSHOT-win64.zip
[hurl-1.9.0-SNAPSHOT-win64-installer.exe]: https://github.com/Orange-OpenSource/hurl/releases/download/1.9.0-SNAPSHOT/hurl-1.9.0-SNAPSHOT-win64-installer.exe
[hurl-1.9.0-SNAPSHOT-x86_64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.9.0-SNAPSHOT/hurl-1.9.0-SNAPSHOT-x86_64-macos.tar.gz
[hurl-1.9.0-SNAPSHOT-arm64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.9.0-SNAPSHOT/hurl-1.9.0-SNAPSHOT-arm64-macos.tar.gz
[hurl-1.9.0-SNAPSHOT-x86_64-linux.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.9.0-SNAPSHOT/hurl-1.9.0-SNAPSHOT-x86_64-linux.tar.gz
2021-10-22 16:04:50 +03:00
[AUR]: https://wiki.archlinux.org/index.php/Arch_User_Repository
[`hurl-bin` package]: https://aur.archlinux.org/packages/hurl-bin/
[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
2022-09-25 13:52:24 +03:00
[NixOS / Nix package]: https://search.nixos.org/packages?from=0&size=1&sort=relevance&type=packages&query=hurl
2021-02-04 16:04:17 +03:00