mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-26 00:22:10 +03:00
Update docs for Hurl 2.0.0.
This commit is contained in:
parent
a9e7b85262
commit
42ef4125fe
325
README.md
325
README.md
@ -12,21 +12,24 @@
|
||||
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 <b>fetching data</b>, <b>testing HTTP</b> sessions and testing <b>XML / JSON APIs</b>.
|
||||
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
|
||||
# Get home:
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
|
||||
|
||||
|
||||
# Do login!
|
||||
POST https://example.org/login?user=toto&password=1234
|
||||
X-CSRF-TOKEN: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
```
|
||||
|
||||
Chaining multiple requests is easy:
|
||||
@ -55,7 +58,7 @@ POST https://example.org/api/tests
|
||||
"evaluate": true
|
||||
}
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "X-Frame-Options" == "SAMEORIGIN"
|
||||
jsonpath "$.status" == "RUNNING" # Check the status code
|
||||
@ -68,12 +71,27 @@ jsonpath "$.id" matches /\d{4}/ # Check the format of the id
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "normalize-space(//head/title)" == "Hello world!"
|
||||
```
|
||||
|
||||
and even SOAP APIs
|
||||
<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
|
||||
@ -88,8 +106,7 @@ SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
|
||||
</m:GetStockPrice>
|
||||
</soap:Body>
|
||||
</soap:Envelope>
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
Hurl can also be used to performance test HTTP endpoints:
|
||||
@ -97,7 +114,7 @@ Hurl can also be used to performance test HTTP endpoints:
|
||||
```hurl
|
||||
GET https://example.org/api/v1/pets
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
duration < 1000 # Duration in ms
|
||||
```
|
||||
@ -107,7 +124,7 @@ And response bytes
|
||||
```hurl
|
||||
GET https://example.org/data.tar.gz
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
|
||||
```
|
||||
@ -138,7 +155,7 @@ POST https://hurl.dev/api/feedback
|
||||
"name": "John Doe",
|
||||
"feedback": "Hurl is awesome !"
|
||||
}
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
# Resources
|
||||
@ -164,7 +181,9 @@ Table of Contents
|
||||
* [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 / XML Body](#templating-a-json--xml-body)
|
||||
* [Templating a JSON Body](#templating-a-json-body)
|
||||
* [Templating a XML Body](#templating-a-xml-body)
|
||||
* [Using GraphQL Query](#using-graphql-query)
|
||||
* [Testing Response](#testing-response)
|
||||
* [Testing Response Headers](#testing-response-headers)
|
||||
* [Testing REST APIs](#testing-rest-apis)
|
||||
@ -172,6 +191,7 @@ Table of Contents
|
||||
* [Testing Set-Cookie Attributes](#testing-set-cookie-attributes)
|
||||
* [Testing Bytes Content](#testing-bytes-content)
|
||||
* [Others](#others)
|
||||
* [HTTP Version](#http-version)
|
||||
* [Polling and Retry](#polling-and-retry)
|
||||
* [Testing Endpoint Performance](#testing-endpoint-performance)
|
||||
* [Using SOAP APIs](#using-soap-apis)
|
||||
@ -354,15 +374,11 @@ file,data.json;
|
||||
|
||||
[Doc](https://hurl.dev/docs/request.html#file-body)
|
||||
|
||||
### Templating a JSON / XML Body
|
||||
### Templating a JSON Body
|
||||
|
||||
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:
|
||||
|
||||
~~~hurl
|
||||
```hurl
|
||||
PUT https://example.org/api/hits
|
||||
Content-Type: application/json
|
||||
```
|
||||
{
|
||||
"key0": "{{a_string}}",
|
||||
"key1": {{a_bool}},
|
||||
@ -370,7 +386,6 @@ Content-Type: application/json
|
||||
"key3": {{a_number}}
|
||||
}
|
||||
```
|
||||
~~~
|
||||
|
||||
Variables can be initialized via command line:
|
||||
|
||||
@ -393,8 +408,67 @@ Resulting in a PUT request with the following JSON body:
|
||||
}
|
||||
```
|
||||
|
||||
[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-body)
|
||||
|
||||
## Testing Response
|
||||
|
||||
### Testing Response Headers
|
||||
@ -404,7 +478,7 @@ Use implicit response asserts to test header values:
|
||||
```hurl
|
||||
GET https://example.org/index.html
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
Set-Cookie: theme=light
|
||||
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
|
||||
```
|
||||
@ -417,7 +491,7 @@ Or use explicit response asserts with [predicates]:
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
[Asserts]
|
||||
header "Location" contains "www.example.net"
|
||||
```
|
||||
@ -433,7 +507,7 @@ Asserting JSON body response (node values, collection count etc...) with [JSONPa
|
||||
GET https://example.org/order
|
||||
screencapability: low
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.validated" == true
|
||||
jsonpath "$.userInfo.firstName" == "Franck"
|
||||
@ -453,7 +527,7 @@ Testing status code:
|
||||
```hurl
|
||||
GET https://example.org/order/435
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
[Doc](https://hurl.dev/docs/asserting-response.html#version-status)
|
||||
@ -462,7 +536,7 @@ HTTP/1.1 200
|
||||
GET https://example.org/order/435
|
||||
|
||||
# Testing status code is in a 200-300 range
|
||||
HTTP/1.1 *
|
||||
HTTP *
|
||||
[Asserts]
|
||||
status >= 200
|
||||
status < 300
|
||||
@ -476,7 +550,7 @@ status < 300
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
[Asserts]
|
||||
@ -495,7 +569,7 @@ xpath "string(//div[1])" matches /Hello.*/
|
||||
```hurl
|
||||
GET http://myserver.com/home
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
cookie "JSESSIONID" == "8400BAFE2F66443613DC38AE3D9D6239"
|
||||
cookie "JSESSIONID[Value]" == "8400BAFE2F66443613DC38AE3D9D6239"
|
||||
@ -525,6 +599,17 @@ sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
|
||||
|
||||
## Others
|
||||
|
||||
### HTTP Version
|
||||
|
||||
Testing HTTP version (1.0, 1.1 or 2):
|
||||
|
||||
```hurl
|
||||
GET https://example.org/order/435
|
||||
HTTP/2 200
|
||||
```
|
||||
|
||||
[Doc](https://hurl.dev/docs/asserting-response.html#version-status)
|
||||
|
||||
### Polling and Retry
|
||||
|
||||
Retry request on any errors (asserts, captures, status code, runtime etc...):
|
||||
@ -533,7 +618,7 @@ Retry request on any errors (asserts, captures, status code, runtime etc...):
|
||||
# Create a new job
|
||||
POST https://api.example.org/jobs
|
||||
|
||||
HTTP/* 201
|
||||
HTTP 201
|
||||
[Captures]
|
||||
job_id: jsonpath "$.id"
|
||||
[Asserts]
|
||||
@ -545,7 +630,7 @@ GET https://api.example.org/jobs/{{job_id}}
|
||||
[Options]
|
||||
retry: true
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.state" == "COMPLETED"
|
||||
```
|
||||
@ -559,7 +644,7 @@ jsonpath "$.state" == "COMPLETED"
|
||||
```hurl
|
||||
GET https://sample.org/helloworld
|
||||
|
||||
HTTP/* *
|
||||
HTTP *
|
||||
[Asserts]
|
||||
duration < 1000 # Check that response time is less than one second
|
||||
```
|
||||
@ -582,7 +667,7 @@ SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
|
||||
</soap:Body>
|
||||
</soap:Envelope>
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
[Doc](https://hurl.dev/docs/request.html#xml-body)
|
||||
@ -592,14 +677,14 @@ HTTP/1.1 200
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/* 200
|
||||
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
|
||||
HTTP 302
|
||||
```
|
||||
|
||||
[Doc](https://hurl.dev/docs/capturing-response.html#xpath-capture)
|
||||
@ -609,7 +694,7 @@ HTTP/* 302
|
||||
```hurl
|
||||
GET https://example.org/data.bin
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
bytes startsWith hex,efbbbf;
|
||||
```
|
||||
@ -631,9 +716,9 @@ hurl - run and test HTTP requests.
|
||||
|
||||
## Description
|
||||
|
||||
**Hurl** is an HTTP client that performs HTTP requests defined in a simple plain text format.
|
||||
**Hurl** is a command line tool that runs 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.
|
||||
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
|
||||
@ -690,11 +775,11 @@ GET http:/example.org/endpoint2
|
||||
|
||||
A value from an HTTP response can be-reused for successive HTTP requests.
|
||||
|
||||
A typical example occurs with csrf tokens.
|
||||
A typical example occurs with CSRF tokens.
|
||||
|
||||
```hurl
|
||||
GET https://example.org
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
# Capture the CSRF token value from html body.
|
||||
[Captures]
|
||||
csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"
|
||||
@ -708,28 +793,28 @@ More information on captures can be found here [https://hurl.dev/docs/capturing-
|
||||
|
||||
### Asserts
|
||||
|
||||
The HTTP response defined in the Hurl session are used to make asserts.
|
||||
The HTTP response defined in the Hurl file are used to make asserts. Responses are optional.
|
||||
|
||||
At the minimum, the response includes the asserts on the HTTP version and status code.
|
||||
At the minimum, response includes assert on the HTTP status code.
|
||||
|
||||
```hurl
|
||||
GET http:/google.com
|
||||
HTTP/1.1 301
|
||||
GET http:/example.org
|
||||
HTTP 301
|
||||
```
|
||||
|
||||
It can also include asserts on the response headers
|
||||
|
||||
```hurl
|
||||
GET http:/google.com
|
||||
HTTP/1.1 301
|
||||
Location: http://www.google.com
|
||||
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:/google.com
|
||||
HTTP/1.1 301
|
||||
GET http:/example.org
|
||||
HTTP 301
|
||||
[Asserts]
|
||||
xpath "string(//title)" == "301 Moved"
|
||||
```
|
||||
@ -753,56 +838,61 @@ $ 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://google.com
|
||||
HTTP/* 301
|
||||
GET https://example.org
|
||||
HTTP 301
|
||||
|
||||
GET https://google.com
|
||||
GET https://example.org
|
||||
[Options]
|
||||
location: true
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
will follow a redirection only for the second entry.
|
||||
|
||||
Option | Description
|
||||
--- | ---
|
||||
<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/>
|
||||
<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/>
|
||||
<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/>See also [`-m, --max-time`](#max-time) option.<br/>
|
||||
<a href="#cookie" id="cookie"><code>-b, --cookie <FILE></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 <FILE></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/>
|
||||
<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/>
|
||||
<a href="#file-root" id="file-root"><code>--file-root <DIR></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/>
|
||||
<a href="#glob" id="glob"><code>--glob <GLOB></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/>
|
||||
<a href="#include" id="include"><code>-i, --include</code></a> | Include the HTTP headers in the output (last entry).<br/>
|
||||
<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/>
|
||||
<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/>
|
||||
<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/>
|
||||
<a href="#max-redirs" id="max-redirs"><code>--max-redirs <NUM></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 <SECONDS></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/>
|
||||
<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/>
|
||||
<a href="#noproxy" id="noproxy"><code>--noproxy <HOST(S)></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 <FILE></code></a> | Write output to FILE instead of stdout.<br/>
|
||||
<a href="#proxy" id="proxy"><code>-x, --proxy [protocol://]host[:port]</code></a> | Use the specified proxy.<br/>
|
||||
<a href="#report-junit" id="report-junit"><code>--report-junit <FILE></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 <DIR></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 <MILLISECONDS></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 <NUM></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/>
|
||||
<a href="#to-entry" id="to-entry"><code>--to-entry <ENTRY_NUMBER></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 <USER:PASSWORD></code></a> | Add basic Authentication header to each request.<br/>
|
||||
<a href="#user-agent" id="user-agent"><code>-A, --user-agent <NAME></code></a> | Specify the User-Agent string to send to the HTTP server.<br/>
|
||||
<a href="#variable" id="variable"><code>--variable <NAME=VALUE></code></a> | Define variable (name/value) to be used in Hurl templates.<br/>
|
||||
<a href="#variables-file" id="variables-file"><code>--variables-file <FILE></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/>
|
||||
<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/>
|
||||
| Option | Description |
|
||||
|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| <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 [`--key`](#key).<br> |
|
||||
| <a href="#color" id="color"><code>--color</code></a> | Colorize Output.<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> |
|
||||
| <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>See also [`-m, --max-time`](#max-time).<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 [`--resolve`](#resolve).<br> |
|
||||
| <a href="#cookie" id="cookie"><code>-b, --cookie <FILE></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 <FILE></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> |
|
||||
| <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> |
|
||||
| <a href="#file-root" id="file-root"><code>--file-root <DIR></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> |
|
||||
| <a href="#glob" id="glob"><code>--glob <GLOB></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> |
|
||||
| <a href="#include" id="include"><code>-i, --include</code></a> | Include the HTTP headers in the output (last entry).<br> |
|
||||
| <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> |
|
||||
| <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> |
|
||||
| <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> |
|
||||
| <a href="#key" id="key"><code>--key <KEY></code></a> | Private key file name.<br> |
|
||||
| <a href="#max-redirs" id="max-redirs"><code>--max-redirs <NUM></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 <SECONDS></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).<br> |
|
||||
| <a href="#no-color" id="no-color"><code>--no-color</code></a> | Do not colorize output.<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> |
|
||||
| <a href="#noproxy" id="noproxy"><code>--noproxy <HOST(S)></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 <FILE></code></a> | Write output to FILE instead of stdout.<br> |
|
||||
| <a href="#proxy" id="proxy"><code>-x, --proxy <[PROTOCOL://]HOST[:PORT]></code></a> | Use the specified proxy.<br> |
|
||||
| <a href="#report-junit" id="report-junit"><code>--report-junit <FILE></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 <DIR></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="#resolve" id="resolve"><code>--resolve <HOST:PORT:ADDR></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="#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 <MILLISECONDS></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 <NUM></code></a> | Maximum number of retries. Set this option to -1 to make it unlimited. Default is 10.<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> |
|
||||
| <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> |
|
||||
| <a href="#to-entry" id="to-entry"><code>--to-entry <ENTRY_NUMBER></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 <USER:PASSWORD></code></a> | Add basic Authentication header to each request.<br> |
|
||||
| <a href="#user-agent" id="user-agent"><code>-A, --user-agent <NAME></code></a> | Specify the User-Agent string to send to the HTTP server.<br> |
|
||||
| <a href="#variable" id="variable"><code>--variable <NAME=VALUE></code></a> | Define variable (name/value) to be used in Hurl templates.<br> |
|
||||
| <a href="#variables-file" id="variables-file"><code>--variables-file <FILE></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> |
|
||||
| <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> |
|
||||
|
||||
## Environment
|
||||
|
||||
@ -810,23 +900,23 @@ Environment variables can only be specified in lowercase.
|
||||
|
||||
Using an environment variable to set the proxy has the same effect as using the [`-x, --proxy`](#proxy) option.
|
||||
|
||||
Variable | Description
|
||||
--- | ---
|
||||
`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/>
|
||||
`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/>
|
||||
| Variable | Description |
|
||||
|--------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `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> |
|
||||
| `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> |
|
||||
|
||||
## Exit Codes
|
||||
|
||||
Value | Description
|
||||
--- | ---
|
||||
`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/>
|
||||
| Value | Description |
|
||||
|-------|---------------------------------------------------------|
|
||||
| `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
|
||||
|
||||
@ -843,12 +933,12 @@ curl(1) hurlfmt(1)
|
||||
|
||||
### Linux
|
||||
|
||||
Precompiled binary is available at [hurl-1.8.0-x86_64-linux.tar.gz]:
|
||||
Precompiled binary is available at [hurl-2.0.0-x86_64-linux.tar.gz]:
|
||||
|
||||
```shell
|
||||
$ INSTALL_DIR=/tmp
|
||||
$ curl -sL https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-x86_64-linux.tar.gz | tar xvz -C $INSTALL_DIR
|
||||
$ export PATH=$INSTALL_DIR/hurl-1.8.0:$PATH
|
||||
$ curl -sL https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-x86_64-linux.tar.gz | tar xvz -C $INSTALL_DIR
|
||||
$ export PATH=$INSTALL_DIR/hurl-2.0.0:$PATH
|
||||
```
|
||||
|
||||
#### Debian / Ubuntu
|
||||
@ -856,8 +946,8 @@ $ export PATH=$INSTALL_DIR/hurl-1.8.0:$PATH
|
||||
For Debian / Ubuntu, Hurl can be installed using a binary .deb file provided in each Hurl release.
|
||||
|
||||
```shell
|
||||
$ curl -LO https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl_1.8.0_amd64.deb
|
||||
$ sudo apt update && apt install ./hurl_1.8.0_amd64.deb
|
||||
$ curl -LO https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl_2.0.0_amd64.deb
|
||||
$ sudo apt update && apt install ./hurl_2.0.0_amd64.deb
|
||||
```
|
||||
|
||||
#### Arch Linux / Manjaro
|
||||
@ -870,7 +960,7 @@ $ sudo apt update && apt install ./hurl_1.8.0_amd64.deb
|
||||
|
||||
### macOS
|
||||
|
||||
Precompiled binary is available at [hurl-1.8.0-x86_64-macos.tar.gz] for x86 CPUs and [hurl-1.8.0-arm64-macos.tar.gz] for ARM CPUS.
|
||||
Precompiled binary is available at [hurl-2.0.0-x86_64-macos.tar.gz] for x86 CPUs and [hurl-2.0.0-arm64-macos.tar.gz] for ARM CPUS.
|
||||
|
||||
#### Homebrew
|
||||
|
||||
@ -894,11 +984,11 @@ $ sudo pkg install hurl
|
||||
|
||||
#### Zip File
|
||||
|
||||
Hurl can be installed from a standalone zip file [hurl-1.8.0-win64.zip]. You will need to update your `PATH` variable.
|
||||
Hurl can be installed from a standalone zip file [hurl-2.0.0-win64.zip]. You will need to update your `PATH` variable.
|
||||
|
||||
#### Installer
|
||||
|
||||
An installer [hurl-1.8.0-win64-installer.exe] is also available.
|
||||
An installer [hurl-2.0.0-win64-installer.exe] is also available.
|
||||
|
||||
#### Chocolatey
|
||||
|
||||
@ -1011,7 +1101,7 @@ Please follow the [contrib on Windows section].
|
||||
[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
|
||||
[XML 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
|
||||
@ -1022,12 +1112,13 @@ Please follow the [contrib on Windows section].
|
||||
[curl]: https://curl.se
|
||||
[entry]: https://hurl.dev/docs/entry.html
|
||||
[`--test` option]: https://hurl.dev/docs/manual.html#test
|
||||
[Hurl templates]: https://hurl.dev/docs/templates.html
|
||||
[GitHub]: https://github.com/Orange-OpenSource/hurl
|
||||
[hurl-1.8.0-win64.zip]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-win64.zip
|
||||
[hurl-1.8.0-win64-installer.exe]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-win64-installer.exe
|
||||
[hurl-1.8.0-x86_64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-x86_64-macos.tar.gz
|
||||
[hurl-1.8.0-arm64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-arm64-macos.tar.gz
|
||||
[hurl-1.8.0-x86_64-linux.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-x86_64-linux.tar.gz
|
||||
[hurl-2.0.0-win64.zip]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-win64.zip
|
||||
[hurl-2.0.0-win64-installer.exe]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-win64-installer.exe
|
||||
[hurl-2.0.0-x86_64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-x86_64-macos.tar.gz
|
||||
[hurl-2.0.0-arm64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-arm64-macos.tar.gz
|
||||
[hurl-2.0.0-x86_64-linux.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-x86_64-linux.tar.gz
|
||||
[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
|
||||
|
@ -45,7 +45,7 @@ def process_table(doc: MarkdownDoc, nodes: List[Node], col_name: str) -> None:
|
||||
|
||||
new_nodes = [
|
||||
Whitespace(content="\n"),
|
||||
Paragraph(content=f"{col_name} | Description\n --- | --- \n"),
|
||||
Paragraph(content=f"| {col_name} | Description |\n| --- | --- |\n"),
|
||||
]
|
||||
|
||||
h3s = [n for n in nodes if isinstance(n, Header)]
|
||||
@ -78,9 +78,9 @@ def process_table(doc: MarkdownDoc, nodes: List[Node], col_name: str) -> None:
|
||||
paragraphs = doc.slice(first_p, next_node)
|
||||
paragraphs_contents = [p.content for p in paragraphs if p.content]
|
||||
description = "".join(paragraphs_contents)
|
||||
description = description.replace("\n", "<br/>")
|
||||
description = description.replace("\n", "<br>")
|
||||
|
||||
new_node = Paragraph(content=f"{name} | {description}\n")
|
||||
new_node = Paragraph(content=f"| {name} | {description} |\n")
|
||||
new_nodes.append(new_node)
|
||||
|
||||
# Delete all previous options:
|
||||
|
@ -4,15 +4,15 @@ Hurl is a command line tool written in Rust that runs <b>HTTP requests</b> defin
|
||||
|
||||
The `@orangeopensource/hurl` package allows JavaScript developers to use Hurl in npm scripts.
|
||||
|
||||
Hurl can perform 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.
|
||||
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/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
|
||||
|
||||
@ -20,23 +20,23 @@ csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
|
||||
POST https://example.net/login?user=toto&password=1234
|
||||
X-CSRF-TOKEN: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 302
|
||||
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>
|
||||
It is well adapted for <b>REST / JSON APIs</b>
|
||||
|
||||
```hurl
|
||||
POST https://api.example.net/tests
|
||||
POST https://example.org/api/tests
|
||||
{
|
||||
"id": "4568",
|
||||
"evaluate": true
|
||||
}
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "X-Frame-Options" == "SAMEORIGIN"
|
||||
jsonpath "$.status" == "RUNNING" # Check the status code
|
||||
@ -44,16 +44,49 @@ jsonpath "$.tests" count == 25 # Check the number of items
|
||||
jsonpath "$.id" matches /\d{4}/ # Check the format of the id
|
||||
```
|
||||
|
||||
and <b>HTML content</b>
|
||||
<b>HTML content</b>
|
||||
|
||||
```hurl
|
||||
GET https://example.net
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
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
|
||||
|
||||
```
|
||||
|
@ -1,32 +1,60 @@
|
||||
# Asserting Response
|
||||
|
||||
## Version - Status
|
||||
## 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.
|
||||
|
||||
|
||||
```hurl
|
||||
GET https://api/example.org/cats
|
||||
|
||||
HTTP 200
|
||||
Content-Type: application/json; charset=utf-8 # Implicit assert on Content-Type Hedaer
|
||||
[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
|
||||
```
|
||||
|
||||
## 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` or
|
||||
`HTTP/*`; `HTTP/*` describes any version. Note that there are no status text following the status code.
|
||||
`HTTP`; `HTTP` describes any version. Note that there are no status text following the status code.
|
||||
|
||||
```hurl
|
||||
GET https://example.org/404.html
|
||||
|
||||
HTTP/1.1 404
|
||||
HTTP 404
|
||||
```
|
||||
|
||||
Wildcard keywords (`HTTP/*`, `*`) can be used to disable tests on protocol version and status:
|
||||
Wildcard keywords `HTTP` and `*` can be used to disable tests on protocol version and status:
|
||||
|
||||
```hurl
|
||||
GET https://example.org/api/pets
|
||||
|
||||
HTTP/1.0 *
|
||||
HTTP *
|
||||
# Check that response status code is > 400 and <= 500
|
||||
[Asserts]
|
||||
status > 400
|
||||
status <= 500
|
||||
```
|
||||
|
||||
While `HTTP/1.0`, `HTTP/1.1` and `HTTP/2` explicitly check HTTP version:
|
||||
|
||||
## Headers
|
||||
```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.
|
||||
|
||||
@ -43,7 +71,7 @@ POST https://example.org/login
|
||||
user: toto
|
||||
password: 12345678
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
Location: https://example.org/home
|
||||
```
|
||||
|
||||
@ -71,7 +99,7 @@ You can either test the two header values:
|
||||
GET https://example.org/index.html
|
||||
Host: example.net
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
Set-Cookie: theme=light
|
||||
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
|
||||
```
|
||||
@ -82,7 +110,7 @@ Or only one:
|
||||
GET https://example.org/index.html
|
||||
Host: example.net
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
Set-Cookie: theme=light
|
||||
```
|
||||
|
||||
@ -91,9 +119,9 @@ if you want to test header value with [predicates] (like `startsWith`, `contains
|
||||
you can use the explicit [header assert].
|
||||
|
||||
|
||||
## Asserts
|
||||
## Explicit asserts
|
||||
|
||||
Optional list of assertions on the HTTP response. Assertions can describe checks
|
||||
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 assert:
|
||||
@ -132,31 +160,33 @@ is shared with [captures], and can be one of :
|
||||
- [`variable`](#variable-assert)
|
||||
- [`duration`](#duration-assert)
|
||||
|
||||
Queries, as in captures, can be refined with subqueries. [`count`] subquery can be used
|
||||
with various predicates to add tests on collections sizes.
|
||||
Queries are used to extract data from the HTTP response. 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:
|
||||
Predicates consist of a predicate function and a predicate value. Predicate functions are:
|
||||
|
||||
- `==` (`equals`): check equality of query and predicate value
|
||||
- `!=`: check that query and predicate value are different
|
||||
- `>` (`greaterThan`): check that query number is greater than predicate value
|
||||
- `>=` (`greaterThanOrEquals`): check that query number is greater than or equal to the predicate value
|
||||
- `<` (`lessThan`): check that query number is less than that predicate value
|
||||
- `<=` (`lessThanOrEquals`): check that query number is less than or equal to the predicate value
|
||||
- `startsWith`: check that query starts with the predicate value (query can return a string or a binary content)
|
||||
- `endsWith`: check that query ends with the predicate value (query can return a string or a binary content)
|
||||
- `contains`: check that query contains the predicate value (query can return a string or a binary content)
|
||||
- `includes`: check that query collections includes the predicate value
|
||||
- `matches`: check that query string matches the regex pattern described by the predicate value
|
||||
- `exists`: check that query returns a value
|
||||
- `isInteger`: check that query returns an integer
|
||||
- `isFloat`: check that query returns a float
|
||||
- `isBoolean`: check that query returns a boolean
|
||||
- `isString`: check that query returns a string
|
||||
- `isCollection`: check that query returns a collection
|
||||
| Predicate | Description | Example |
|
||||
|--------------------|-------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------|
|
||||
| __`==`__ | Query and predicate value are equals | `jsonpath "$.book" == "Dune"` |
|
||||
| __`!=`__ | Query and predicate value are different | `jsonpath "$.color" != "red"` |
|
||||
| __`>`__ | Query number is greater than predicate value | `jsonpath "$.year" > 1978` |
|
||||
| __`>=`__ | Query number is greater than or equal to the predicate value | `jsonpath "$.year" >= 1978` |
|
||||
| __`<`__ | Query number is less than that predicate value | `jsonpath "$.year" < 1978` |
|
||||
| __`<=`__ | Query number 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`__ | Query contains the predicate value<br>Value is string or a binary content | `jsonpath "$.movie" contains "Empire"`<br><br>`bytes contains hex,beef;` |
|
||||
| __`includes`__ | Query collections includes the predicate value | `jsonpath "$.nooks" includes "Dune"` |
|
||||
| __`matches`__ | Part of the query string matches the regex pattern described by the predicate value | `jsonpath "$.release" matches "\\d{4}"`<br><br>`jsonpath "$.release" matches /\d{4}/` |
|
||||
| __`exists`__ | Query returns a value | `jsonpath "$.book" exists` |
|
||||
| __`isInteger`__ | Query returns an integer | `jsonpath "$.count" isInteger` |
|
||||
| __`isFloat`__ | Query returns a float | `jsonpath "$.height" isFloat` |
|
||||
| __`isBoolean`__ | Query returns a boolean | `jsonpath "$.suceeded" isBoolean` |
|
||||
| __`isString`__ | Query returns a string | `jsonpath "$.name" isString` |
|
||||
| __`isCollection`__ | Query returns a collection | `jsonpath "$.books" isCollection` |
|
||||
|
||||
|
||||
Each predicate can be negated by prefixing it with `not` (for instance, `not contains` or `not exists`)
|
||||
@ -170,7 +200,7 @@ Each predicate can be negated by prefixing it with `not` (for instance, `not con
|
||||
</div>
|
||||
|
||||
|
||||
A predicate values is typed, and can be a string, a boolean, a number, a bytestream, `null` or a collection. Note that
|
||||
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:
|
||||
@ -178,7 +208,7 @@ For instance, to test the presence of a h1 node in an HTML response, the followi
|
||||
```hurl
|
||||
GET https://example.org/home
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "boolean(count(//h1))" == true
|
||||
xpath "//h1" exists # Equivalent but simpler
|
||||
@ -201,7 +231,7 @@ The following assert will check the value of the `data-visible` attribute:
|
||||
```hurl
|
||||
GET https://example.org/home
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "string(//article/@data-visible)" == "true"
|
||||
```
|
||||
@ -209,14 +239,14 @@ 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 `equals` can work with string, number or boolean while `matches`, `startWith` and `contains` work
|
||||
only on string. If a query returns a number, a `contains` predicate will raise a runner error.
|
||||
The predicate function `equals` 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/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" contains "text/html"
|
||||
header "Last-Modified" == "Wed, 21 Oct 2015 07:28:00 GMT"
|
||||
@ -234,22 +264,23 @@ function and value.
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 *
|
||||
HTTP *
|
||||
[Asserts]
|
||||
status < 300
|
||||
```
|
||||
|
||||
### Header assert
|
||||
|
||||
Check the value of a received HTTP response header. Header assert consists of the keyword `header` followed by a predicate
|
||||
function and value.
|
||||
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.
|
||||
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 302
|
||||
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`, `includes` can be
|
||||
@ -261,7 +292,7 @@ Let's say we have this request and response:
|
||||
> GET /hello HTTP/1.1
|
||||
> Host: example.org
|
||||
> Accept: */*
|
||||
> User-Agent: hurl/1.8.0-SNAPSHOT
|
||||
> User-Agent: hurl/2.0.0-SNAPSHOT
|
||||
>
|
||||
* Response: (received 12 bytes in 11 ms)
|
||||
*
|
||||
@ -279,7 +310,7 @@ One can use explicit header asserts:
|
||||
```hurl
|
||||
GET https://example.org/hello
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Vary" count == 2
|
||||
header "Vary" includes "User-Agent"
|
||||
@ -291,7 +322,7 @@ Or implicit header asserts:
|
||||
```hurl
|
||||
GET https://example.org/hello
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
Vary: User-Agent
|
||||
Vary: Content-Type
|
||||
```
|
||||
@ -306,7 +337,7 @@ GET https://example.org/redirecting
|
||||
[Options]
|
||||
location: true
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
url == "https://example.org/redirected"
|
||||
```
|
||||
@ -325,7 +356,7 @@ Cookie attributes value can be checked by using the following format:
|
||||
```hurl
|
||||
GET http://localhost:8000/cookies/set
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
|
||||
# Explicit check of Set-Cookie header value. If the attributes are
|
||||
# not in this exact order, this assert will fail.
|
||||
@ -361,13 +392,11 @@ value. The encoding used to decode the body is based on the `charset` value in t
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
body contains "<h1>Welcome!</h1>"
|
||||
```
|
||||
|
||||
> Precise the encoding used to decode the text body.
|
||||
|
||||
### Bytes assert
|
||||
|
||||
Check the value of the received HTTP response body as a bytestream. Body assert
|
||||
@ -376,9 +405,11 @@ consists of the keyword `bytes` followed by a predicate function and value.
|
||||
```hurl
|
||||
GET https://example.org/data.bin
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
bytes startsWith hex,efbbbf;
|
||||
bytes count == 12424
|
||||
header "Content-Length" == "12424"
|
||||
```
|
||||
|
||||
### XPath assert
|
||||
@ -418,9 +449,8 @@ With Hurl, we can write multiple XPath asserts describing the DOM content:
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
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>
|
||||
@ -446,7 +476,7 @@ This XML response can be tested with the following Hurl file:
|
||||
```hurl
|
||||
GET http://localhost:8000/assert-xpath
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
|
||||
xpath "string(//bk:book/bk:title)" == "Cheaper by the Dozen"
|
||||
@ -467,7 +497,7 @@ namespaces.
|
||||
### JSONPath assert
|
||||
|
||||
Check the value of a [JSONPath] query on the received HTTP body decoded as a JSON
|
||||
document. Body assert consists of the keyword `jsonpath` followed by a predicate
|
||||
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:
|
||||
@ -501,7 +531,7 @@ With Hurl, we can write multiple JSONPath asserts describing the DOM content:
|
||||
```hurl
|
||||
GET http://httpbin.org/json
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.slideshow.author" == "Yours Truly"
|
||||
jsonpath "$.slideshow.slides[0].title" contains "Wonder"
|
||||
@ -520,7 +550,7 @@ the readability:
|
||||
```hurl
|
||||
GET https://sample.org/hello
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
# Predicate value with matches predicate:
|
||||
jsonpath "$.date" matches "^\\d{4}-\\d{2}-\\d{2}$"
|
||||
@ -537,11 +567,19 @@ Check that the HTTP received body, decoded as text, matches a regex pattern.
|
||||
```hurl
|
||||
GET https://sample.org/hello
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
regex "^\\d{4}-\\d{2}-\\d{2}$" == "2018-12-31"
|
||||
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.
|
||||
|
||||
|
||||
### SHA-256 assert
|
||||
|
||||
Check response body [SHA-256] hash.
|
||||
@ -549,7 +587,7 @@ Check response body [SHA-256] hash.
|
||||
```hurl
|
||||
GET https://example.org/data.tar.gz
|
||||
|
||||
HTTP/* *
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
|
||||
```
|
||||
@ -561,7 +599,7 @@ Check response body [MD5] hash.
|
||||
```hurl
|
||||
GET https://example.org/data.tar.gz
|
||||
|
||||
HTTP/* *
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
md5 == hex,ed076287532e86365e841e92bfc50d8c;
|
||||
```
|
||||
@ -572,7 +610,8 @@ md5 == hex,ed076287532e86365e841e92bfc50d8c;
|
||||
```hurl
|
||||
# Test that the XML endpoint return 200 pets
|
||||
GET https://example.org/api/pets
|
||||
HTTP/* 200
|
||||
|
||||
HTTP 200
|
||||
[Captures]
|
||||
pets: xpath "//pets"
|
||||
[Asserts]
|
||||
@ -586,37 +625,11 @@ Check the total duration (sending plus receiving time) of the HTTP transaction.
|
||||
```hurl
|
||||
GET https://sample.org/helloworld
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
duration < 1000 # Check that response time is less than one second
|
||||
```
|
||||
|
||||
## Filters
|
||||
|
||||
Optionally, asserts can be refined using filters `count` and `regex`.
|
||||
|
||||
### Count filter
|
||||
|
||||
```hurl
|
||||
GET https://pets.org/cats/cutest
|
||||
|
||||
HTTP/1.0 200
|
||||
[Asserts]
|
||||
jsonpath "$.cats" count == 12
|
||||
```
|
||||
|
||||
### Regex filter
|
||||
|
||||
```hurl
|
||||
GET https://pets.org/cats/cutest
|
||||
|
||||
HTTP/1.0 200
|
||||
# Cat name are structured like this `meow + id`: for instance `meow123456`
|
||||
[Asserts]
|
||||
jsonpath "$.cats[0].name" regex /meow(\d+)/ == "123456"
|
||||
```
|
||||
|
||||
|
||||
## Body
|
||||
|
||||
Optional assertion on the received HTTP response body. Body section can be seen
|
||||
@ -634,7 +647,7 @@ the body byte content to check.
|
||||
# Get a doggy thing:
|
||||
GET https://example.org/api/dogs/{{dog-id}}
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
{
|
||||
"id": 0,
|
||||
"name": "Frieda",
|
||||
@ -645,12 +658,32 @@ HTTP/1.1 200
|
||||
}
|
||||
```
|
||||
|
||||
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/1.1 200
|
||||
HTTP 200
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<catalog>
|
||||
<book id="bk101">
|
||||
@ -664,12 +697,34 @@ HTTP/1.1 200
|
||||
</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/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
Year,Make,Model,Description,Price
|
||||
1997,Ford,E350,"ac, abs, moon",3000.00
|
||||
@ -689,41 +744,28 @@ line3
|
||||
```
|
||||
~~~
|
||||
|
||||
is evaluated as "line1\nline2\nline3\n".
|
||||
#### Oneline string body
|
||||
|
||||
For text based response body that do not contain newlines, one can use oneline string, started and ending with <code>`</code>.
|
||||
|
||||
To construct an empty string :
|
||||
~~~hurl
|
||||
POST https://example.org/helloworld
|
||||
|
||||
~~~
|
||||
```
|
||||
```
|
||||
HTTP 200
|
||||
`Hello world!`
|
||||
~~~
|
||||
|
||||
or
|
||||
|
||||
~~~
|
||||
``````
|
||||
~~~
|
||||
|
||||
|
||||
Finally, multiline can be used without any newline:
|
||||
|
||||
~~~
|
||||
```line```
|
||||
~~~
|
||||
|
||||
is evaluated as "line".
|
||||
|
||||
### Base64 body
|
||||
|
||||
Base64 body assert starts with `base64,` and end with `;`. MIME's Base64 encoding
|
||||
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/1.1 200
|
||||
HTTP 200
|
||||
base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIG
|
||||
FkaXBpc2NpbmcgZWxpdC4gSW4gbWFsZXN1YWRhLCBuaXNsIHZlbCBkaWN0dW0g
|
||||
aGVuZHJlcml0LCBlc3QganVzdG8gYmliZW5kdW0gbWV0dXMsIG5lYyBydXRydW
|
||||
@ -738,7 +780,7 @@ can be used. File body starts with `file,` and ends with `;``
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
file,data.bin;
|
||||
```
|
||||
|
||||
@ -760,9 +802,11 @@ of all file nodes.
|
||||
[XML]: https://en.wikipedia.org/wiki/XML
|
||||
[Base64]: https://en.wikipedia.org/wiki/Base64
|
||||
[`--file-root` option]: /docs/manual.md#file-root
|
||||
[`count`]: /docs/capturing-response.md#count-subquery
|
||||
[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
|
250
docs/assets/cast/hurl.cast
Normal file
250
docs/assets/cast/hurl.cast
Normal file
@ -0,0 +1,250 @@
|
||||
{"version": 2, "width": 80, "height": 25, "timestamp": 1665239255, "env": {"SHELL": "/bin/zsh", "TERM": "xterm-256color", "PROMPT": "%F{cyan}$%f "}}
|
||||
[0.01621, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
|
||||
[0.027176, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[36m$\u001b[39m \u001b[K\u001b[?2004h"]
|
||||
[0.51818, "o", "v"]
|
||||
[0.667008, "o", "\bvi"]
|
||||
[0.906839, "o", "m"]
|
||||
[0.967164, "o", " "]
|
||||
[1.297275, "o", "s"]
|
||||
[1.509441, "o", "t"]
|
||||
[1.688824, "o", "a"]
|
||||
[1.824537, "o", "r"]
|
||||
[2.318819, "o", "w"]
|
||||
[2.527648, "o", "a"]
|
||||
[2.708786, "o", "r"]
|
||||
[2.798336, "o", "s"]
|
||||
[3.247485, "o", "."]
|
||||
[3.578633, "o", "h"]
|
||||
[3.757589, "o", "u"]
|
||||
[3.846672, "o", "r"]
|
||||
[4.088367, "o", "l"]
|
||||
[4.95909, "o", "\u001b[?2004l\r\r\n"]
|
||||
[5.010246, "o", "\u001b[?1049h\u001b[>4;2m\u001b[?1h\u001b=\u001b[?2004h\u001b[?1004h\u001b[1;25r\u001b[?12h\u001b[?12l\u001b[22;2t\u001b[22;1t"]
|
||||
[5.010721, "o", "\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[?25l\u001b[25;1H\"starwars.hurl\" [New]"]
|
||||
[5.015574, "o", "\u001b[2;1H▽\u001b[6n\u001b[2;1H \u001b[3;1H\u001bPzz\u001b\\\u001b[0%m\u001b[6n\u001b[3;1H \u001b[1;1H\u001b[>c"]
|
||||
[5.015583, "o", "\u001b]10;?\u0007\u001b]11;?\u0007"]
|
||||
[5.016023, "o", "\u001b[1;1H\u001b[38;5;242m 1 \u001b[m\r\n\u001b[94m~ \u001b[3;1H~ \u001b[4;1H~ \u001b[5;1H~ \u001b[6;1H~ \u001b[7;1H~ \u001b[8;1H~ \u001b[9;1H~ \u001b[10;1H~ \u001b[11;1H~ \u001b[12;1H~ \u001b[13;1H~ "]
|
||||
[5.016049, "o", " \u001b[14;1H~ \u001b[15;1H~ \u001b[16;1H~ \u001b[17;1H~ \u001b[18;1H~ \u001b[19;1H~ \u001b[20;1H~ \u001b[21;1H~ \u001b[22;1H~ \u001b[23;1H~ \u001b[m\u001b[24;1H\u001b[38;5;238m\u001b[48;5;117m NORMAL "]
|
||||
[5.016131, "o", "\u001b[m\u001b[38;5;252m\u001b[48;5;240m starwars.hurl \u001b[m\u001b[38;5;248m\u001b[48;5;238m unix | utf-8 | hurl \u001b[m\u001b[38;5;247m\u001b[48;5;240m 100% \u001b[m\u001b[38;5;238m\u001b[48;5;244m 0:0 \u001b[1;5H\u001b[?25h"]
|
||||
[5.016144, "o", "\u001b[?12$p"]
|
||||
[5.980583, "o", "\u001b[m\u001b[24;1H\u001b[38;5;238m\u001b[48;5;119m INSERT \u001b[m\u001b[69C\u001b[38;5;238m\u001b[48;5;244m1\u001b[1;5H\u001b[?25l\u001b[?25h"]
|
||||
[6.339754, "o", "\u001b[?25l\u001b[mG\u001b[24;24H\u001b[38;5;252m\u001b[48;5;240m| + \u001b[m\u001b[48C\u001b[38;5;238m\u001b[48;5;244m1:2\u001b[1;6H\u001b[?25h"]
|
||||
[6.426642, "o", "\u001b[?25l\u001b[mE\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m3\u001b[1;7H\u001b[?25h"]
|
||||
[6.580036, "o", "\u001b[?25l\u001b[m\b\b\u001b[93mGET\u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m4\u001b[1;8H\u001b[?25h"]
|
||||
[6.656322, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m \u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m5\u001b[1;9H\u001b[?25h"]
|
||||
[7.720245, "o", "\u001b[?25l\u001b[mh\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m6\u001b[1;10H\u001b[?25h"]
|
||||
[7.959788, "o", "\u001b[?25l\u001b[mt\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m7\u001b[1;11H\u001b[?25h"]
|
||||
[8.064465, "o", "\u001b[?25l\u001b[mt\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m8\u001b[1;12H\u001b[?25h"]
|
||||
[8.350182, "o", "\u001b[?25l\u001b[mp\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m9\u001b[1;13H\u001b[?25h"]
|
||||
[8.530041, "o", "\u001b[?25l\u001b[ms\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m10\u001b[1;14H\u001b[?25h"]
|
||||
[8.82781, "o", "\u001b[?25l\u001b[m:\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[1;15H\u001b[?25h"]
|
||||
[9.159365, "o", "\u001b[?25l\u001b[m/\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m2\u001b[1;16H\u001b[?25h"]
|
||||
[9.29217, "o", "\u001b[?25l\u001b[m/\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m3\u001b[1;17H\u001b[?25h"]
|
||||
[9.608683, "o", "\u001b[?25l\u001b[ms\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m4\u001b[1;18H\u001b[?25h"]
|
||||
[9.772887, "o", "\u001b[?25l\u001b[mw\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m5\u001b[1;19H\u001b[?25h"]
|
||||
[9.998823, "o", "\u001b[?25l\u001b[ma\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m6\u001b[1;20H\u001b[?25h"]
|
||||
[10.18035, "o", "\u001b[?25l\u001b[mp\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m7\u001b[1;21H\u001b[?25h"]
|
||||
[10.222808, "o", "\u001b[?25l\u001b[mi\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m8\u001b[1;22H\u001b[?25h"]
|
||||
[10.599361, "o", "\u001b[?25l\u001b[m.\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m9\u001b[1;23H\u001b[?25h"]
|
||||
[10.809162, "o", "\u001b[?25l\u001b[md\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m20\u001b[1;24H\u001b[?25h"]
|
||||
[10.959103, "o", "\u001b[?25l\u001b[me\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[1;25H\u001b[?25h"]
|
||||
[11.034188, "o", "\u001b[?25l\u001b[mv\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m2\u001b[1;26H\u001b[?25h"]
|
||||
[11.52938, "o", "\u001b[?25l\u001b[m/\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m3\u001b[1;27H\u001b[?25h"]
|
||||
[11.769769, "o", "\u001b[?25l\u001b[ma\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m4\u001b[1;28H\u001b[?25h"]
|
||||
[11.979865, "o", "\u001b[?25l\u001b[mp\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m5\u001b[1;29H\u001b[?25h"]
|
||||
[11.993141, "o", "\u001b[?25l\u001b[mi\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m6\u001b[1;30H\u001b[?25h"]
|
||||
[12.444503, "o", "\u001b[?25l\u001b[m/\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m7\u001b[1;31H\u001b[?25h"]
|
||||
[12.792815, "o", "\u001b[?25l\u001b[mp\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m8\u001b[1;32H\u001b[?25h"]
|
||||
[12.938877, "o", "\u001b[?25l\u001b[me\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m9\u001b[1;33H\u001b[?25h"]
|
||||
[13.149924, "o", "\u001b[?25l\u001b[mo\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m30\u001b[1;34H\u001b[?25h"]
|
||||
[13.360561, "o", "\u001b[?25l\u001b[mp\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[1;35H\u001b[?25h"]
|
||||
[13.509042, "o", "\u001b[?25l\u001b[ml\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m2\u001b[1;36H\u001b[?25h"]
|
||||
[13.644134, "o", "\u001b[?25l\u001b[me\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m3\u001b[1;37H\u001b[?25h"]
|
||||
[14.230904, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 2 \u001b[m\u001b[2;5H\u001b[K\u001b[24;76H\u001b[38;5;238m\u001b[48;5;244m2:1 \u001b[2;5H\u001b[?25h"]
|
||||
[14.366055, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 3 \u001b[m\u001b[3;5H\u001b[K\u001b[24;76H\u001b[38;5;238m\u001b[48;5;244m3\u001b[3;5H\u001b[?25h"]
|
||||
[16.118006, "o", "\u001b[?25l\u001b[mH\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m2\u001b[3;6H\u001b[?25h"]
|
||||
[16.361333, "o", "\u001b[?25l\u001b[mT\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m3\u001b[3;7H\u001b[?25h"]
|
||||
[16.479912, "o", "\u001b[?25l\u001b[mT\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m4\u001b[3;8H\u001b[?25h"]
|
||||
[16.765441, "o", "\u001b[?25l\u001b[mP\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m5\u001b[3;9H\u001b[?25h"]
|
||||
[17.089972, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m \u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m8\u001b[3;10H\u001b[?25h"]
|
||||
[17.479949, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m2\u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m9\u001b[3;11H\u001b[?25h"]
|
||||
[17.750065, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m0\u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m10\u001b[3;12H\u001b[?25h"]
|
||||
[17.885149, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m0\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[3;13H\u001b[?25h"]
|
||||
[18.938288, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 4 \u001b[m\u001b[4;5H\u001b[K\u001b[24;76H\u001b[38;5;238m\u001b[48;5;244m4:1 \u001b[4;5H\u001b[?25h"]
|
||||
[19.930771, "o", "\u001b[?25l\u001b[m[\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m2\u001b[4;6H\u001b[?25h"]
|
||||
[20.469027, "o", "\u001b[?25l\u001b[mA\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m3\u001b[4;7H\u001b[?25h"]
|
||||
[20.777164, "o", "\u001b[?25l\u001b[ms\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m4\u001b[4;8H\u001b[?25h"]
|
||||
[20.903673, "o", "\u001b[?25l\u001b[ms\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m5\u001b[4;9H\u001b[?25h"]
|
||||
[21.160428, "o", "\u001b[?25l\u001b[me\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m6\u001b[4;10H\u001b[?25h"]
|
||||
[21.368903, "o", "\u001b[?25l\u001b[mr\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m7\u001b[4;11H\u001b[?25h"]
|
||||
[21.609942, "o", "\u001b[?25l\u001b[mt\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m8\u001b[4;12H\u001b[?25h"]
|
||||
[21.775268, "o", "\u001b[?25l\u001b[ms\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m9\u001b[4;13H\u001b[?25h"]
|
||||
[22.688437, "o", "\u001b[?25l\u001b[m\u001b[4;5H\u001b[95m[Asserts]\u001b[m\u001b[4;5H\u001b[95m\u001b[46m[\u001b[7C]\u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m10\u001b[4;14H\u001b[?25h"]
|
||||
[22.9887, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 5 \u001b[m\u001b[5;5H\u001b[K\u001b[4;5H\u001b[95m[\u001b[7C]\u001b[m\u001b[24;76H\u001b[38;5;238m\u001b[48;5;244m5:1 \u001b[5;5H\u001b[?25h"]
|
||||
[23.68264, "o", "\u001b[?25l\u001b[mj\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m2\u001b[5;6H\u001b[?25h"]
|
||||
[23.78524, "o", "\u001b[?25l\u001b[ms\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m3\u001b[5;7H\u001b[?25h"]
|
||||
[23.919476, "o", "\u001b[?25l\u001b[mo\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m4\u001b[5;8H\u001b[?25h"]
|
||||
[23.980456, "o", "\u001b[?25l\u001b[mn\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m5\u001b[5;9H\u001b[?25h"]
|
||||
[24.189599, "o", "\u001b[?25l\u001b[mp\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m6\u001b[5;10H\u001b[?25h"]
|
||||
[24.291845, "o", "\u001b[?25l\u001b[ma\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m7\u001b[5;11H\u001b[?25h"]
|
||||
[24.45999, "o", "\u001b[?25l\u001b[mt\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m8\u001b[5;12H\u001b[?25h"]
|
||||
[24.639712, "o", "\u001b[?25l\u001b[mh\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m9\u001b[5;13H\u001b[?25h"]
|
||||
[24.684401, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m \u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m10\u001b[5;14H\u001b[?25h"]
|
||||
[25.000139, "o", "\u001b[?25l\u001b[m\u001b[92m\"\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[5;15H\u001b[?25h"]
|
||||
[25.51158, "o", "\u001b[?25l\u001b[m\u001b[92m$\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m2\u001b[5;16H\u001b[?25h"]
|
||||
[25.8998, "o", "\u001b[?25l\u001b[m\u001b[92m.\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m3\u001b[5;17H\u001b[?25h"]
|
||||
[26.138606, "o", "\u001b[?25l\u001b[m\u001b[92mc\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m4\u001b[5;18H\u001b[?25h"]
|
||||
[26.318844, "o", "\u001b[?25l\u001b[m\u001b[92mo\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m5\u001b[5;19H\u001b[?25h"]
|
||||
[26.349408, "o", "\u001b[?25l\u001b[m\u001b[92mu\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m6\u001b[5;20H\u001b[?25h"]
|
||||
[26.589545, "o", "\u001b[?25l\u001b[m\u001b[92mn\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m7\u001b[5;21H\u001b[?25h"]
|
||||
[26.666032, "o", "\u001b[?25l\u001b[m\u001b[92mt\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m8\u001b[5;22H\u001b[?25h"]
|
||||
[26.98015, "o", "\u001b[?25l\u001b[m\u001b[92m\"\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m9\u001b[5;23H\u001b[?25h"]
|
||||
[27.400301, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m \u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m20\u001b[5;24H\u001b[?25h"]
|
||||
[27.940385, "o", "\u001b[?25l\u001b[m=\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[5;25H\u001b[?25h"]
|
||||
[28.058324, "o", "\u001b[?25l\u001b[m=\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m2\u001b[5;26H\u001b[?25h"]
|
||||
[28.330285, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m \u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m3\u001b[5;27H\u001b[?25h"]
|
||||
[28.869495, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m8\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m4\u001b[5;28H\u001b[?25h"]
|
||||
[29.16975, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m2\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m5\u001b[5;29H\u001b[?25h"]
|
||||
[29.559967, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 6 \u001b[m\u001b[6;5H\u001b[K\u001b[24;76H\u001b[38;5;238m\u001b[48;5;244m6:1 \u001b[6;5H\u001b[?25h"]
|
||||
[29.679857, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 7 \u001b[m\u001b[7;5H\u001b[K\u001b[24;76H\u001b[38;5;238m\u001b[48;5;244m7\u001b[7;5H\u001b[?25h"]
|
||||
[29.890601, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 8 \u001b[m\u001b[8;5H\u001b[K\u001b[24;76H\u001b[38;5;238m\u001b[48;5;244m8\u001b[8;5H\u001b[?25h"]
|
||||
[31.299997, "o", "\u001b[?25l\u001b[mG\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m2\u001b[8;6H\u001b[?25h"]
|
||||
[31.418839, "o", "\u001b[?25l\u001b[mE\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m3\u001b[8;7H\u001b[?25h"]
|
||||
[31.538763, "o", "\u001b[?25l\u001b[m\b\b\u001b[93mGET\u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m4\u001b[8;8H\u001b[?25h"]
|
||||
[31.614974, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m \u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m5\u001b[8;9H\u001b[?25h"]
|
||||
[32.680907, "o", "\u001b[?25l\u001b[mh\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m6\u001b[8;10H\u001b[?25h"]
|
||||
[32.890015, "o", "\u001b[?25l\u001b[mt\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m7\u001b[8;11H\u001b[?25h"]
|
||||
[33.008892, "o", "\u001b[?25l\u001b[mt\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m8\u001b[8;12H\u001b[?25h"]
|
||||
[33.340299, "o", "\u001b[?25l\u001b[mp\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m9\u001b[8;13H\u001b[?25h"]
|
||||
[33.487104, "o", "\u001b[?25l\u001b[ms\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m10\u001b[8;14H\u001b[?25h"]
|
||||
[33.702452, "o", "\u001b[?25l\u001b[m:\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[8;15H\u001b[?25h"]
|
||||
[33.984328, "o", "\u001b[?25l\u001b[m/\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m2\u001b[8;16H\u001b[?25h"]
|
||||
[34.119828, "o", "\u001b[?25l\u001b[m/\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m3\u001b[8;17H\u001b[?25h"]
|
||||
[34.328978, "o", "\u001b[?25l\u001b[ms\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m4\u001b[8;18H\u001b[?25h"]
|
||||
[34.508459, "o", "\u001b[?25l\u001b[mw\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m5\u001b[8;19H\u001b[?25h"]
|
||||
[34.690022, "o", "\u001b[?25l\u001b[ma\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m6\u001b[8;20H\u001b[?25h"]
|
||||
[34.870277, "o", "\u001b[?25l\u001b[mp\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m7\u001b[8;21H\u001b[?25h"]
|
||||
[34.94284, "o", "\u001b[?25l\u001b[mi\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m8\u001b[8;22H\u001b[?25h"]
|
||||
[35.271978, "o", "\u001b[?25l\u001b[m.\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m9\u001b[8;23H\u001b[?25h"]
|
||||
[35.530057, "o", "\u001b[?25l\u001b[md\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m20\u001b[8;24H\u001b[?25h"]
|
||||
[35.679772, "o", "\u001b[?25l\u001b[me\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[8;25H\u001b[?25h"]
|
||||
[35.785471, "o", "\u001b[?25l\u001b[mv\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m2\u001b[8;26H\u001b[?25h"]
|
||||
[36.234008, "o", "\u001b[?25l\u001b[m/\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m3\u001b[8;27H\u001b[?25h"]
|
||||
[36.429984, "o", "\u001b[?25l\u001b[ma\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m4\u001b[8;28H\u001b[?25h"]
|
||||
[36.639217, "o", "\u001b[?25l\u001b[mp\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m5\u001b[8;29H\u001b[?25h"]
|
||||
[36.700511, "o", "\u001b[?25l\u001b[mi\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m6\u001b[8;30H\u001b[?25h"]
|
||||
[37.179882, "o", "\u001b[?25l\u001b[m/\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m7\u001b[8;31H\u001b[?25h"]
|
||||
[38.199234, "o", "\u001b[?25l\u001b[mp\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m8\u001b[8;32H\u001b[?25h"]
|
||||
[38.320493, "o", "\u001b[?25l\u001b[me\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m9\u001b[8;33H\u001b[?25h"]
|
||||
[38.500165, "o", "\u001b[?25l\u001b[mo\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m30\u001b[8;34H\u001b[?25h"]
|
||||
[38.737671, "o", "\u001b[?25l\u001b[mp\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[8;35H\u001b[?25h"]
|
||||
[38.889822, "o", "\u001b[?25l\u001b[ml\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m2\u001b[8;36H\u001b[?25h"]
|
||||
[39.010086, "o", "\u001b[?25l\u001b[me\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m3\u001b[8;37H\u001b[?25h"]
|
||||
[39.354628, "o", "\u001b[?25l\u001b[m/\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m4\u001b[8;38H\u001b[?25h"]
|
||||
[39.669139, "o", "\u001b[?25l\u001b[m1\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m5\u001b[8;39H\u001b[?25h"]
|
||||
[40.300656, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 9 \u001b[m\u001b[9;5H\u001b[K\u001b[24;76H\u001b[38;5;238m\u001b[48;5;244m9:1 \u001b[9;5H\u001b[?25h"]
|
||||
[40.405191, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 10 \u001b[m\u001b[10;5H\u001b[K\u001b[24;75H\u001b[38;5;238m\u001b[48;5;244m10\u001b[10;5H\u001b[?25h"]
|
||||
[41.200373, "o", "\u001b[?25l\u001b[mH\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m2\u001b[10;6H\u001b[?25h"]
|
||||
[41.409986, "o", "\u001b[?25l\u001b[mT\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m3\u001b[10;7H\u001b[?25h"]
|
||||
[41.543744, "o", "\u001b[?25l\u001b[mT\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m4\u001b[10;8H\u001b[?25h"]
|
||||
[41.888207, "o", "\u001b[?25l\u001b[mP\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m5\u001b[10;9H\u001b[?25h"]
|
||||
[42.466984, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m \u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m8\u001b[10;10H\u001b[?25h"]
|
||||
[42.885714, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m2\u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m9\u001b[10;11H\u001b[?25h"]
|
||||
[43.09993, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m0\u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m10\u001b[10;12H\u001b[?25h"]
|
||||
[43.750093, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m0\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[10;13H\u001b[?25h"]
|
||||
[44.379124, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 11 \u001b[m\u001b[11;5H\u001b[K\u001b[24;76H\u001b[38;5;238m\u001b[48;5;244m1:1 \u001b[11;5H\u001b[?25h"]
|
||||
[45.520172, "o", "\u001b[?25l\u001b[m[\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m2\u001b[11;6H\u001b[?25h"]
|
||||
[46.331364, "o", "\u001b[?25l\u001b[mA\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m3\u001b[11;7H\u001b[?25h"]
|
||||
[47.410577, "o", "\u001b[?25l\u001b[ms\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m4\u001b[11;8H\u001b[?25h"]
|
||||
[47.54615, "o", "\u001b[?25l\u001b[ms\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m5\u001b[11;9H\u001b[?25h"]
|
||||
[47.800418, "o", "\u001b[?25l\u001b[me\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m6\u001b[11;10H\u001b[?25h"]
|
||||
[47.979125, "o", "\u001b[?25l\u001b[mr\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m7\u001b[11;11H\u001b[?25h"]
|
||||
[48.188143, "o", "\u001b[?25l\u001b[mt\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m8\u001b[11;12H\u001b[?25h"]
|
||||
[48.355861, "o", "\u001b[?25l\u001b[ms\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m9\u001b[11;13H\u001b[?25h"]
|
||||
[49.001936, "o", "\u001b[?25l\u001b[m\u001b[11;5H\u001b[95m[Asserts]\u001b[m\u001b[11;5H\u001b[95m\u001b[46m[\u001b[7C]\u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m10\u001b[11;14H\u001b[?25h"]
|
||||
[49.327319, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 12 \u001b[m\u001b[12;5H\u001b[K\u001b[11;5H\u001b[95m[\u001b[7C]\u001b[m\u001b[24;76H\u001b[38;5;238m\u001b[48;5;244m2:1 \u001b[12;5H\u001b[?25h"]
|
||||
[50.02065, "o", "\u001b[?25l\u001b[mj\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m2\u001b[12;6H\u001b[?25h"]
|
||||
[50.288374, "o", "\u001b[?25l\u001b[ms\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m3\u001b[12;7H\u001b[?25h"]
|
||||
[50.619446, "o", "\u001b[?25l\u001b[mo\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m4\u001b[12;8H\u001b[?25h"]
|
||||
[50.646937, "o", "\u001b[?25l\u001b[mn\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m5\u001b[12;9H\u001b[?25h"]
|
||||
[50.859392, "o", "\u001b[?25l\u001b[mp\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m6\u001b[12;10H\u001b[?25h"]
|
||||
[50.979905, "o", "\u001b[?25l\u001b[ma\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m7\u001b[12;11H\u001b[?25h"]
|
||||
[51.160997, "o", "\u001b[?25l\u001b[mt\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m8\u001b[12;12H\u001b[?25h"]
|
||||
[51.370097, "o", "\u001b[?25l\u001b[mh\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m9\u001b[12;13H\u001b[?25h"]
|
||||
[51.415244, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m \u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m10\u001b[12;14H\u001b[?25h"]
|
||||
[51.700144, "o", "\u001b[?25l\u001b[m\u001b[92m\"\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[12;15H\u001b[?25h"]
|
||||
[52.360838, "o", "\u001b[?25l\u001b[m\u001b[92m$\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m2\u001b[12;16H\u001b[?25h"]
|
||||
[52.809737, "o", "\u001b[?25l\u001b[m\u001b[92m.\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m3\u001b[12;17H\u001b[?25h"]
|
||||
[53.470085, "o", "\u001b[?25l\u001b[m\u001b[92mn\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m4\u001b[12;18H\u001b[?25h"]
|
||||
[53.560389, "o", "\u001b[?25l\u001b[m\u001b[92ma\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m5\u001b[12;19H\u001b[?25h"]
|
||||
[53.800169, "o", "\u001b[?25l\u001b[m\u001b[92mm\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m6\u001b[12;20H\u001b[?25h"]
|
||||
[53.873787, "o", "\u001b[?25l\u001b[m\u001b[92me\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m7\u001b[12;21H\u001b[?25h"]
|
||||
[54.13006, "o", "\u001b[?25l\u001b[m\u001b[92m\"\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m8\u001b[12;22H\u001b[?25h"]
|
||||
[54.430549, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m \u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m9\u001b[12;23H\u001b[?25h"]
|
||||
[54.999008, "o", "\u001b[?25l\u001b[m=\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m20\u001b[12;24H\u001b[?25h"]
|
||||
[55.103269, "o", "\u001b[?25l\u001b[m=\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[12;25H\u001b[?25h"]
|
||||
[55.419937, "o", "\u001b[?25l\u001b[m\u001b[38;5;81m \u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m2\u001b[12;26H\u001b[?25h"]
|
||||
[55.541378, "o", "\u001b[?25l\u001b[m\u001b[92m\"\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m3\u001b[12;27H\u001b[?25h"]
|
||||
[56.169023, "o", "\u001b[?25l\u001b[m\u001b[92mD\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m4\u001b[12;28H\u001b[?25h"]
|
||||
[56.530119, "o", "\u001b[?25l\u001b[m\u001b[92ma\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m5\u001b[12;29H\u001b[?25h"]
|
||||
[56.66352, "o", "\u001b[?25l\u001b[m\u001b[92mr\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m6\u001b[12;30H\u001b[?25h"]
|
||||
[56.888287, "o", "\u001b[?25l\u001b[m\u001b[92mt\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m7\u001b[12;31H\u001b[?25h"]
|
||||
[57.217614, "o", "\u001b[?25l\u001b[m\u001b[92mh\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m8\u001b[12;32H\u001b[?25h"]
|
||||
[57.729172, "o", "\u001b[?25l\u001b[m\u001b[92m \u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m9\u001b[12;33H\u001b[?25h"]
|
||||
[58.089175, "o", "\u001b[?25l\u001b[m\u001b[92mV\u001b[m\u001b[24;78H\u001b[38;5;238m\u001b[48;5;244m30\u001b[12;34H\u001b[?25h"]
|
||||
[58.810289, "o", "\u001b[?25l\u001b[m\u001b[92ma\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m1\u001b[12;35H\u001b[?25h"]
|
||||
[59.050431, "o", "\u001b[?25l\u001b[m\u001b[92md\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m2\u001b[12;36H\u001b[?25h"]
|
||||
[59.230771, "o", "\u001b[?25l\u001b[m\u001b[92me\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m3\u001b[12;37H\u001b[?25h"]
|
||||
[59.407561, "o", "\u001b[?25l\u001b[m\u001b[92mr\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m4\u001b[12;38H\u001b[?25h"]
|
||||
[59.619514, "o", "\u001b[?25l\u001b[m\u001b[92m\"\u001b[m\u001b[24;79H\u001b[38;5;238m\u001b[48;5;244m5\u001b[12;39H\u001b[?25h"]
|
||||
[60.251408, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 13 \u001b[m\u001b[13;5H\u001b[K\u001b[24;76H\u001b[38;5;238m\u001b[48;5;244m3:1 \u001b[13;5H\u001b[?25h"]
|
||||
[60.400358, "o", "\u001b[?25l\u001b[m\r\n\u001b[38;5;242m 14 \u001b[m\u001b[14;5H\u001b[K\u001b[24;76H\u001b[38;5;238m\u001b[48;5;244m4\u001b[14;5H\u001b[?25h"]
|
||||
[61.870358, "o", "\u001b[m\u001b[24;1H\u001b[38;5;238m\u001b[48;5;117m NORMAL \u001b[m\u001b[69C\u001b[38;5;238m\u001b[48;5;244m0\u001b[14;5H\u001b[?25l\u001b[m\u001b[25;1H\u001b[K\u001b[25;1H:\u001b[?25h"]
|
||||
[62.003726, "o", "w"]
|
||||
[62.199186, "o", "q"]
|
||||
[62.303996, "o", "\r"]
|
||||
[62.305851, "o", "\u001b[?25l\u001b[?2004l\u001b[>4;m\"starwars.hurl\""]
|
||||
[62.327041, "o", " [New] 14L, 176B written"]
|
||||
[62.331626, "o", "\r\u001b[23;2t\u001b[23;1t\r\r\n\u001b[?1004l\u001b[?2004l\u001b[?1l\u001b>\u001b[?25h\u001b[>4;m\u001b[?1049l"]
|
||||
[62.333658, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
|
||||
[62.352147, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[36m$\u001b[39m \u001b[K\u001b[?2004h"]
|
||||
[63.369186, "o", "h"]
|
||||
[63.549714, "o", "\bhu"]
|
||||
[64.062416, "o", "r"]
|
||||
[64.222636, "o", "l"]
|
||||
[64.298216, "o", " "]
|
||||
[64.627363, "o", "-"]
|
||||
[64.748937, "o", "-"]
|
||||
[65.106564, "o", "t"]
|
||||
[65.167739, "o", "e"]
|
||||
[65.347715, "o", "s"]
|
||||
[65.438304, "o", "t"]
|
||||
[65.498885, "o", " "]
|
||||
[65.963696, "o", "*"]
|
||||
[66.308602, "o", "."]
|
||||
[66.608382, "o", "h"]
|
||||
[66.789524, "o", "u"]
|
||||
[66.862967, "o", "r"]
|
||||
[67.012863, "o", "l"]
|
||||
[67.749707, "o", "\u001b[?2004l\r\r\n"]
|
||||
[67.760315, "o", "\u001b[1mbasic.hurl\u001b[0m: \u001b[1;36mRunning\u001b[0m [1/8]\r\n"]
|
||||
[68.192546, "o", "\u001b[1mbasic.hurl\u001b[0m: \u001b[1;32mSuccess\u001b[0m (4 request(s) in 431 ms)\r\n"]
|
||||
[68.196455, "o", "\u001b[1mhealth.hurl\u001b[0m: \u001b[1;36mRunning\u001b[0m [2/8]\r\n"]
|
||||
[68.458322, "o", "\u001b[1mhealth.hurl\u001b[0m: \u001b[1;32mSuccess\u001b[0m (6 request(s) in 261 ms)\r\n"]
|
||||
[68.462394, "o", "\u001b[1mlogin.hurl\u001b[0m: \u001b[1;36mRunning\u001b[0m [3/8]\r\n"]
|
||||
[68.724943, "o", "\u001b[1mlogin.hurl\u001b[0m: \u001b[1;32mSuccess\u001b[0m (6 request(s) in 261 ms)\r\n"]
|
||||
[68.728932, "o", "\u001b[1mlogout.hurl\u001b[0m: \u001b[1;36mRunning\u001b[0m [4/8]\r\n"]
|
||||
[68.995074, "o", "\u001b[1mlogout.hurl\u001b[0m: \u001b[1;32mSuccess\u001b[0m (6 request(s) in 265 ms)\r\n"]
|
||||
[69.001866, "o", "\u001b[1mnew-user.hurl\u001b[0m: \u001b[1;36mRunning\u001b[0m [5/8]\r\n"]
|
||||
[69.202078, "o", "\u001b[1mnew-user.hurl\u001b[0m: \u001b[1;32mSuccess\u001b[0m (4 request(s) in 200 ms)\r\n"]
|
||||
[69.206269, "o", "\u001b[1msecurity.hurl\u001b[0m: \u001b[1;36mRunning\u001b[0m [6/8]\r\n"]
|
||||
[69.410651, "o", "\u001b[1msecurity.hurl\u001b[0m: \u001b[1;32mSuccess\u001b[0m (4 request(s) in 203 ms)\r\n"]
|
||||
[69.414707, "o", "\u001b[1mstarwars.hurl\u001b[0m: \u001b[1;36mRunning\u001b[0m [7/8]\r\n"]
|
||||
[69.744533, "o", "\u001b[1;31merror\u001b[0m: \u001b[1mAssert failure\u001b[0m\r\n \u001b[1;34m-->\u001b[0m starwars.hurl:12:0\r\n \u001b[1;34m|\u001b[0m\r\n\u001b[1;34m12\u001b[0m \u001b[1;34m|\u001b[0m jsonpath \"$.name\" == \"Darth Vader\"\r\n \u001b[1;34m|\u001b[0m \u001b[1;31mactual: string <Luke Skywalker>\u001b[0m\r\n \u001b[1;34m|\u001b[0m \u001b[1;31mexpected: string <Darth Vader>\u001b[0m\r\n \u001b[1;34m|\u001b[0m\r\n\r\n\u001b[1mstarwars.hurl\u001b[0m: \u001b[1;31mFailure\u001b[0m (2 request(s) in 329 ms)\r\n"]
|
||||
[69.74857, "o", "\u001b[1mstress.hurl\u001b[0m: \u001b[1;36mRunning"]
|
||||
[69.748646, "o", "\u001b[0m [8/8]\r\n"]
|
||||
[69.967151, "o", "\u001b[1mstress.hurl\u001b[0m: \u001b[1;32mSuccess\u001b[0m (4 request(s) in 218 ms)\r\n"]
|
||||
[69.971905, "o", "--------------------------------------------------------------------------------\r\nExecuted files: 8\r\nSucceeded files: 7 (87.5%)\r\nFailed files: 1 (12.5%)\r\nDuration: 2211 ms\r\n\r\n"]
|
||||
[69.97336, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
|
||||
[69.991528, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[36m$\u001b[39m \u001b[K\u001b[?2004h"]
|
||||
[90.954253, "o", "\u001b[?2004l\r\r\n"]
|
Binary file not shown.
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 161 KiB |
@ -2,23 +2,22 @@
|
||||
|
||||
## Captures
|
||||
|
||||
Captures are optional values captured from the HTTP response, in a named variable. Captures can be the
|
||||
response status code, part of or the entire the body, and response headers.
|
||||
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 are available through a run session; each new value of a given variable overrides the last value.
|
||||
Captured variables can be accessed through a run session; each new value of a given variable overrides the last value.
|
||||
|
||||
Captures allow using data from one request in another request, when working with
|
||||
[CSRF tokens] for instance. Variables can also be initialized at the start of the
|
||||
session, by passing [variable values], or can be used in [templates].
|
||||
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:
|
||||
# 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/1.1 200
|
||||
HTTP 200
|
||||
# Capture the CSRF token value from html body.
|
||||
[Captures]
|
||||
csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"
|
||||
@ -27,7 +26,7 @@ csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"
|
||||
POST https://acmecorp.net/login?user=toto&password=1234
|
||||
X-CSRF-TOKEN: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
```
|
||||
|
||||
Structure of a capture:
|
||||
@ -40,13 +39,15 @@ Structure of a capture:
|
||||
</div>
|
||||
</div>
|
||||
|
||||
A capture consists of a variable name, followed by `:` and a query. The captures
|
||||
A capture consists of a variable name, followed by `:` and a query. Captures
|
||||
section starts with `[Captures]`.
|
||||
|
||||
|
||||
### Query
|
||||
|
||||
Query can be of the following type:
|
||||
Queries are used to extract data from an HTTP response.
|
||||
|
||||
A query can be of the following type:
|
||||
|
||||
- [`status`](#status-capture)
|
||||
- [`header`](#header-capture)
|
||||
@ -60,6 +61,7 @@ Query can be of the following type:
|
||||
- [`variable`](#variable-capture)
|
||||
- [`duration`](#duration-capture)
|
||||
|
||||
Extracted data can then be further refined using [filters].
|
||||
|
||||
### Status capture
|
||||
|
||||
@ -69,7 +71,7 @@ keyword `status`.
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
my_status: status
|
||||
```
|
||||
@ -85,7 +87,7 @@ POST https://example.org/login
|
||||
user: toto
|
||||
password: 12345678
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
[Captures]
|
||||
next_url: header "Location"
|
||||
```
|
||||
@ -100,7 +102,7 @@ GET https://example.org/redirecting
|
||||
[Options]
|
||||
location: true
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
landing_url: url
|
||||
```
|
||||
@ -114,7 +116,7 @@ and a cookie name.
|
||||
```hurl
|
||||
GET https://example.org/cookies/set
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
session-id: cookie "LSID"
|
||||
```
|
||||
@ -126,7 +128,7 @@ Cookie attributes value can also be captured by using the following format:
|
||||
```hurl
|
||||
GET https://example.org/cookies/set
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
value1: cookie "LSID"
|
||||
value2: cookie "LSID[Value]" # Equivalent to the previous capture
|
||||
@ -147,7 +149,7 @@ Capture the entire body (decoded as text) from the received HTTP response
|
||||
```hurl
|
||||
GET https://example.org/home
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
my_body: body
|
||||
```
|
||||
@ -159,7 +161,7 @@ Capture the entire body (as a raw bytestream) from the received HTTP response
|
||||
```hurl
|
||||
GET https://example.org/data.bin
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
my_data: bytes
|
||||
```
|
||||
@ -174,14 +176,14 @@ Currently, only XPath 1.0 expression can be used.
|
||||
GET https://example.org/home
|
||||
|
||||
# Capture the identifier from the dom node <div id="pet0">5646eaf23</div
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
ped-id: xpath "normalize-space(//div[@id='pet0'])"
|
||||
|
||||
# Open the captured page.
|
||||
GET https://example.org/home/pets/{{pet-id}}
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
XPath captures are not limited to node values (like string, or boolean); any
|
||||
@ -190,7 +192,8 @@ 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
|
||||
|
||||
HTTP 200
|
||||
[Captures]
|
||||
pets: xpath "//pets"
|
||||
[Asserts]
|
||||
@ -208,7 +211,7 @@ POST https://example.org/api/contact
|
||||
token: {{token}}
|
||||
email: toto@rookie.net
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
contact-id: jsonpath "$['id']"
|
||||
```
|
||||
@ -241,7 +244,7 @@ We can capture the following paths:
|
||||
```hurl
|
||||
GET https://example.org/captures-json
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
an_object: jsonpath "$['an_object']"
|
||||
a_list: jsonpath "$['a_list']"
|
||||
@ -261,16 +264,17 @@ Capture a regex pattern from the HTTP received body, decoded as text.
|
||||
```hurl
|
||||
GET https://example.org/helloworld
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
id_a: regex "id_a:([0-9]+)!"
|
||||
id_b: regex "id_b:(\\d+)!"
|
||||
name: regex "Hello ([a-zA-Z]+)!"
|
||||
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]+)"
|
||||
```
|
||||
|
||||
Pattern of the regex query must have at least one capture group, otherwise the
|
||||
capture will fail. Metacharacters beginning with a backslash in the pattern
|
||||
(like `\d`, `\s`) must be escaped: `regex "(\\d+)!"` will capture one or more digit.
|
||||
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.
|
||||
|
||||
|
||||
### Variable capture
|
||||
@ -280,10 +284,10 @@ Capture the value of a variable into another.
|
||||
```hurl
|
||||
GET https://example.org/helloworld
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
in: body
|
||||
name: variable "in" regex "Hello ([a-zA-Z]+)!"
|
||||
name: variable "in"
|
||||
```
|
||||
|
||||
### Duration capture
|
||||
@ -293,60 +297,19 @@ Capture the response time of the request in ms.
|
||||
```hurl
|
||||
GET https://example.org/helloworld
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
duration_in_ms: duration
|
||||
|
||||
```
|
||||
|
||||
## Filters
|
||||
|
||||
Optionally, query can be refined using filters `count` and `regex`.
|
||||
|
||||
<div class="schema-container u-font-size-0 u-font-size-1-sm u-font-size-3-md">
|
||||
<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>
|
||||
<span class="schema-token">regex "(\\d+)"<span class="schema-label">filter (optional)</span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
### Count filter
|
||||
|
||||
Returns the count of a collection.
|
||||
|
||||
```hurl
|
||||
GET https://pets.org/cats/cutest
|
||||
|
||||
HTTP/1.0 200
|
||||
[Captures]
|
||||
cats_size: jsonpath "$.cats" count
|
||||
```
|
||||
|
||||
### Regex filter
|
||||
|
||||
```hurl
|
||||
GET https://pets.org/cats/cutest
|
||||
|
||||
HTTP/1.0 200
|
||||
# Cat name are structured like this `meow + id`: for instance `meow123456`
|
||||
[Captures]
|
||||
id: jsonpath "$.cats[0].name" regex "meow(\\d+)"
|
||||
```
|
||||
|
||||
Pattern of the regex filter must have at least one capture group, otherwise the
|
||||
capture will fail. Metacharacters beginning with a backslash in the pattern
|
||||
(like `\d`, `\s`) must be escaped: `regex "(\\d+)!"` will capture one or more digit.
|
||||
|
||||
|
||||
[CSRF tokens]: https://en.wikipedia.org/wiki/Cross-site_request_forgery
|
||||
[variable values]: /docs/manual.md#variable
|
||||
[templates]: /docs/templates.md
|
||||
[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
|
||||
[`--location` option]: /docs/manual.md#location
|
||||
[filters]: /docs/filters.md
|
@ -13,22 +13,21 @@ to [capture values] to perform subsequent requests, or [add asserts to HTTP resp
|
||||
# First, test home title.
|
||||
GET https://acmecorp.net
|
||||
|
||||
HTTP/1.1 200
|
||||
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
|
||||
# Do a POST request without CSRF token and check
|
||||
# that status code is Forbidden 403
|
||||
POST https://acmecorp.net/contact
|
||||
[FormParams]
|
||||
default: false
|
||||
email: john.doe@rookie.org
|
||||
number: 33611223344
|
||||
|
||||
HTTP/1.1 403
|
||||
HTTP 403
|
||||
```
|
||||
|
||||
## Description
|
||||
@ -42,24 +41,24 @@ every entry of a given file will follow redirection:
|
||||
$ hurl --location foo.hurl
|
||||
```
|
||||
|
||||
You can use an [`[Options]` section] to use option only for a specified option. For instance, in this Hurl file:
|
||||
You can use an [`[Options]` section][options] to use option only for a specified option. For instance, in this Hurl file:
|
||||
|
||||
```hurl
|
||||
GET https://google.fr
|
||||
HTTP/* 301
|
||||
HTTP 301
|
||||
|
||||
GET https://google.fr
|
||||
[Options]
|
||||
location: true
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
|
||||
GET https://google.fr
|
||||
HTTP/* 301
|
||||
HTTP 301
|
||||
```
|
||||
|
||||
The second entry will follow location (and so we can test the status code to be 200 instead of 301).
|
||||
The second entry will follow location (so we can test the status code to be 200 instead of 301).
|
||||
|
||||
You can use it to logs a specific entry:
|
||||
You can use it to log a specific entry:
|
||||
|
||||
```hurl
|
||||
# ... previous entries
|
||||
@ -67,8 +66,7 @@ You can use it to logs a specific entry:
|
||||
GET https://api.example.org
|
||||
[Options]
|
||||
very-verbose: true
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
|
||||
# ... next entries
|
||||
```
|
||||
@ -83,17 +81,15 @@ By default, Hurl doesn't follow redirection. To effectively run a redirection, e
|
||||
of the redirection, allowing insertion of asserts in each response.
|
||||
|
||||
```hurl
|
||||
# First entry, test the redirection (status code and
|
||||
# Location header)
|
||||
# First entry, test the redirection (status code and 'Location' header)
|
||||
GET https://google.fr
|
||||
|
||||
HTTP/1.1 301
|
||||
HTTP 301
|
||||
Location: https://www.google.fr/
|
||||
|
||||
# Second entry, the 200 OK response
|
||||
GET https://www.google.fr
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
Alternatively, one can use [`--location`] option to force redirection
|
||||
@ -103,7 +99,7 @@ redirections can be limited with [`--max-redirs`].
|
||||
```hurl
|
||||
# Running hurl --location google.hurl
|
||||
GET https://google.fr
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
Finally, you can force redirection on a particular request with an [`[Options]` section][options] and the [`--location` option]:
|
||||
@ -112,7 +108,7 @@ Finally, you can force redirection on a particular request with an [`[Options]`
|
||||
GET https://google.fr
|
||||
[Options]
|
||||
location: true
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
### Retry
|
||||
@ -129,7 +125,7 @@ For example, in this Hurl file, first we create a new job, then we poll the new
|
||||
# Create a new job
|
||||
POST http://api.example.org/jobs
|
||||
|
||||
HTTP/* 201
|
||||
HTTP 201
|
||||
[Captures]
|
||||
job_id: jsonpath "$.id"
|
||||
[Asserts]
|
||||
@ -141,7 +137,7 @@ GET http://api.example.org/jobs/{{job_id}}
|
||||
[Options]
|
||||
retry: true
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.state" == "COMPLETED"
|
||||
```
|
||||
@ -154,7 +150,7 @@ jsonpath "$.state" == "COMPLETED"
|
||||
[`--location`]: /docs/manual.md#location
|
||||
[`--max-redirs`]: /docs/manual.md#max-redirs
|
||||
[Options]: /docs/manual.md#options
|
||||
[options]: /docs/manual.md#options
|
||||
[options]: /docs/request.md#options
|
||||
[`--location` option]: /docs/manual.md#location
|
||||
[headers]: /docs/response.md#headers
|
||||
[status code]: /docs/response.md#version-status
|
||||
|
189
docs/filters.md
Normal file
189
docs/filters.md
Normal file
@ -0,0 +1,189 @@
|
||||
# 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-informations (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" replace /\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
|
||||
|
||||
### count
|
||||
|
||||
Counts the number of items in a collection.
|
||||
|
||||
```hurl
|
||||
GET https://example.org/api
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.books" count == 12
|
||||
```
|
||||
|
||||
### htmlEscape
|
||||
|
||||
Converts the characters `&`, `<` and `>` to HTML-safe sequence.
|
||||
|
||||
```hurl
|
||||
GET https://example.org/api
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.text" htmlEscape == "a > b"
|
||||
```
|
||||
|
||||
### htmlUnescape
|
||||
|
||||
Converts all named and numeric character references (e.g. `>`, `>`, `>`) to the corresponding Unicode characters.
|
||||
|
||||
```hurl
|
||||
GET https://example.org/api
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.escaped_html[1]" htmlUnescape == "Foo © bar 𝌆"
|
||||
```
|
||||
|
||||
### nth
|
||||
|
||||
Returns the element from a collection at a zero-based index.
|
||||
|
||||
```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 (.*)!/
|
||||
```
|
||||
|
||||
### 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"
|
||||
```
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
### toInt
|
||||
|
||||
Converts to integer number.
|
||||
|
||||
```hurl
|
||||
GET https://example.org/foo
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.id" toInt == 123
|
||||
```
|
||||
|
||||
### 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]) with the exception of 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"
|
||||
```
|
||||
|
||||
[Captures]: /docs/capturing-response.md
|
||||
[asserts]: /docs/asserting-response.md
|
||||
[RFC3986]: https://www.rfc-editor.org/rfc/rfc3986
|
39
docs/home.md
39
docs/home.md
@ -10,21 +10,24 @@
|
||||
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 <b>fetching data</b>, <b>testing HTTP</b> sessions and testing <b>XML / JSON APIs</b>.
|
||||
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
|
||||
# Get home:
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
|
||||
|
||||
|
||||
# Do login!
|
||||
POST https://example.org/login?user=toto&password=1234
|
||||
X-CSRF-TOKEN: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
```
|
||||
|
||||
Chaining multiple requests is easy:
|
||||
@ -53,7 +56,7 @@ POST https://example.org/api/tests
|
||||
"evaluate": true
|
||||
}
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "X-Frame-Options" == "SAMEORIGIN"
|
||||
jsonpath "$.status" == "RUNNING" # Check the status code
|
||||
@ -66,12 +69,27 @@ jsonpath "$.id" matches /\d{4}/ # Check the format of the id
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "normalize-space(//head/title)" == "Hello world!"
|
||||
```
|
||||
|
||||
and even SOAP APIs
|
||||
<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
|
||||
@ -86,8 +104,7 @@ SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
|
||||
</m:GetStockPrice>
|
||||
</soap:Body>
|
||||
</soap:Envelope>
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
Hurl can also be used to performance test HTTP endpoints:
|
||||
@ -95,7 +112,7 @@ Hurl can also be used to performance test HTTP endpoints:
|
||||
```hurl
|
||||
GET https://example.org/api/v1/pets
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
duration < 1000 # Duration in ms
|
||||
```
|
||||
@ -105,7 +122,7 @@ And response bytes
|
||||
```hurl
|
||||
GET https://example.org/data.tar.gz
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
|
||||
```
|
||||
@ -136,7 +153,7 @@ POST https://hurl.dev/api/feedback
|
||||
"name": "John Doe",
|
||||
"feedback": "Hurl is awesome !"
|
||||
}
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
# Resources
|
||||
|
@ -20,7 +20,7 @@ a documentation for HTTP based workflows so it can be useful to be very descript
|
||||
GET https://www.sample.net
|
||||
x-app: MY_APP # Add a dummy header
|
||||
|
||||
HTTP/1.1 302 # Check that we have a redirection
|
||||
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
|
||||
@ -37,8 +37,7 @@ String can include the following special characters:
|
||||
```hurl
|
||||
GET https://example.org/api
|
||||
|
||||
HTTP/1.1 200
|
||||
|
||||
HTTP 200
|
||||
# The following assert are equivalent:
|
||||
[Asserts]
|
||||
jsonpath "$.slideshow.title" == "A beautiful ✈!"
|
||||
@ -51,7 +50,7 @@ In the following example:
|
||||
```hurl
|
||||
GET https://example.org/api
|
||||
x-token: BEEF \#STEACK # Some comment
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
We're sending a header `x-token` with value `BEEF #STEACK`
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
### Linux
|
||||
|
||||
Precompiled binary is available at [hurl-1.8.0-x86_64-linux.tar.gz]:
|
||||
Precompiled binary is available at [hurl-2.0.0-x86_64-linux.tar.gz]:
|
||||
|
||||
```shell
|
||||
$ INSTALL_DIR=/tmp
|
||||
$ curl -sL https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-x86_64-linux.tar.gz | tar xvz -C $INSTALL_DIR
|
||||
$ export PATH=$INSTALL_DIR/hurl-1.8.0:$PATH
|
||||
$ curl -sL https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-x86_64-linux.tar.gz | tar xvz -C $INSTALL_DIR
|
||||
$ export PATH=$INSTALL_DIR/hurl-2.0.0:$PATH
|
||||
```
|
||||
|
||||
#### Debian / Ubuntu
|
||||
@ -17,8 +17,8 @@ $ export PATH=$INSTALL_DIR/hurl-1.8.0:$PATH
|
||||
For Debian / Ubuntu, Hurl can be installed using a binary .deb file provided in each Hurl release.
|
||||
|
||||
```shell
|
||||
$ curl -LO https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl_1.8.0_amd64.deb
|
||||
$ sudo apt update && apt install ./hurl_1.8.0_amd64.deb
|
||||
$ curl -LO https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl_2.0.0_amd64.deb
|
||||
$ sudo apt update && apt install ./hurl_2.0.0_amd64.deb
|
||||
```
|
||||
|
||||
#### Arch Linux / Manjaro
|
||||
@ -31,7 +31,7 @@ $ sudo apt update && apt install ./hurl_1.8.0_amd64.deb
|
||||
|
||||
### macOS
|
||||
|
||||
Precompiled binary is available at [hurl-1.8.0-x86_64-macos.tar.gz] for x86 CPUs and [hurl-1.8.0-arm64-macos.tar.gz] for ARM CPUS.
|
||||
Precompiled binary is available at [hurl-2.0.0-x86_64-macos.tar.gz] for x86 CPUs and [hurl-2.0.0-arm64-macos.tar.gz] for ARM CPUS.
|
||||
|
||||
#### Homebrew
|
||||
|
||||
@ -55,11 +55,11 @@ $ sudo pkg install hurl
|
||||
|
||||
#### Zip File
|
||||
|
||||
Hurl can be installed from a standalone zip file [hurl-1.8.0-win64.zip]. You will need to update your `PATH` variable.
|
||||
Hurl can be installed from a standalone zip file [hurl-2.0.0-win64.zip]. You will need to update your `PATH` variable.
|
||||
|
||||
#### Installer
|
||||
|
||||
An installer [hurl-1.8.0-win64-installer.exe] is also available.
|
||||
An installer [hurl-2.0.0-win64-installer.exe] is also available.
|
||||
|
||||
#### Chocolatey
|
||||
|
||||
@ -156,11 +156,11 @@ $ ./target/release/hurl --version
|
||||
Please follow the [contrib on Windows section].
|
||||
|
||||
[GitHub]: https://github.com/Orange-OpenSource/hurl
|
||||
[hurl-1.8.0-win64.zip]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-win64.zip
|
||||
[hurl-1.8.0-win64-installer.exe]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-win64-installer.exe
|
||||
[hurl-1.8.0-x86_64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-x86_64-macos.tar.gz
|
||||
[hurl-1.8.0-arm64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-arm64-macos.tar.gz
|
||||
[hurl-1.8.0-x86_64-linux.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-x86_64-linux.tar.gz
|
||||
[hurl-2.0.0-win64.zip]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-win64.zip
|
||||
[hurl-2.0.0-win64-installer.exe]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-win64-installer.exe
|
||||
[hurl-2.0.0-x86_64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-x86_64-macos.tar.gz
|
||||
[hurl-2.0.0-arm64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-arm64-macos.tar.gz
|
||||
[hurl-2.0.0-x86_64-linux.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-x86_64-linux.tar.gz
|
||||
[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
|
||||
|
145
docs/manual.md
145
docs/manual.md
@ -12,9 +12,9 @@ hurl - run and test HTTP requests.
|
||||
|
||||
## Description
|
||||
|
||||
**Hurl** is an HTTP client that performs HTTP requests defined in a simple plain text format.
|
||||
**Hurl** is a command line tool that runs 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.
|
||||
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
|
||||
@ -71,11 +71,11 @@ GET http:/example.org/endpoint2
|
||||
|
||||
A value from an HTTP response can be-reused for successive HTTP requests.
|
||||
|
||||
A typical example occurs with csrf tokens.
|
||||
A typical example occurs with CSRF tokens.
|
||||
|
||||
```hurl
|
||||
GET https://example.org
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
# Capture the CSRF token value from html body.
|
||||
[Captures]
|
||||
csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"
|
||||
@ -89,28 +89,28 @@ More information on captures can be found here [https://hurl.dev/docs/capturing-
|
||||
|
||||
### Asserts
|
||||
|
||||
The HTTP response defined in the Hurl session are used to make asserts.
|
||||
The HTTP response defined in the Hurl file are used to make asserts. Responses are optional.
|
||||
|
||||
At the minimum, the response includes the asserts on the HTTP version and status code.
|
||||
At the minimum, response includes assert on the HTTP status code.
|
||||
|
||||
```hurl
|
||||
GET http:/google.com
|
||||
HTTP/1.1 301
|
||||
GET http:/example.org
|
||||
HTTP 301
|
||||
```
|
||||
|
||||
It can also include asserts on the response headers
|
||||
|
||||
```hurl
|
||||
GET http:/google.com
|
||||
HTTP/1.1 301
|
||||
Location: http://www.google.com
|
||||
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:/google.com
|
||||
HTTP/1.1 301
|
||||
GET http:/example.org
|
||||
HTTP 301
|
||||
[Asserts]
|
||||
xpath "string(//title)" == "301 Moved"
|
||||
```
|
||||
@ -134,56 +134,61 @@ $ 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://google.com
|
||||
HTTP/* 301
|
||||
GET https://example.org
|
||||
HTTP 301
|
||||
|
||||
GET https://google.com
|
||||
GET https://example.org
|
||||
[Options]
|
||||
location: true
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
will follow a redirection only for the second entry.
|
||||
|
||||
Option | Description
|
||||
--- | ---
|
||||
<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/>
|
||||
<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/>
|
||||
<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/>See also [`-m, --max-time`](#max-time) option.<br/>
|
||||
<a href="#cookie" id="cookie"><code>-b, --cookie <FILE></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 <FILE></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/>
|
||||
<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/>
|
||||
<a href="#file-root" id="file-root"><code>--file-root <DIR></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/>
|
||||
<a href="#glob" id="glob"><code>--glob <GLOB></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/>
|
||||
<a href="#include" id="include"><code>-i, --include</code></a> | Include the HTTP headers in the output (last entry).<br/>
|
||||
<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/>
|
||||
<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/>
|
||||
<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/>
|
||||
<a href="#max-redirs" id="max-redirs"><code>--max-redirs <NUM></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 <SECONDS></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/>
|
||||
<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/>
|
||||
<a href="#noproxy" id="noproxy"><code>--noproxy <HOST(S)></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 <FILE></code></a> | Write output to FILE instead of stdout.<br/>
|
||||
<a href="#proxy" id="proxy"><code>-x, --proxy [protocol://]host[:port]</code></a> | Use the specified proxy.<br/>
|
||||
<a href="#report-junit" id="report-junit"><code>--report-junit <FILE></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 <DIR></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 <MILLISECONDS></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 <NUM></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/>
|
||||
<a href="#to-entry" id="to-entry"><code>--to-entry <ENTRY_NUMBER></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 <USER:PASSWORD></code></a> | Add basic Authentication header to each request.<br/>
|
||||
<a href="#user-agent" id="user-agent"><code>-A, --user-agent <NAME></code></a> | Specify the User-Agent string to send to the HTTP server.<br/>
|
||||
<a href="#variable" id="variable"><code>--variable <NAME=VALUE></code></a> | Define variable (name/value) to be used in Hurl templates.<br/>
|
||||
<a href="#variables-file" id="variables-file"><code>--variables-file <FILE></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/>
|
||||
<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/>
|
||||
| Option | Description |
|
||||
|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| <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 [`--key`](#key).<br> |
|
||||
| <a href="#color" id="color"><code>--color</code></a> | Colorize Output.<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> |
|
||||
| <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>See also [`-m, --max-time`](#max-time).<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 [`--resolve`](#resolve).<br> |
|
||||
| <a href="#cookie" id="cookie"><code>-b, --cookie <FILE></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 <FILE></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> |
|
||||
| <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> |
|
||||
| <a href="#file-root" id="file-root"><code>--file-root <DIR></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> |
|
||||
| <a href="#glob" id="glob"><code>--glob <GLOB></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> |
|
||||
| <a href="#include" id="include"><code>-i, --include</code></a> | Include the HTTP headers in the output (last entry).<br> |
|
||||
| <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> |
|
||||
| <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> |
|
||||
| <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> |
|
||||
| <a href="#key" id="key"><code>--key <KEY></code></a> | Private key file name.<br> |
|
||||
| <a href="#max-redirs" id="max-redirs"><code>--max-redirs <NUM></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 <SECONDS></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).<br> |
|
||||
| <a href="#no-color" id="no-color"><code>--no-color</code></a> | Do not colorize output.<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> |
|
||||
| <a href="#noproxy" id="noproxy"><code>--noproxy <HOST(S)></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 <FILE></code></a> | Write output to FILE instead of stdout.<br> |
|
||||
| <a href="#proxy" id="proxy"><code>-x, --proxy <[PROTOCOL://]HOST[:PORT]></code></a> | Use the specified proxy.<br> |
|
||||
| <a href="#report-junit" id="report-junit"><code>--report-junit <FILE></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 <DIR></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="#resolve" id="resolve"><code>--resolve <HOST:PORT:ADDR></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="#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 <MILLISECONDS></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 <NUM></code></a> | Maximum number of retries. Set this option to -1 to make it unlimited. Default is 10.<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> |
|
||||
| <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> |
|
||||
| <a href="#to-entry" id="to-entry"><code>--to-entry <ENTRY_NUMBER></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 <USER:PASSWORD></code></a> | Add basic Authentication header to each request.<br> |
|
||||
| <a href="#user-agent" id="user-agent"><code>-A, --user-agent <NAME></code></a> | Specify the User-Agent string to send to the HTTP server.<br> |
|
||||
| <a href="#variable" id="variable"><code>--variable <NAME=VALUE></code></a> | Define variable (name/value) to be used in Hurl templates.<br> |
|
||||
| <a href="#variables-file" id="variables-file"><code>--variables-file <FILE></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> |
|
||||
| <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> |
|
||||
|
||||
## Environment
|
||||
|
||||
@ -191,23 +196,23 @@ Environment variables can only be specified in lowercase.
|
||||
|
||||
Using an environment variable to set the proxy has the same effect as using the [`-x, --proxy`](#proxy) option.
|
||||
|
||||
Variable | Description
|
||||
--- | ---
|
||||
`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/>
|
||||
`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/>
|
||||
| Variable | Description |
|
||||
|--------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `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> |
|
||||
| `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> |
|
||||
|
||||
## Exit Codes
|
||||
|
||||
Value | Description
|
||||
--- | ---
|
||||
`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/>
|
||||
| Value | Description |
|
||||
|-------|---------------------------------------------------------|
|
||||
| `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
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
.TH hurl 1 "07 Nov 2022" "hurl 2.0.0-SNAPSHOT" " Hurl Manual"
|
||||
.TH hurl 1 "24 Jan 2023" "hurl 2.0.0-SNAPSHOT" " Hurl Manual"
|
||||
.SH NAME
|
||||
|
||||
hurl - run and test HTTP requests.
|
||||
@ -13,9 +13,9 @@ hurl - run and test HTTP requests.
|
||||
.SH DESCRIPTION
|
||||
|
||||
.B Hurl
|
||||
is an HTTP client that performs HTTP requests defined in a simple plain text format.
|
||||
is a command line tool that runs 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.
|
||||
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
|
||||
|
||||
@ -62,10 +62,10 @@ It consists of one or several HTTP requests
|
||||
|
||||
A value from an HTTP response can be-reused for successive HTTP requests.
|
||||
|
||||
A typical example occurs with csrf tokens.
|
||||
A typical example occurs with CSRF tokens.
|
||||
|
||||
GET https://example.org
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
# Capture the CSRF token value from html body.
|
||||
[Captures]
|
||||
csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"
|
||||
@ -78,23 +78,23 @@ More information on captures can be found here \fIhttps://hurl.dev/docs/capturin
|
||||
|
||||
.IP "Asserts"
|
||||
|
||||
The HTTP response defined in the Hurl session are used to make asserts.
|
||||
The HTTP response defined in the Hurl file are used to make asserts. Responses are optional.
|
||||
|
||||
At the minimum, the response includes the asserts on the HTTP version and status code.
|
||||
At the minimum, response includes assert on the HTTP status code.
|
||||
|
||||
GET http:/google.com
|
||||
HTTP/1.1 301
|
||||
GET http:/example.org
|
||||
HTTP 301
|
||||
|
||||
It can also include asserts on the response headers
|
||||
|
||||
GET http:/google.com
|
||||
HTTP/1.1 301
|
||||
Location: http://www.google.com
|
||||
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:/google.com
|
||||
HTTP/1.1 301
|
||||
GET http:/example.org
|
||||
HTTP 301
|
||||
[Asserts]
|
||||
xpath "string(//title)" == "301 Moved"
|
||||
|
||||
@ -114,21 +114,27 @@ For instance:
|
||||
|
||||
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://google.com
|
||||
HTTP/* 301
|
||||
GET https://example.org
|
||||
HTTP 301
|
||||
|
||||
GET https://google.com
|
||||
GET https://example.org
|
||||
[Options]
|
||||
location: true
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
|
||||
will follow a redirection only for the second entry.
|
||||
|
||||
.IP "--cacert "
|
||||
.IP "--cacert <FILE> "
|
||||
|
||||
Specifies the certificate file for peer verification. The file may contain multiple CA certificates and must be in PEM format.
|
||||
Normally Hurl is built to use a default file for this, so this option is typically used to alter that default file.
|
||||
|
||||
.IP "-E, --cert <CERTIFICATE[:PASSWORD]> "
|
||||
|
||||
Client certificate file and password.
|
||||
|
||||
See also \fI--key\fP.
|
||||
|
||||
.IP "--color "
|
||||
|
||||
Colorize Output.
|
||||
@ -141,7 +147,13 @@ Request a compressed response using one of the algorithms br, gzip, deflate and
|
||||
|
||||
Maximum time in seconds that you allow Hurl's connection to take.
|
||||
|
||||
See also \fI-m, --max-time\fP option.
|
||||
See also \fI-m, --max-time\fP.
|
||||
|
||||
.IP "--connect-to <HOST1:PORT1:HOST2:PORT2> "
|
||||
|
||||
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.
|
||||
|
||||
See also \fI--resolve\fP.
|
||||
|
||||
.IP "-b, --cookie <FILE> "
|
||||
|
||||
@ -202,6 +214,10 @@ This is similar to a break point, You can then continue (Press C) or quit (Press
|
||||
|
||||
Output each hurl file result to JSON. The format is very closed to HAR format.
|
||||
|
||||
.IP "--key <KEY> "
|
||||
|
||||
Private key file name.
|
||||
|
||||
.IP "--max-redirs <NUM> "
|
||||
|
||||
Set maximum number of redirection-followings allowed
|
||||
@ -211,7 +227,7 @@ By default, the limit is set to 50 redirections. Set this option to -1 to make i
|
||||
|
||||
Maximum time in seconds that you allow a request/response to take. This is the standard timeout.
|
||||
|
||||
See also \fI--connect-timeout\fP option.
|
||||
See also \fI--connect-timeout\fP.
|
||||
|
||||
.IP "--no-color "
|
||||
|
||||
@ -230,7 +246,7 @@ Override value from Environment variable no_proxy.
|
||||
|
||||
Write output to FILE instead of stdout.
|
||||
|
||||
.IP "-x, --proxy [protocol://]host[:port] "
|
||||
.IP "-x, --proxy <[PROTOCOL://]HOST[:PORT]> "
|
||||
|
||||
Use the specified proxy.
|
||||
|
||||
@ -246,6 +262,10 @@ Generate HTML report in DIR.
|
||||
|
||||
If the HTML report already exists, it will be updated with the new test results.
|
||||
|
||||
.IP "--resolve <HOST:PORT:ADDR> <HOST:PORT:ADDR>"
|
||||
|
||||
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.
|
||||
|
||||
.IP "--retry "
|
||||
|
||||
Retry requests if any error occurs (asserts, captures, runtimes etc...).
|
||||
@ -258,6 +278,10 @@ Duration in milliseconds between each retry. Default is 1000 ms.
|
||||
|
||||
Maximum number of retries. Set this option to -1 to make it unlimited. Default is 10.
|
||||
|
||||
.IP "--ssl-no-revoke "
|
||||
|
||||
(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.
|
||||
|
||||
.IP "--test "
|
||||
|
||||
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.
|
||||
|
@ -10,9 +10,9 @@ hurl - run and test HTTP requests.
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
**Hurl** is an HTTP client that performs HTTP requests defined in a simple plain text format.
|
||||
**Hurl** is a command line tool that runs 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.
|
||||
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
|
||||
@ -69,11 +69,11 @@ GET http:/example.org/endpoint2
|
||||
|
||||
A value from an HTTP response can be-reused for successive HTTP requests.
|
||||
|
||||
A typical example occurs with csrf tokens.
|
||||
A typical example occurs with CSRF tokens.
|
||||
|
||||
```hurl
|
||||
GET https://example.org
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
# Capture the CSRF token value from html body.
|
||||
[Captures]
|
||||
csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"
|
||||
@ -87,28 +87,28 @@ More information on captures can be found here [https://hurl.dev/docs/capturing-
|
||||
|
||||
### Asserts
|
||||
|
||||
The HTTP response defined in the Hurl session are used to make asserts.
|
||||
The HTTP response defined in the Hurl file are used to make asserts. Responses are optional.
|
||||
|
||||
At the minimum, the response includes the asserts on the HTTP version and status code.
|
||||
At the minimum, response includes assert on the HTTP status code.
|
||||
|
||||
```hurl
|
||||
GET http:/google.com
|
||||
HTTP/1.1 301
|
||||
GET http:/example.org
|
||||
HTTP 301
|
||||
```
|
||||
|
||||
It can also include asserts on the response headers
|
||||
|
||||
```hurl
|
||||
GET http:/google.com
|
||||
HTTP/1.1 301
|
||||
Location: http://www.google.com
|
||||
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:/google.com
|
||||
HTTP/1.1 301
|
||||
GET http:/example.org
|
||||
HTTP 301
|
||||
[Asserts]
|
||||
xpath "string(//title)" == "301 Moved"
|
||||
```
|
||||
@ -132,22 +132,28 @@ $ 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://google.com
|
||||
HTTP/* 301
|
||||
GET https://example.org
|
||||
HTTP 301
|
||||
|
||||
GET https://google.com
|
||||
GET https://example.org
|
||||
[Options]
|
||||
location: true
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
will follow a redirection only for the second entry.
|
||||
|
||||
### --cacert {#cacert}
|
||||
### --cacert <FILE> {#cacert}
|
||||
|
||||
Specifies the certificate file for peer verification. The file may contain multiple CA certificates and must be in PEM format.
|
||||
Normally Hurl is built to use a default file for this, so this option is typically used to alter that default file.
|
||||
|
||||
### -E, --cert <CERTIFICATE[:PASSWORD]> {#cert}
|
||||
|
||||
Client certificate file and password.
|
||||
|
||||
See also [`--key`](#key).
|
||||
|
||||
### --color {#color}
|
||||
|
||||
Colorize Output.
|
||||
@ -160,7 +166,13 @@ Request a compressed response using one of the algorithms br, gzip, deflate and
|
||||
|
||||
Maximum time in seconds that you allow Hurl's connection to take.
|
||||
|
||||
See also [`-m, --max-time`](#max-time) option.
|
||||
See also [`-m, --max-time`](#max-time).
|
||||
|
||||
### --connect-to <HOST1:PORT1:HOST2:PORT2> {#connect-to}
|
||||
|
||||
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.
|
||||
|
||||
See also [`--resolve`](#resolve).
|
||||
|
||||
### -b, --cookie <FILE> {#cookie}
|
||||
|
||||
@ -221,6 +233,10 @@ This is similar to a break point, You can then continue (Press C) or quit (Press
|
||||
|
||||
Output each hurl file result to JSON. The format is very closed to HAR format.
|
||||
|
||||
### --key <KEY> {#key}
|
||||
|
||||
Private key file name.
|
||||
|
||||
### --max-redirs <NUM> {#max-redirs}
|
||||
|
||||
Set maximum number of redirection-followings allowed
|
||||
@ -230,7 +246,7 @@ By default, the limit is set to 50 redirections. Set this option to -1 to make i
|
||||
|
||||
Maximum time in seconds that you allow a request/response to take. This is the standard timeout.
|
||||
|
||||
See also [`--connect-timeout`](#connect-timeout) option.
|
||||
See also [`--connect-timeout`](#connect-timeout).
|
||||
|
||||
### --no-color {#no-color}
|
||||
|
||||
@ -249,7 +265,7 @@ Override value from Environment variable no_proxy.
|
||||
|
||||
Write output to FILE instead of stdout.
|
||||
|
||||
### -x, --proxy [protocol://]host[:port] {#proxy}
|
||||
### -x, --proxy <[PROTOCOL://]HOST[:PORT]> {#proxy}
|
||||
|
||||
Use the specified proxy.
|
||||
|
||||
@ -265,6 +281,10 @@ Generate HTML report in DIR.
|
||||
|
||||
If the HTML report already exists, it will be updated with the new test results.
|
||||
|
||||
### --resolve <HOST:PORT:ADDR> {#resolve} <HOST:PORT:ADDR>
|
||||
|
||||
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.
|
||||
|
||||
### --retry {#retry}
|
||||
|
||||
Retry requests if any error occurs (asserts, captures, runtimes etc...).
|
||||
@ -277,6 +297,10 @@ Duration in milliseconds between each retry. Default is 1000 ms.
|
||||
|
||||
Maximum number of retries. Set this option to -1 to make it unlimited. Default is 10.
|
||||
|
||||
### --ssl-no-revoke {#ssl-no-revoke}
|
||||
|
||||
(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.
|
||||
|
||||
### --test {#test}
|
||||
|
||||
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.
|
||||
|
@ -1,4 +1,4 @@
|
||||
.TH hurl 1 "07 Nov 2022" "hurl 2.0.0-SNAPSHOT" " Hurl Manual"
|
||||
.TH hurl 1 "24 Jan 2023" "hurl 2.0.0-SNAPSHOT" " Hurl Manual"
|
||||
.SH NAME
|
||||
|
||||
hurlfmt - format Hurl files
|
||||
|
182
docs/request.md
182
docs/request.md
@ -4,8 +4,8 @@
|
||||
|
||||
Request describes an HTTP request: a mandatory [method] and [URL], followed by optional [headers].
|
||||
|
||||
Then, [query parameters], [form parameters], [multipart form data], [cookies] and
|
||||
[basic authentication] can be used to configure the HTTP request.
|
||||
Then, [query parameters], [form parameters], [multipart form data], [cookies], [basic authentication] and [options]
|
||||
can be used to configure the HTTP request.
|
||||
|
||||
Finally, an optional [body] can be used to configure the HTTP request body.
|
||||
|
||||
@ -116,7 +116,7 @@ order: newest
|
||||
```
|
||||
|
||||
The last optional part of a request configuration is the request [body]. Request body must be the last parameter of a request
|
||||
(after [headers] and request sections). Like headers, [body] have no explicit marker:
|
||||
(after [headers] and request sections). Like headers, body have no explicit marker:
|
||||
|
||||
```hurl
|
||||
POST https://example.org/api/dogs?id=4567
|
||||
@ -131,7 +131,7 @@ User-Agent: My User Agent
|
||||
### Method
|
||||
|
||||
Mandatory HTTP request method, one of `GET`, `HEAD`, `POST`, `PUT`, `DELETE`, `CONNECT`, `OPTIONS`,
|
||||
`TRACE`, `PATCH`.
|
||||
`TRACE`, `PATCH`, `LINK`, `UNLINK`, `PURGE`, `LOCK`, `UNLOCK`, `PROPFIND`, `VIEW`.
|
||||
|
||||
### URL
|
||||
|
||||
@ -173,7 +173,7 @@ Connection: keep-alive
|
||||
> Headers directly follow URL, without any section name, contrary to query parameters, form parameters
|
||||
> or cookies
|
||||
|
||||
Note that header usually don't start with double quotes. If the header value starts with double quotes, the double
|
||||
Note that a header usually doesn't start with double quotes. If a header value starts with double quotes, double
|
||||
quotes will be part of the header value:
|
||||
|
||||
```hurl
|
||||
@ -223,7 +223,7 @@ number: 33611223344
|
||||
```
|
||||
|
||||
Form parameters section can be seen as syntactic sugar over body section (values in form parameters section
|
||||
are not URL encoded.). A [multiline string body] could be used instead of a forms parameters section.
|
||||
are not URL encoded.). A [oneline string body] could be used instead of a forms parameters section.
|
||||
|
||||
~~~hurl
|
||||
# Run a POST request with form parameters section:
|
||||
@ -235,9 +235,7 @@ key1: value1
|
||||
# Run the same POST request with a body section:
|
||||
POST https://example.org/test
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
```
|
||||
name=John%20Doe&key1=value1
|
||||
```
|
||||
`name=John%20Doe&key1=value1`
|
||||
~~~
|
||||
|
||||
When both [body section] and form parameters section are present, only the body section is taken into account.
|
||||
@ -342,8 +340,9 @@ Optional HTTP body request.
|
||||
|
||||
If the body of the request is a [JSON] string or a [XML] string, the value can be
|
||||
directly inserted without any modification. For a text based body that is not JSON nor XML,
|
||||
one can use multiline string that starts with <code>```</code> and ends
|
||||
with <code>```</code>.
|
||||
one can use [multiline string body] that starts with <code>```</code> and ends
|
||||
with <code>```</code>. Multiline string body support "language hint" and can be used
|
||||
to create [GraphQL queries].
|
||||
|
||||
For a precise byte control of the request body, [Base64] encoded string, [hexadecimal string]
|
||||
or [included file] can be used to describe exactly the body byte content.
|
||||
@ -354,7 +353,7 @@ The body section must be the last section of the request configuration.
|
||||
|
||||
#### JSON body
|
||||
|
||||
JSON body is used to set a literal JSON as the request body.
|
||||
JSON request body is used to set a literal JSON as the request body.
|
||||
|
||||
```hurl
|
||||
# Create a new doggy thing with JSON body:
|
||||
@ -369,11 +368,43 @@ POST https://example.org/api/dogs
|
||||
}
|
||||
```
|
||||
|
||||
When using JSON body, the content type `application/json` is automatically set.
|
||||
JSON request body can be [templatized with variables]:
|
||||
|
||||
```hurl
|
||||
# Create a new catty thing with JSON body:
|
||||
POST https://example.org/api/cats
|
||||
{
|
||||
"id": 42,
|
||||
"lives": {{ lives_count }},
|
||||
"name": "{{ name }}"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
When using JSON request body, the content type `application/json` is automatically set.
|
||||
|
||||
JSON request body can be seen as syntactic sugar of [multiline string body] with `json` identifier:
|
||||
|
||||
~~~hurl
|
||||
# Create a new doggy thing with JSON body:
|
||||
POST https://example.org/api/dogs
|
||||
```json
|
||||
{
|
||||
"id": 0,
|
||||
"name": "Frieda",
|
||||
"picture": "images/scottish-terrier.jpeg",
|
||||
"age": 3,
|
||||
"breed": "Scottish Terrier",
|
||||
"location": "Lisco, Alabama"
|
||||
}
|
||||
```
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
#### XML body
|
||||
|
||||
XML body is used to set a literal XML as the request body.
|
||||
XML request body is used to set a literal XML as the request body.
|
||||
|
||||
~~~hurl
|
||||
# Create a new soapy thing XML body:
|
||||
@ -392,9 +423,88 @@ SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
|
||||
</soap:Envelope>
|
||||
~~~
|
||||
|
||||
XML request body can be seen as syntactic sugar of [multiline string body] with `xml` identifier:
|
||||
|
||||
~~~hurl
|
||||
# Create a new soapy thing XML body:
|
||||
POST https://example.org/InStock
|
||||
Content-Type: application/soap+xml; charset=utf-8
|
||||
Content-Length: 299
|
||||
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="http://example.net">
|
||||
<soap:Header></soap:Header>
|
||||
<soap:Body>
|
||||
<m:GetStockPrice>
|
||||
<m:StockName>GOOG</m:StockName>
|
||||
</m:GetStockPrice>
|
||||
</soap:Body>
|
||||
</soap:Envelope>
|
||||
```
|
||||
~~~
|
||||
|
||||
> Contrary to JSON body, the succint syntax of XML body can not use variables. If you need to use variables in your
|
||||
> XML body, use a simple [multiline string body] with variables.
|
||||
|
||||
#### GraphQL query
|
||||
|
||||
GraphQL query uses [multiline string body] with `graphql` identifier:
|
||||
|
||||
|
||||
~~~hurl
|
||||
POST https://example.org/starwars/graphql
|
||||
```graphql
|
||||
{
|
||||
human(id: "1000") {
|
||||
name
|
||||
height(unit: FOOT)
|
||||
}
|
||||
}
|
||||
```
|
||||
~~~
|
||||
|
||||
GraphQL query body can use [GraphQL 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 query, as every multiline string body, can use Hurl variables.
|
||||
|
||||
~~~hurl
|
||||
POST https://example.org/starwars/graphql
|
||||
```graphql
|
||||
{
|
||||
human(id: "{{human_id}}") {
|
||||
name
|
||||
height(unit: FOOT)
|
||||
}
|
||||
}
|
||||
```
|
||||
~~~
|
||||
|
||||
> Hurl variables and GraphQL variables can be mixed in the same body.
|
||||
|
||||
|
||||
#### Multiline string body
|
||||
|
||||
For text based body that are not JSON nor XML, one can used multiline string, started and ending with
|
||||
For text based body that are not JSON nor XML, one can use multiline string, started and ending with
|
||||
<code>```</code>.
|
||||
|
||||
~~~hurl
|
||||
@ -420,28 +530,28 @@ line3
|
||||
|
||||
is evaluated as "line1\nline2\nline3\n".
|
||||
|
||||
Multiline string body can use language identifier, like `json`, `xml` or `graphql`. Depending on the language identifier,
|
||||
an additional 'Content-Type' request header is sent, and the real body (bytes sent over the wire) can be different from the
|
||||
raw multiline text.
|
||||
|
||||
To construct an empty string:
|
||||
|
||||
~~~
|
||||
```
|
||||
~~~hurl
|
||||
POST https://example.org/api/dogs
|
||||
```json
|
||||
{
|
||||
"id": 0,
|
||||
"name": "Frieda",
|
||||
}
|
||||
```
|
||||
~~~
|
||||
|
||||
or
|
||||
#### Oneline string body
|
||||
|
||||
For text based body that do not contain newlines, one can use oneline string, started and ending with <code>`</code>.
|
||||
|
||||
~~~hurl
|
||||
POST https://example.org/helloworld
|
||||
`Hello world!`
|
||||
~~~
|
||||
``````
|
||||
~~~
|
||||
|
||||
|
||||
Finally, multiline string can be used without any newline:
|
||||
|
||||
~~~
|
||||
```line```
|
||||
~~~
|
||||
|
||||
is evaluated as "line".
|
||||
|
||||
|
||||
#### Base64 body
|
||||
@ -504,10 +614,15 @@ compressed: true # request a compressed response
|
||||
insecure: true # allows insecure SSL connections and transfers
|
||||
location: true # follow redirection for this request
|
||||
max-redirs: 10 # maximum number of redirections
|
||||
variable: country=Italy # define variable country
|
||||
variable: planet=Earth # define variable planet
|
||||
verbose: true # allow verbose output
|
||||
very-verbose: true # allow more verbose output
|
||||
```
|
||||
|
||||
> Variable defined in an `[Options]` section are defined also for the next entries. This is
|
||||
> the exception, all other options are defined only for the current request.
|
||||
|
||||
[method]: #method
|
||||
[URL]: #url
|
||||
[headers]: #headers
|
||||
@ -521,6 +636,7 @@ very-verbose: true # allow more verbose output
|
||||
[query parameters section]: #query-parameters
|
||||
[HTML form]: https://developer.mozilla.org/en-US/docs/Learn/Forms
|
||||
[multiline string body]: #multiline-string-body
|
||||
[oneline string body]: #oneline-string-body
|
||||
[body section]: #body
|
||||
[multipart/form-data on MDN]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
|
||||
[`--file-root` option]: /docs/manual.md#file-root
|
||||
@ -536,4 +652,8 @@ very-verbose: true # allow more verbose output
|
||||
[`--location`]: /docs/manual.md#location
|
||||
[`--verbose`]: /docs/manual.md#verbose
|
||||
[`--insecure`]: /docs/manual.md#insecure
|
||||
[templatized with variables]: /docs/templates.md#templating-body
|
||||
[GraphQL queries]: #graphql-query
|
||||
[GraphQL variables]: https://graphql.org/learn/queries/#variables
|
||||
[options]: #options
|
||||
|
||||
|
@ -15,7 +15,7 @@ in the following entries.
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
|
||||
[Asserts]
|
||||
xpath "normalize-space(//head/title)" startsWith "Welcome"
|
||||
@ -28,7 +28,7 @@ xpath "//li" count == 18
|
||||
<div class="hurl-structure">
|
||||
<div class="hurl-structure-col-0">
|
||||
<div class="hurl-part-0">
|
||||
HTTP/1.1 *
|
||||
HTTP *
|
||||
</div>
|
||||
<div class=" hurl-part-1">
|
||||
content-length: 206<br>accept-ranges: bytes<br>user-agent: Test
|
||||
|
@ -63,17 +63,25 @@ You can use [`--glob` option] to test files that match a given pattern:
|
||||
$ hurl --test --glob "test/integration/**/*.hurl"
|
||||
```
|
||||
|
||||
## Generating an HTML Report
|
||||
## Generating Report
|
||||
|
||||
Hurl can also generate an HTML report by using the [`--report-html HTML_DIR`] option.
|
||||
### HTML Report
|
||||
|
||||
Hurl can generate an HTML report by using the [`--report-html HTML_DIR`] option.
|
||||
|
||||
If the HTML report already exists, the test results will be appended to it.
|
||||
|
||||
<img src="/docs/assets/img/hurl-html-report.png" width="320" height="258" alt="Hurl HTML Report">
|
||||
<img src="/docs/assets/img/hurl-html-report.png" style="max-width:670px;width:100%" alt="Hurl HTML Report">
|
||||
|
||||
The input Hurl files (HTML version) are also included and are easily accessed from the main page.
|
||||
|
||||
<img src="/docs/assets/img/hurl-html-file.png" width="380" height="206" alt="Hurl HTML file">
|
||||
<img src="/docs/assets/img/hurl-html-file.png" style="max-width:380px;width:100%" alt="Hurl HTML file">
|
||||
|
||||
### JUnit Report
|
||||
|
||||
A JUnit report can be produced by using the [`--report-junit FILE`] option.
|
||||
|
||||
If the JUnit file already exists, it will be updated with the new test results.
|
||||
|
||||
|
||||
## Use Variables in Tests
|
||||
@ -89,6 +97,7 @@ You will find a detailed description in the [Injecting Variables] section of the
|
||||
[`--output /dev/null`]: /docs/manual.md#output
|
||||
[`--test`]: /docs/manual.md#test
|
||||
[`--report-html HTML_DIR`]: /docs/manual.md#report-html
|
||||
[`--report-junit FILE`]: /docs/manual.md#report-junit
|
||||
[`--test` option]: /docs/manual.md#test
|
||||
[`--glob` option]: /docs/manual.md#glob
|
||||
[`--variable` option]: /docs/manual.md#variable
|
||||
|
110
docs/samples.md
110
docs/samples.md
@ -137,15 +137,11 @@ file,data.json;
|
||||
|
||||
[Doc](/docs/request.md#file-body)
|
||||
|
||||
### Templating a JSON / XML Body
|
||||
### Templating a JSON Body
|
||||
|
||||
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:
|
||||
|
||||
~~~hurl
|
||||
```hurl
|
||||
PUT https://example.org/api/hits
|
||||
Content-Type: application/json
|
||||
```
|
||||
{
|
||||
"key0": "{{a_string}}",
|
||||
"key1": {{a_bool}},
|
||||
@ -153,7 +149,6 @@ Content-Type: application/json
|
||||
"key3": {{a_number}}
|
||||
}
|
||||
```
|
||||
~~~
|
||||
|
||||
Variables can be initialized via command line:
|
||||
|
||||
@ -176,8 +171,67 @@ Resulting in a PUT request with the following JSON body:
|
||||
}
|
||||
```
|
||||
|
||||
[Doc](/docs/templates.md)
|
||||
|
||||
### 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](/docs/request.md#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](/docs/request.md#graphql-body)
|
||||
|
||||
## Testing Response
|
||||
|
||||
### Testing Response Headers
|
||||
@ -187,7 +241,7 @@ Use implicit response asserts to test header values:
|
||||
```hurl
|
||||
GET https://example.org/index.html
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
Set-Cookie: theme=light
|
||||
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
|
||||
```
|
||||
@ -200,7 +254,7 @@ Or use explicit response asserts with [predicates]:
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
[Asserts]
|
||||
header "Location" contains "www.example.net"
|
||||
```
|
||||
@ -216,7 +270,7 @@ Asserting JSON body response (node values, collection count etc...) with [JSONPa
|
||||
GET https://example.org/order
|
||||
screencapability: low
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.validated" == true
|
||||
jsonpath "$.userInfo.firstName" == "Franck"
|
||||
@ -236,7 +290,7 @@ Testing status code:
|
||||
```hurl
|
||||
GET https://example.org/order/435
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
[Doc](/docs/asserting-response.md#version-status)
|
||||
@ -245,7 +299,7 @@ HTTP/1.1 200
|
||||
GET https://example.org/order/435
|
||||
|
||||
# Testing status code is in a 200-300 range
|
||||
HTTP/1.1 *
|
||||
HTTP *
|
||||
[Asserts]
|
||||
status >= 200
|
||||
status < 300
|
||||
@ -259,7 +313,7 @@ status < 300
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
[Asserts]
|
||||
@ -278,7 +332,7 @@ xpath "string(//div[1])" matches /Hello.*/
|
||||
```hurl
|
||||
GET http://myserver.com/home
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
cookie "JSESSIONID" == "8400BAFE2F66443613DC38AE3D9D6239"
|
||||
cookie "JSESSIONID[Value]" == "8400BAFE2F66443613DC38AE3D9D6239"
|
||||
@ -308,6 +362,17 @@ sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
|
||||
|
||||
## Others
|
||||
|
||||
### HTTP Version
|
||||
|
||||
Testing HTTP version (1.0, 1.1 or 2):
|
||||
|
||||
```hurl
|
||||
GET https://example.org/order/435
|
||||
HTTP/2 200
|
||||
```
|
||||
|
||||
[Doc](/docs/asserting-response.md#version-status)
|
||||
|
||||
### Polling and Retry
|
||||
|
||||
Retry request on any errors (asserts, captures, status code, runtime etc...):
|
||||
@ -316,7 +381,7 @@ Retry request on any errors (asserts, captures, status code, runtime etc...):
|
||||
# Create a new job
|
||||
POST https://api.example.org/jobs
|
||||
|
||||
HTTP/* 201
|
||||
HTTP 201
|
||||
[Captures]
|
||||
job_id: jsonpath "$.id"
|
||||
[Asserts]
|
||||
@ -328,7 +393,7 @@ GET https://api.example.org/jobs/{{job_id}}
|
||||
[Options]
|
||||
retry: true
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.state" == "COMPLETED"
|
||||
```
|
||||
@ -342,7 +407,7 @@ jsonpath "$.state" == "COMPLETED"
|
||||
```hurl
|
||||
GET https://sample.org/helloworld
|
||||
|
||||
HTTP/* *
|
||||
HTTP *
|
||||
[Asserts]
|
||||
duration < 1000 # Check that response time is less than one second
|
||||
```
|
||||
@ -365,7 +430,7 @@ SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
|
||||
</soap:Body>
|
||||
</soap:Envelope>
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
[Doc](/docs/request.md#xml-body)
|
||||
@ -375,14 +440,14 @@ HTTP/1.1 200
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/* 200
|
||||
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
|
||||
HTTP 302
|
||||
```
|
||||
|
||||
[Doc](/docs/capturing-response.md#xpath-capture)
|
||||
@ -392,7 +457,7 @@ HTTP/* 302
|
||||
```hurl
|
||||
GET https://example.org/data.bin
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
bytes startsWith hex,efbbbf;
|
||||
```
|
||||
@ -402,7 +467,7 @@ bytes startsWith hex,efbbbf;
|
||||
|
||||
[JSON body]: /docs/request.md#json-body
|
||||
[XML body]: /docs/request.md#xml-body
|
||||
[multiline string body]: /docs/request.md#multiline-string-body
|
||||
[XML multiline string body]: /docs/request.md#multiline-string-body
|
||||
[predicates]: /docs/asserting-response.md#predicates
|
||||
[JSONPath]: https://goessner.net/articles/JsonPath/
|
||||
[Basic authentication]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme
|
||||
@ -413,3 +478,4 @@ bytes startsWith hex,efbbbf;
|
||||
[curl]: https://curl.se
|
||||
[entry]: /docs/entry.md
|
||||
[`--test` option]: /docs/manual.md#test
|
||||
[Hurl templates]: /docs/templates.md
|
||||
|
@ -8,7 +8,7 @@ value from an HTTP response in the next entries, you can capture this value in a
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
|
||||
|
||||
@ -16,7 +16,7 @@ csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
|
||||
POST https://acmecorp.net/login?user=toto&password=1234
|
||||
X-CSRF-TOKEN: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
```
|
||||
|
||||
In this example, we capture the value of the [CSRF token] from the body of the first response, and inject it
|
||||
@ -24,12 +24,15 @@ as a header in the next POST request.
|
||||
|
||||
```hurl
|
||||
GET https://example.org/api/index
|
||||
HTTP/* 200
|
||||
|
||||
HTTP 200
|
||||
[Captures]
|
||||
index: body
|
||||
|
||||
|
||||
GET https://example.org/api/status
|
||||
HTTP/* 200
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.errors[{{index}}].id" == "error"
|
||||
```
|
||||
@ -45,7 +48,8 @@ templates can be rendered differently. Let's say we have captured an integer val
|
||||
|
||||
```hurl
|
||||
GET https://sample/counter
|
||||
HTTP/* 200
|
||||
|
||||
HTTP 200
|
||||
[Captures]
|
||||
count: jsonpath "$.results[0]"
|
||||
```
|
||||
@ -54,7 +58,8 @@ The following entry:
|
||||
|
||||
```hurl
|
||||
GET https://sample/counter/{{count}}
|
||||
HTTP/* 200
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.id" == "{{count}}"
|
||||
```
|
||||
@ -62,8 +67,9 @@ jsonpath "$.id" == "{{count}}"
|
||||
will be rendered at runtime to:
|
||||
|
||||
```hurl
|
||||
GET https://sample/counter/458
|
||||
HTTP/* 200
|
||||
GET https://sample/counter/458
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.id" == "458"
|
||||
```
|
||||
@ -74,7 +80,8 @@ On the other hand, the following assert:
|
||||
|
||||
```hurl
|
||||
GET https://sample/counter/{{count}}
|
||||
HTTP/* 200
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.index" == {{count}}
|
||||
```
|
||||
@ -83,7 +90,8 @@ will be rendered at runtime to:
|
||||
|
||||
```hurl
|
||||
GET https://sample/counter/458
|
||||
HTTP/* 200
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.index" == 458
|
||||
```
|
||||
@ -105,15 +113,16 @@ Variables can also be injected in a Hurl file:
|
||||
- by using [`--variable` option]
|
||||
- by using [`--variables-file` option]
|
||||
- by defining environment variables, for instance `HURL_foo=bar`
|
||||
- by defining variables in an [`[Options]` section][options]
|
||||
|
||||
Lets' see how to inject variables, given this `test.hurl`:
|
||||
|
||||
```hurl
|
||||
GET https://{{host}}/{{id}}/status
|
||||
HTTP/1.1 304
|
||||
HTTP 304
|
||||
|
||||
GET https://{{host}}/health
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
### `variable` option
|
||||
@ -142,14 +151,28 @@ id=1234
|
||||
|
||||
### Environment variable
|
||||
|
||||
Finally, we can use environment variables in the form of `HURL_name=value`:
|
||||
We can use environment variables in the form of `HURL_name=value`:
|
||||
|
||||
```shell
|
||||
$ export HURL_host=example.net
|
||||
$ export HURL_id=1234
|
||||
$ hurl test.hurl
|
||||
```
|
||||
```
|
||||
|
||||
### Options sections
|
||||
|
||||
We can define variables in `[Options]` section. Variables defined in a section are available for the next requests.
|
||||
|
||||
```hurl
|
||||
GET https://{{host}}/{{id}}/status
|
||||
[Options]
|
||||
variable: host=example.net
|
||||
variable: id=1234
|
||||
HTTP 304
|
||||
|
||||
GET https://{{host}}/health
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
|
||||
## Templating Body
|
||||
@ -194,3 +217,4 @@ Resulting in a PUT request with the following JSON body:
|
||||
[JSON body]: /docs/request.md#json-body
|
||||
[XML body]: /docs/request.md#xml-body
|
||||
[multiline string body]: /docs/request.md#multiline-string-body
|
||||
[options]: /docs/request.md#options
|
||||
|
@ -6,19 +6,13 @@ Our basic Hurl file is now:
|
||||
# Our first Hurl file, just checking
|
||||
# that our server is up and running.
|
||||
GET http://localhost:8080
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
Currently, we're just checking that our home page is responding with a `200 OK` HTTP status code.
|
||||
But we also want to check the _content_ of our home page, to ensure that everything is ok. To check the response
|
||||
of an HTTP request with Hurl, we have to _describe_ tests that the response content must pass.
|
||||
|
||||
> We're already implicitly asserting the response with the line\
|
||||
> `HTTP/1.1 200`\
|
||||
> On one hand, we are checking that the HTTP protocol version is 1.1; on the other hand, we are checking
|
||||
> that the HTTP status response code is 200.
|
||||
|
||||
To do so, we're going to use [asserts].
|
||||
|
||||
As our endpoint <http://localhost:8080> is serving HTML content, it makes sense to use [XPath asserts].
|
||||
@ -48,7 +42,7 @@ going to use the [XPath expression] `string(//head/title)`.
|
||||
# that our server is up and running.
|
||||
GET http://localhost:8080
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "string(//head/title)" == "Welcome to Quiz!"
|
||||
```
|
||||
@ -75,7 +69,7 @@ There is no error so everything is good!
|
||||
# that our server is up and running.
|
||||
GET http://localhost:8080
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "string(//head/title)" == "Welcome to Quaz!"
|
||||
```
|
||||
@ -123,7 +117,7 @@ with `count`:
|
||||
# Checking our home page:
|
||||
GET http://localhost:8080
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "string(//head/title)" == "Welcome to Quiz!"
|
||||
xpath "//button" count == 2
|
||||
@ -135,7 +129,7 @@ xpath "//button" count == 2
|
||||
# Checking our home page:
|
||||
GET http://localhost:8080
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "string(//head/title)" == "Welcome to Quiz!"
|
||||
xpath "//button" count == 2
|
||||
@ -172,7 +166,7 @@ As our endpoint is serving UTF-8 encoded HTML content, we can check the value of
|
||||
# Checking our home page:
|
||||
GET http://localhost:8080
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "string(//head/title)" == "Welcome to Quiz!"
|
||||
xpath "//button" count == 2
|
||||
@ -197,7 +191,7 @@ while the explicit one allows you to use other [predicates] (like `contains`, `s
|
||||
# Checking our home page:
|
||||
GET http://localhost:8080
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
# Implicitly testing response headers:
|
||||
Content-Type: text/html;charset=UTF-8
|
||||
[Asserts]
|
||||
@ -223,7 +217,7 @@ So to test it, we can modify our Hurl file with another header assert.
|
||||
# Checking our home page:
|
||||
GET http://localhost:8080
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "string(//head/title)" == "Welcome to Quiz!"
|
||||
xpath "//button" count == 2
|
||||
@ -250,7 +244,7 @@ So to test that our server is responding with a `HttpOnly` session cookie, we ca
|
||||
# Checking our home page:
|
||||
GET http://localhost:8080
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "string(//head/title)" == "Welcome to Quiz!"
|
||||
xpath "//button" count == 2
|
||||
|
@ -55,7 +55,7 @@ question2: 4edc1fdb
|
||||
question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
```
|
||||
|
||||
> When sending form data with a Form parameters section, you don't need to set the
|
||||
@ -67,10 +67,10 @@ HTTP/1.1 302
|
||||
$ hurl --test create-quiz.hurl
|
||||
[1mcreate-quiz.hurl[0m: [1;36mRunning[0m [1/1]
|
||||
[1;31merror[0m: [1mAssert status code[0m
|
||||
[1;34m-->[0m create-quiz.hurl:10:10
|
||||
[1;34m-->[0m create-quiz.hurl:6:10
|
||||
[1;34m|[0m
|
||||
[1;34m10[0m [1;34m|[0m HTTP/1.1 302
|
||||
[1;34m|[0m [1;31m^^^[0m [1;31mactual value is <403>[0m
|
||||
[1;34m10[0m [1;34m|[0m HTTP 302
|
||||
[1;34m|[0m [1;31m^^^[0m [1;31mactual value is <403>[0m
|
||||
[1;34m|[0m
|
||||
|
||||
[1mcreate-quiz.hurl[0m: [1;31mFailure[0m (1 request(s) in 5 ms)
|
||||
@ -122,7 +122,7 @@ So, let's go!
|
||||
# the CSRF token (see https://en.wikipedia.org/wiki/Cross-site_request_forgery)
|
||||
GET http://localhost:8080/new-quiz
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
csrf_token: xpath "string(//input[@name='_csrf']/@value)"
|
||||
```
|
||||
@ -146,10 +146,11 @@ Now that we have captured the CSRF token value, we can inject it in the POST req
|
||||
# the CSRF token (see https://en.wikipedia.org/wiki/Cross-site_request_forgery):
|
||||
GET http://localhost:8080/new-quiz
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
csrf_token: xpath "string(//input[@name='_csrf']/@value)"
|
||||
|
||||
|
||||
# Create a new quiz, using the captured CSRF token:
|
||||
POST http://localhost:8080/new-quiz
|
||||
[FormParams]
|
||||
@ -160,8 +161,7 @@ question2: 4edc1fdb
|
||||
question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
_csrf: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
```
|
||||
|
||||
3. Run `create-quiz.hurl` and verify everything is ok:
|
||||
@ -207,7 +207,7 @@ question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
_csrf: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
[Captures]
|
||||
detail_url: header "Location"
|
||||
```
|
||||
@ -232,7 +232,7 @@ question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
_csrf: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
[Captures]
|
||||
detail_url: header "Location"
|
||||
[Asserts]
|
||||
@ -250,7 +250,7 @@ header "Location" matches "/quiz/detail/[a-f0-9]{8}"
|
||||
|
||||
# Open the newly created quiz detail page:
|
||||
GET {{detail_url}}
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
4. Run `create-quiz.hurl` and verify everything is ok:
|
||||
@ -267,7 +267,7 @@ Duration: 46 ms
|
||||
```
|
||||
|
||||
|
||||
> You can force Hurl to follow redirection by using [`-L / --location` option].
|
||||
> You can force Hurl to follow redirection by using [`-L / --location` option] or using an [`[Options]` section][options].
|
||||
> In this case, asserts and captures will be run against the last redirection step.
|
||||
|
||||
|
||||
@ -280,10 +280,11 @@ So, our test file `create-quiz.hurl` is now:
|
||||
# the CSRF token (see https://en.wikipedia.org/wiki/Cross-site_request_forgery)
|
||||
GET http://localhost:8080/new-quiz
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
csrf_token: xpath "string(//input[@name='_csrf']/@value)"
|
||||
|
||||
|
||||
# Create a new quiz, using the captured CSRF token.
|
||||
POST http://localhost:8080/new-quiz
|
||||
[FormParams]
|
||||
@ -295,15 +296,16 @@ question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
_csrf: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
[Captures]
|
||||
detail_url: header "Location"
|
||||
[Asserts]
|
||||
header "Location" matches "/quiz/detail/[a-f0-9]{8}"
|
||||
|
||||
|
||||
# Open the newly created quiz detail page:
|
||||
GET {{detail_url}}
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
We have seen how to [capture response data] in a variable and use it in others request.
|
||||
@ -326,4 +328,5 @@ of a redirection.
|
||||
[header capture]: /docs/capturing-response.md#header-capture
|
||||
[`Location`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location
|
||||
[`-L / --location` option]: /docs/manual.md#location
|
||||
[capture response data]: /docs/capturing-response.md
|
||||
[capture response data]: /docs/capturing-response.md
|
||||
[options]: /docs/request.md#options
|
@ -8,7 +8,7 @@ Our basic Hurl file is for the moment:
|
||||
# Checking our home page:
|
||||
GET http://localhost:8080
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "string(//head/title)" == "Welcome to Quiz!"
|
||||
xpath "//button" count == 2
|
||||
@ -33,7 +33,7 @@ request following our first request. Let's say we want to test that we have a [4
|
||||
# Checking our home page:
|
||||
GET http://localhost:8080
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "string(//head/title)" == "Welcome to Quiz!"
|
||||
xpath "//button" count == 2
|
||||
@ -48,7 +48,7 @@ cookie "JSESSIONID[HttpOnly]" exists
|
||||
# Check that we have a 404 response for broken links:
|
||||
GET http://localhost:8080/not-found
|
||||
|
||||
HTTP/1.1 404
|
||||
HTTP 404
|
||||
[Asserts]
|
||||
header "Content-Type" == "text/html;charset=UTF-8"
|
||||
xpath "string(//h1)" == "Error 404, Page not Found!"
|
||||
@ -126,7 +126,7 @@ followed by a predicate. A [JsonPath query] is a simple expression to inspect a
|
||||
# Check our health API:
|
||||
GET http://localhost:8080/api/health
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
jsonpath "$.status" == "RUNNING"
|
||||
@ -155,7 +155,7 @@ through the API endpoint.
|
||||
# Check question API:
|
||||
GET http://localhost:8080/api/questions?offset=0&size=20&sort=oldest
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
jsonpath "$" count == 20
|
||||
@ -194,7 +194,7 @@ offset: 0
|
||||
size: 20
|
||||
sort: oldest
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
jsonpath "$" count == 20
|
||||
@ -208,7 +208,7 @@ Finally, our basic Hurl file, with four requests, looks like:
|
||||
# Checking our home page:
|
||||
GET http://localhost:8080
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "string(//head/title)" == "Welcome to Quiz!"
|
||||
xpath "//button" count == 2
|
||||
@ -220,24 +220,27 @@ header "Content-Type" == "text/html;charset=UTF-8"
|
||||
cookie "JSESSIONID" exists
|
||||
cookie "JSESSIONID[HttpOnly]" exists
|
||||
|
||||
|
||||
# Check that we have a 404 response for broken links:
|
||||
GET http://localhost:8080/not-found
|
||||
|
||||
HTTP/1.1 404
|
||||
HTTP 404
|
||||
[Asserts]
|
||||
header "Content-Type" == "text/html;charset=UTF-8"
|
||||
xpath "string(//h1)" == "Error 404, Page not Found!"
|
||||
|
||||
|
||||
# Check our health API:
|
||||
GET http://localhost:8080/api/health
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
jsonpath "$.status" == "RUNNING"
|
||||
jsonpath "$.healthy" == true
|
||||
jsonpath "$.operationId" exists
|
||||
|
||||
|
||||
# Check question API:
|
||||
GET http://localhost:8080/api/questions
|
||||
[QueryStringParams]
|
||||
@ -245,7 +248,7 @@ offset: 0
|
||||
size: 20
|
||||
sort: oldest
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
jsonpath "$" count == 20
|
||||
|
@ -77,7 +77,7 @@ really ready to accept incoming HTTP requests.
|
||||
|
||||
To do so, we can test our health API. With a function `wait_for_url`,
|
||||
we use Hurl to check a given URL to return a `200 OK`. We loop on this function
|
||||
until the check succeeds. Once the test has succeeded, we stop the container.
|
||||
until the check succeeds with [`--retry`] Hurl option. Once the test has succeeded, we stop the container.
|
||||
|
||||
5. Modify `bin/integration.sh` to wait for the application to be ready:
|
||||
|
||||
@ -86,24 +86,13 @@ until the check succeeds. Once the test has succeeded, we stop the container.
|
||||
set -eu
|
||||
|
||||
wait_for_url () {
|
||||
echo "Testing $1"
|
||||
max_in_s=$2
|
||||
delay_in_s=1
|
||||
total_in_s=0
|
||||
while [ $total_in_s -le "$max_in_s" ]
|
||||
do
|
||||
echo "Wait ${total_in_s}s"
|
||||
if (echo -e "GET $1\nHTTP/* 200" | hurl > /dev/null 2>&1;) then
|
||||
return 0
|
||||
fi
|
||||
total_in_s=$(( total_in_s + delay_in_s))
|
||||
sleep $delay_in_s
|
||||
done
|
||||
return 1
|
||||
echo "Testing $1..."
|
||||
echo -e "GET $1\nHTTP 200" | hurl --retry --retry-max-count "$2" > /dev/null;
|
||||
return 0
|
||||
}
|
||||
|
||||
echo "Starting Quiz container"
|
||||
docker run --name quiz --rm --detach --publish 8080:8080 ghcr.io/jcamiel/quiz:latest
|
||||
docker run --rm --detach --publish 8080:8080 --name quiz ghcr.io/jcamiel/quiz:latest
|
||||
|
||||
echo "Starting Quiz instance to be ready"
|
||||
wait_for_url 'http://localhost:8080' 60
|
||||
@ -275,3 +264,4 @@ Now, we can add more Hurl tests and start developing new features with confidenc
|
||||
[GitLab CI/CD here]: https://about.gitlab.com/blog/2022/12/14/how-to-continously-test-web-apps-apis-with-hurl-and-gitlab-ci-cd/
|
||||
[GitLab CI/CD]: https://about.gitlab.com/why-gitlab/
|
||||
[this detailed tutorial]: https://about.gitlab.com/blog/2022/12/14/how-to-continously-test-web-apps-apis-with-hurl-and-gitlab-ci-cd/
|
||||
[`--retry`]: /docs/manual.md#retry
|
@ -239,7 +239,7 @@ offset: 0
|
||||
size: 20
|
||||
sort: oldest
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
# ...
|
||||
```
|
||||
|
||||
@ -357,18 +357,19 @@ In this mode, headers of the last entry are displayed:
|
||||
|
||||
```shell
|
||||
$ hurl -i basic.hurl
|
||||
HTTP/1.1 200
|
||||
X-Content-Type-Options: nosniff
|
||||
X-XSS-Protection: 1; mode=block
|
||||
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
|
||||
Pragma: no-cache
|
||||
Expires: 0
|
||||
X-Frame-Options: DENY
|
||||
Content-Type: application/json
|
||||
Transfer-Encoding: chunked
|
||||
Date: Sun, 06 Jun 2021 15:11:31 GMT
|
||||
[1;32mHTTP/1.1 200
|
||||
[0m[1;36mSet-Cookie[0m: JSESSIONID=76984131F0D0821C4A8D5CB3FC27CD3B; Path=/; HttpOnly
|
||||
[1;36mX-Content-Type-Options[0m: nosniff
|
||||
[1;36mX-XSS-Protection[0m: 1; mode=block
|
||||
[1;36mCache-Control[0m: no-cache, no-store, max-age=0, must-revalidate
|
||||
[1;36mPragma[0m: no-cache
|
||||
[1;36mExpires[0m: 0
|
||||
[1;36mX-Frame-Options[0m: DENY
|
||||
[1;36mContent-Type[0m: application/json
|
||||
[1;36mTransfer-Encoding[0m: chunked
|
||||
[1;36mDate[0m: Fri, 13 Jan 2023 12:49:47 GMT
|
||||
|
||||
[{"id":"c0d80047-4fbe-4d45-a005-91b5c7018b34","created":"1995-12-17T03:24:00Z"....
|
||||
{"status":"RUNNING","reportedDate":"2023-01-13T13:49:47+01:00","healthy":true,"operationId":3183000623}
|
||||
```
|
||||
|
||||
If you want to inspect any entry other than the last one, you can run your test to a
|
||||
@ -376,40 +377,50 @@ given entry with the [`--to-entry` option], starting at index 1:
|
||||
|
||||
```shell
|
||||
$ hurl -i --to-entry 2 basic.hurl
|
||||
HTTP/1.1 404
|
||||
Vary: Origin
|
||||
Vary: Access-Control-Request-Method
|
||||
Vary: Access-Control-Request-Headers
|
||||
X-Content-Type-Options: nosniff
|
||||
X-XSS-Protection: 1; mode=block
|
||||
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
|
||||
Pragma: no-cache
|
||||
Expires: 0
|
||||
X-Frame-Options: DENY
|
||||
Content-Type: text/html;charset=UTF-8
|
||||
Content-Language: en-US
|
||||
Transfer-Encoding: chunked
|
||||
Date: Sun, 06 Jun 2021 15:14:20 GMT
|
||||
[1;32mHTTP/1.1 404
|
||||
[0m[1;36mVary[0m: Origin
|
||||
[1;36mVary[0m: Access-Control-Request-Method
|
||||
[1;36mVary[0m: Access-Control-Request-Headers
|
||||
[1;36mX-Content-Type-Options[0m: nosniff
|
||||
[1;36mX-XSS-Protection[0m: 1; mode=block
|
||||
[1;36mCache-Control[0m: no-cache, no-store, max-age=0, must-revalidate
|
||||
[1;36mPragma[0m: no-cache
|
||||
[1;36mExpires[0m: 0
|
||||
[1;36mX-Frame-Options[0m: DENY
|
||||
[1;36mContent-Type[0m: text/html;charset=UTF-8
|
||||
[1;36mContent-Language[0m: en-FR
|
||||
[1;36mTransfer-Encoding[0m: chunked
|
||||
[1;36mDate[0m: Fri, 13 Jan 2023 12:50:52 GMT
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Error 404 - Quiz</title>
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<!--<script src="script.js"></script>-->
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<img class="logo" src="/quiz.svg" alt="Quiz logo">
|
||||
<a href="/"><img class="logo-img" src="/quiz.svg" alt="Quiz logo"></a>
|
||||
</div>
|
||||
<div class="main">
|
||||
|
||||
<h1>Error 404, Page not Found!</h1>
|
||||
|
||||
<a href="/">Quiz Home</a>
|
||||
|
||||
|
||||
</div>
|
||||
<footer>
|
||||
<div class="footer">
|
||||
<div class="footer-body">a game by <a href="https://hurl.dev">Hurl⇄ Team</a></div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
## Using a Proxy
|
||||
|
@ -8,10 +8,11 @@ endpoint. Our test file `create-quiz.hurl` now looks like:
|
||||
# the CSRF token (see https://en.wikipedia.org/wiki/Cross-site_request_forgery)
|
||||
GET http://localhost:8080/new-quiz
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
csrf_token: xpath "string(//input[@name='_csrf']/@value)"
|
||||
|
||||
|
||||
# Create a new quiz, using the captured CSRF token.
|
||||
POST http://localhost:8080/new-quiz
|
||||
[FormParams]
|
||||
@ -23,15 +24,16 @@ question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
_csrf: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
[Captures]
|
||||
detail_url: header "Location"
|
||||
[Asserts]
|
||||
header "Location" matches "/quiz/detail/[a-f0-9]{8}"
|
||||
|
||||
|
||||
# Open the newly created quiz detail page:
|
||||
GET {{detail_url}}
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
So far, we have tested a "simple" form creation: every value of the form is valid and sanitized, but what if the user
|
||||
@ -88,7 +90,7 @@ question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
_csrf: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "//label[@for='name'][@class='invalid']" exists
|
||||
```
|
||||
@ -123,7 +125,7 @@ question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
_csrf: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "//label[@for='email'][@class='invalid']" exists
|
||||
```
|
||||
@ -156,8 +158,7 @@ question1: dd894cca
|
||||
question2: 4edc1fdb
|
||||
question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
|
||||
HTTP/1.1 403
|
||||
HTTP 403
|
||||
```
|
||||
|
||||
> We're using [the exist predicate] to check labels in the DOM
|
||||
@ -198,7 +199,7 @@ With Hurl, you will be able to check the content of the _real_ network data.
|
||||
# the CSRF token (see https://en.wikipedia.org/wiki/Cross-site_request_forgery)
|
||||
GET http://localhost:8080/new-quiz
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
csrf_token: xpath "string(//input[@name='_csrf']/@value)"
|
||||
[Asserts]
|
||||
@ -230,12 +231,13 @@ So, our test file `create-quiz.hurl` is now:
|
||||
# the CSRF token (see https://en.wikipedia.org/wiki/Cross-site_request_forgery)
|
||||
GET http://localhost:8080/new-quiz
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
csrf_token: xpath "string(//input[@name='_csrf']/@value)"
|
||||
[Asserts]
|
||||
xpath "//comment" count == 0 # Check that we don't leak comments
|
||||
|
||||
|
||||
# Create a new quiz, using the captured CSRF token.
|
||||
POST http://localhost:8080/new-quiz
|
||||
[FormParams]
|
||||
@ -247,15 +249,16 @@ question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
_csrf: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
[Captures]
|
||||
detail_url: header "Location"
|
||||
[Asserts]
|
||||
header "Location" matches "/quiz/detail/[a-f0-9]{8}"
|
||||
|
||||
|
||||
# Open the newly created quiz detail page:
|
||||
GET {{detail_url}}
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
|
||||
# Test various server-side validations:
|
||||
|
||||
@ -270,10 +273,11 @@ question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
_csrf: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "//label[@for='name'][@class='invalid']" exists
|
||||
|
||||
|
||||
# Invalid email parameter:
|
||||
POST http://localhost:8080/new-quiz
|
||||
[FormParams]
|
||||
@ -286,10 +290,11 @@ question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
_csrf: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "//label[@for='email'][@class='invalid']" exists
|
||||
|
||||
|
||||
# No CSRF token:
|
||||
POST http://localhost:8080/new-quiz
|
||||
[FormParams]
|
||||
@ -300,8 +305,7 @@ question1: dd894cca
|
||||
question2: 4edc1fdb
|
||||
question3: 37b9eff3
|
||||
question4: 0fec576c
|
||||
|
||||
HTTP/1.1 403
|
||||
HTTP 403
|
||||
```
|
||||
|
||||
We have seen that Hurl can be used as a security tool, to check you server-side validation.
|
||||
|
@ -127,7 +127,7 @@ the response and, at least, check that the HTTP response status code is [`200 OK
|
||||
|
||||
```hurl
|
||||
GET http://localhost:8080
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
4. Execute `basic.hurl`:
|
||||
@ -173,7 +173,7 @@ Duration: 7 ms
|
||||
|
||||
```hurl
|
||||
GET http://localhost:8080
|
||||
HTTP/1.1 500
|
||||
HTTP 500
|
||||
```
|
||||
|
||||
7. Save and execute it:
|
||||
@ -204,7 +204,7 @@ Duration: 13 ms
|
||||
# Our first Hurl file, just checking
|
||||
# that our server is up and running.
|
||||
GET http://localhost:8080
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
## Recap
|
||||
|
@ -12,21 +12,24 @@
|
||||
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 <b>fetching data</b>, <b>testing HTTP</b> sessions and testing <b>XML / JSON APIs</b>.
|
||||
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
|
||||
# Get home:
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Captures]
|
||||
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
|
||||
|
||||
|
||||
# Do login!
|
||||
POST https://example.org/login?user=toto&password=1234
|
||||
X-CSRF-TOKEN: {{csrf_token}}
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
```
|
||||
|
||||
Chaining multiple requests is easy:
|
||||
@ -55,7 +58,7 @@ POST https://example.org/api/tests
|
||||
"evaluate": true
|
||||
}
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "X-Frame-Options" == "SAMEORIGIN"
|
||||
jsonpath "$.status" == "RUNNING" # Check the status code
|
||||
@ -68,12 +71,27 @@ jsonpath "$.id" matches /\d{4}/ # Check the format of the id
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
xpath "normalize-space(//head/title)" == "Hello world!"
|
||||
```
|
||||
|
||||
and even SOAP APIs
|
||||
<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
|
||||
@ -88,8 +106,7 @@ SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
|
||||
</m:GetStockPrice>
|
||||
</soap:Body>
|
||||
</soap:Envelope>
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
Hurl can also be used to performance test HTTP endpoints:
|
||||
@ -97,7 +114,7 @@ Hurl can also be used to performance test HTTP endpoints:
|
||||
```hurl
|
||||
GET https://example.org/api/v1/pets
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
duration < 1000 # Duration in ms
|
||||
```
|
||||
@ -107,7 +124,7 @@ And response bytes
|
||||
```hurl
|
||||
GET https://example.org/data.tar.gz
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
|
||||
```
|
||||
@ -138,7 +155,7 @@ POST https://hurl.dev/api/feedback
|
||||
"name": "John Doe",
|
||||
"feedback": "Hurl is awesome !"
|
||||
}
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
# Resources
|
||||
@ -164,7 +181,9 @@ Table of Contents
|
||||
* [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 / XML Body](#templating-a-json--xml-body)
|
||||
* [Templating a JSON Body](#templating-a-json-body)
|
||||
* [Templating a XML Body](#templating-a-xml-body)
|
||||
* [Using GraphQL Query](#using-graphql-query)
|
||||
* [Testing Response](#testing-response)
|
||||
* [Testing Response Headers](#testing-response-headers)
|
||||
* [Testing REST APIs](#testing-rest-apis)
|
||||
@ -172,6 +191,7 @@ Table of Contents
|
||||
* [Testing Set-Cookie Attributes](#testing-set-cookie-attributes)
|
||||
* [Testing Bytes Content](#testing-bytes-content)
|
||||
* [Others](#others)
|
||||
* [HTTP Version](#http-version)
|
||||
* [Polling and Retry](#polling-and-retry)
|
||||
* [Testing Endpoint Performance](#testing-endpoint-performance)
|
||||
* [Using SOAP APIs](#using-soap-apis)
|
||||
@ -354,15 +374,11 @@ file,data.json;
|
||||
|
||||
[Doc](https://hurl.dev/docs/request.html#file-body)
|
||||
|
||||
### Templating a JSON / XML Body
|
||||
### Templating a JSON Body
|
||||
|
||||
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:
|
||||
|
||||
~~~hurl
|
||||
```hurl
|
||||
PUT https://example.org/api/hits
|
||||
Content-Type: application/json
|
||||
```
|
||||
{
|
||||
"key0": "{{a_string}}",
|
||||
"key1": {{a_bool}},
|
||||
@ -370,7 +386,6 @@ Content-Type: application/json
|
||||
"key3": {{a_number}}
|
||||
}
|
||||
```
|
||||
~~~
|
||||
|
||||
Variables can be initialized via command line:
|
||||
|
||||
@ -393,8 +408,67 @@ Resulting in a PUT request with the following JSON body:
|
||||
}
|
||||
```
|
||||
|
||||
[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-body)
|
||||
|
||||
## Testing Response
|
||||
|
||||
### Testing Response Headers
|
||||
@ -404,7 +478,7 @@ Use implicit response asserts to test header values:
|
||||
```hurl
|
||||
GET https://example.org/index.html
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
Set-Cookie: theme=light
|
||||
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
|
||||
```
|
||||
@ -417,7 +491,7 @@ Or use explicit response asserts with [predicates]:
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 302
|
||||
HTTP 302
|
||||
[Asserts]
|
||||
header "Location" contains "www.example.net"
|
||||
```
|
||||
@ -433,7 +507,7 @@ Asserting JSON body response (node values, collection count etc...) with [JSONPa
|
||||
GET https://example.org/order
|
||||
screencapability: low
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.validated" == true
|
||||
jsonpath "$.userInfo.firstName" == "Franck"
|
||||
@ -453,7 +527,7 @@ Testing status code:
|
||||
```hurl
|
||||
GET https://example.org/order/435
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
[Doc](https://hurl.dev/docs/asserting-response.html#version-status)
|
||||
@ -462,7 +536,7 @@ HTTP/1.1 200
|
||||
GET https://example.org/order/435
|
||||
|
||||
# Testing status code is in a 200-300 range
|
||||
HTTP/1.1 *
|
||||
HTTP *
|
||||
[Asserts]
|
||||
status >= 200
|
||||
status < 300
|
||||
@ -476,7 +550,7 @@ status < 300
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
[Asserts]
|
||||
@ -495,7 +569,7 @@ xpath "string(//div[1])" matches /Hello.*/
|
||||
```hurl
|
||||
GET http://myserver.com/home
|
||||
|
||||
HTTP/1.0 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
cookie "JSESSIONID" == "8400BAFE2F66443613DC38AE3D9D6239"
|
||||
cookie "JSESSIONID[Value]" == "8400BAFE2F66443613DC38AE3D9D6239"
|
||||
@ -525,6 +599,17 @@ sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
|
||||
|
||||
## Others
|
||||
|
||||
### HTTP Version
|
||||
|
||||
Testing HTTP version (1.0, 1.1 or 2):
|
||||
|
||||
```hurl
|
||||
GET https://example.org/order/435
|
||||
HTTP/2 200
|
||||
```
|
||||
|
||||
[Doc](https://hurl.dev/docs/asserting-response.html#version-status)
|
||||
|
||||
### Polling and Retry
|
||||
|
||||
Retry request on any errors (asserts, captures, status code, runtime etc...):
|
||||
@ -533,7 +618,7 @@ Retry request on any errors (asserts, captures, status code, runtime etc...):
|
||||
# Create a new job
|
||||
POST https://api.example.org/jobs
|
||||
|
||||
HTTP/* 201
|
||||
HTTP 201
|
||||
[Captures]
|
||||
job_id: jsonpath "$.id"
|
||||
[Asserts]
|
||||
@ -545,7 +630,7 @@ GET https://api.example.org/jobs/{{job_id}}
|
||||
[Options]
|
||||
retry: true
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.state" == "COMPLETED"
|
||||
```
|
||||
@ -559,7 +644,7 @@ jsonpath "$.state" == "COMPLETED"
|
||||
```hurl
|
||||
GET https://sample.org/helloworld
|
||||
|
||||
HTTP/* *
|
||||
HTTP *
|
||||
[Asserts]
|
||||
duration < 1000 # Check that response time is less than one second
|
||||
```
|
||||
@ -582,7 +667,7 @@ SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
|
||||
</soap:Body>
|
||||
</soap:Envelope>
|
||||
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
[Doc](https://hurl.dev/docs/request.html#xml-body)
|
||||
@ -592,14 +677,14 @@ HTTP/1.1 200
|
||||
```hurl
|
||||
GET https://example.org
|
||||
|
||||
HTTP/* 200
|
||||
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
|
||||
HTTP 302
|
||||
```
|
||||
|
||||
[Doc](https://hurl.dev/docs/capturing-response.html#xpath-capture)
|
||||
@ -609,7 +694,7 @@ HTTP/* 302
|
||||
```hurl
|
||||
GET https://example.org/data.bin
|
||||
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
bytes startsWith hex,efbbbf;
|
||||
```
|
||||
@ -631,9 +716,9 @@ hurl - run and test HTTP requests.
|
||||
|
||||
## Description
|
||||
|
||||
**Hurl** is an HTTP client that performs HTTP requests defined in a simple plain text format.
|
||||
**Hurl** is a command line tool that runs 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.
|
||||
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
|
||||
@ -690,11 +775,11 @@ GET http:/example.org/endpoint2
|
||||
|
||||
A value from an HTTP response can be-reused for successive HTTP requests.
|
||||
|
||||
A typical example occurs with csrf tokens.
|
||||
A typical example occurs with CSRF tokens.
|
||||
|
||||
```hurl
|
||||
GET https://example.org
|
||||
HTTP/1.1 200
|
||||
HTTP 200
|
||||
# Capture the CSRF token value from html body.
|
||||
[Captures]
|
||||
csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"
|
||||
@ -708,28 +793,28 @@ More information on captures can be found here [https://hurl.dev/docs/capturing-
|
||||
|
||||
### Asserts
|
||||
|
||||
The HTTP response defined in the Hurl session are used to make asserts.
|
||||
The HTTP response defined in the Hurl file are used to make asserts. Responses are optional.
|
||||
|
||||
At the minimum, the response includes the asserts on the HTTP version and status code.
|
||||
At the minimum, response includes assert on the HTTP status code.
|
||||
|
||||
```hurl
|
||||
GET http:/google.com
|
||||
HTTP/1.1 301
|
||||
GET http:/example.org
|
||||
HTTP 301
|
||||
```
|
||||
|
||||
It can also include asserts on the response headers
|
||||
|
||||
```hurl
|
||||
GET http:/google.com
|
||||
HTTP/1.1 301
|
||||
Location: http://www.google.com
|
||||
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:/google.com
|
||||
HTTP/1.1 301
|
||||
GET http:/example.org
|
||||
HTTP 301
|
||||
[Asserts]
|
||||
xpath "string(//title)" == "301 Moved"
|
||||
```
|
||||
@ -753,56 +838,61 @@ $ 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://google.com
|
||||
HTTP/* 301
|
||||
GET https://example.org
|
||||
HTTP 301
|
||||
|
||||
GET https://google.com
|
||||
GET https://example.org
|
||||
[Options]
|
||||
location: true
|
||||
HTTP/* 200
|
||||
HTTP 200
|
||||
```
|
||||
|
||||
will follow a redirection only for the second entry.
|
||||
|
||||
Option | Description
|
||||
--- | ---
|
||||
<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/>
|
||||
<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/>
|
||||
<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/>See also [`-m, --max-time`](#max-time) option.<br/>
|
||||
<a href="#cookie" id="cookie"><code>-b, --cookie <FILE></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 <FILE></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/>
|
||||
<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/>
|
||||
<a href="#file-root" id="file-root"><code>--file-root <DIR></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/>
|
||||
<a href="#glob" id="glob"><code>--glob <GLOB></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/>
|
||||
<a href="#include" id="include"><code>-i, --include</code></a> | Include the HTTP headers in the output (last entry).<br/>
|
||||
<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/>
|
||||
<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/>
|
||||
<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/>
|
||||
<a href="#max-redirs" id="max-redirs"><code>--max-redirs <NUM></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 <SECONDS></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/>
|
||||
<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/>
|
||||
<a href="#noproxy" id="noproxy"><code>--noproxy <HOST(S)></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 <FILE></code></a> | Write output to FILE instead of stdout.<br/>
|
||||
<a href="#proxy" id="proxy"><code>-x, --proxy [protocol://]host[:port]</code></a> | Use the specified proxy.<br/>
|
||||
<a href="#report-junit" id="report-junit"><code>--report-junit <FILE></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 <DIR></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 <MILLISECONDS></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 <NUM></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/>
|
||||
<a href="#to-entry" id="to-entry"><code>--to-entry <ENTRY_NUMBER></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 <USER:PASSWORD></code></a> | Add basic Authentication header to each request.<br/>
|
||||
<a href="#user-agent" id="user-agent"><code>-A, --user-agent <NAME></code></a> | Specify the User-Agent string to send to the HTTP server.<br/>
|
||||
<a href="#variable" id="variable"><code>--variable <NAME=VALUE></code></a> | Define variable (name/value) to be used in Hurl templates.<br/>
|
||||
<a href="#variables-file" id="variables-file"><code>--variables-file <FILE></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/>
|
||||
<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/>
|
||||
| Option | Description |
|
||||
|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| <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 [`--key`](#key).<br> |
|
||||
| <a href="#color" id="color"><code>--color</code></a> | Colorize Output.<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> |
|
||||
| <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>See also [`-m, --max-time`](#max-time).<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 [`--resolve`](#resolve).<br> |
|
||||
| <a href="#cookie" id="cookie"><code>-b, --cookie <FILE></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 <FILE></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> |
|
||||
| <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> |
|
||||
| <a href="#file-root" id="file-root"><code>--file-root <DIR></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> |
|
||||
| <a href="#glob" id="glob"><code>--glob <GLOB></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> |
|
||||
| <a href="#include" id="include"><code>-i, --include</code></a> | Include the HTTP headers in the output (last entry).<br> |
|
||||
| <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> |
|
||||
| <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> |
|
||||
| <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> |
|
||||
| <a href="#key" id="key"><code>--key <KEY></code></a> | Private key file name.<br> |
|
||||
| <a href="#max-redirs" id="max-redirs"><code>--max-redirs <NUM></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 <SECONDS></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).<br> |
|
||||
| <a href="#no-color" id="no-color"><code>--no-color</code></a> | Do not colorize output.<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> |
|
||||
| <a href="#noproxy" id="noproxy"><code>--noproxy <HOST(S)></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 <FILE></code></a> | Write output to FILE instead of stdout.<br> |
|
||||
| <a href="#proxy" id="proxy"><code>-x, --proxy <[PROTOCOL://]HOST[:PORT]></code></a> | Use the specified proxy.<br> |
|
||||
| <a href="#report-junit" id="report-junit"><code>--report-junit <FILE></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 <DIR></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="#resolve" id="resolve"><code>--resolve <HOST:PORT:ADDR></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="#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 <MILLISECONDS></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 <NUM></code></a> | Maximum number of retries. Set this option to -1 to make it unlimited. Default is 10.<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> |
|
||||
| <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> |
|
||||
| <a href="#to-entry" id="to-entry"><code>--to-entry <ENTRY_NUMBER></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 <USER:PASSWORD></code></a> | Add basic Authentication header to each request.<br> |
|
||||
| <a href="#user-agent" id="user-agent"><code>-A, --user-agent <NAME></code></a> | Specify the User-Agent string to send to the HTTP server.<br> |
|
||||
| <a href="#variable" id="variable"><code>--variable <NAME=VALUE></code></a> | Define variable (name/value) to be used in Hurl templates.<br> |
|
||||
| <a href="#variables-file" id="variables-file"><code>--variables-file <FILE></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> |
|
||||
| <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> |
|
||||
|
||||
## Environment
|
||||
|
||||
@ -810,23 +900,23 @@ Environment variables can only be specified in lowercase.
|
||||
|
||||
Using an environment variable to set the proxy has the same effect as using the [`-x, --proxy`](#proxy) option.
|
||||
|
||||
Variable | Description
|
||||
--- | ---
|
||||
`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/>
|
||||
`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/>
|
||||
| Variable | Description |
|
||||
|--------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `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> |
|
||||
| `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> |
|
||||
|
||||
## Exit Codes
|
||||
|
||||
Value | Description
|
||||
--- | ---
|
||||
`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/>
|
||||
| Value | Description |
|
||||
|-------|---------------------------------------------------------|
|
||||
| `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
|
||||
|
||||
@ -843,12 +933,12 @@ curl(1) hurlfmt(1)
|
||||
|
||||
### Linux
|
||||
|
||||
Precompiled binary is available at [hurl-1.8.0-x86_64-linux.tar.gz]:
|
||||
Precompiled binary is available at [hurl-2.0.0-x86_64-linux.tar.gz]:
|
||||
|
||||
```shell
|
||||
$ INSTALL_DIR=/tmp
|
||||
$ curl -sL https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-x86_64-linux.tar.gz | tar xvz -C $INSTALL_DIR
|
||||
$ export PATH=$INSTALL_DIR/hurl-1.8.0:$PATH
|
||||
$ curl -sL https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-x86_64-linux.tar.gz | tar xvz -C $INSTALL_DIR
|
||||
$ export PATH=$INSTALL_DIR/hurl-2.0.0:$PATH
|
||||
```
|
||||
|
||||
#### Debian / Ubuntu
|
||||
@ -856,8 +946,8 @@ $ export PATH=$INSTALL_DIR/hurl-1.8.0:$PATH
|
||||
For Debian / Ubuntu, Hurl can be installed using a binary .deb file provided in each Hurl release.
|
||||
|
||||
```shell
|
||||
$ curl -LO https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl_1.8.0_amd64.deb
|
||||
$ sudo apt update && apt install ./hurl_1.8.0_amd64.deb
|
||||
$ curl -LO https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl_2.0.0_amd64.deb
|
||||
$ sudo apt update && apt install ./hurl_2.0.0_amd64.deb
|
||||
```
|
||||
|
||||
#### Arch Linux / Manjaro
|
||||
@ -870,7 +960,7 @@ $ sudo apt update && apt install ./hurl_1.8.0_amd64.deb
|
||||
|
||||
### macOS
|
||||
|
||||
Precompiled binary is available at [hurl-1.8.0-x86_64-macos.tar.gz] for x86 CPUs and [hurl-1.8.0-arm64-macos.tar.gz] for ARM CPUS.
|
||||
Precompiled binary is available at [hurl-2.0.0-x86_64-macos.tar.gz] for x86 CPUs and [hurl-2.0.0-arm64-macos.tar.gz] for ARM CPUS.
|
||||
|
||||
#### Homebrew
|
||||
|
||||
@ -894,11 +984,11 @@ $ sudo pkg install hurl
|
||||
|
||||
#### Zip File
|
||||
|
||||
Hurl can be installed from a standalone zip file [hurl-1.8.0-win64.zip]. You will need to update your `PATH` variable.
|
||||
Hurl can be installed from a standalone zip file [hurl-2.0.0-win64.zip]. You will need to update your `PATH` variable.
|
||||
|
||||
#### Installer
|
||||
|
||||
An installer [hurl-1.8.0-win64-installer.exe] is also available.
|
||||
An installer [hurl-2.0.0-win64-installer.exe] is also available.
|
||||
|
||||
#### Chocolatey
|
||||
|
||||
@ -1011,7 +1101,7 @@ Please follow the [contrib on Windows section].
|
||||
[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
|
||||
[XML 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
|
||||
@ -1022,12 +1112,13 @@ Please follow the [contrib on Windows section].
|
||||
[curl]: https://curl.se
|
||||
[entry]: https://hurl.dev/docs/entry.html
|
||||
[`--test` option]: https://hurl.dev/docs/manual.html#test
|
||||
[Hurl templates]: https://hurl.dev/docs/templates.html
|
||||
[GitHub]: https://github.com/Orange-OpenSource/hurl
|
||||
[hurl-1.8.0-win64.zip]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-win64.zip
|
||||
[hurl-1.8.0-win64-installer.exe]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-win64-installer.exe
|
||||
[hurl-1.8.0-x86_64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-x86_64-macos.tar.gz
|
||||
[hurl-1.8.0-arm64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-arm64-macos.tar.gz
|
||||
[hurl-1.8.0-x86_64-linux.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.8.0/hurl-1.8.0-x86_64-linux.tar.gz
|
||||
[hurl-2.0.0-win64.zip]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-win64.zip
|
||||
[hurl-2.0.0-win64-installer.exe]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-win64-installer.exe
|
||||
[hurl-2.0.0-x86_64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-x86_64-macos.tar.gz
|
||||
[hurl-2.0.0-arm64-macos.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-arm64-macos.tar.gz
|
||||
[hurl-2.0.0-x86_64-linux.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/2.0.0/hurl-2.0.0-x86_64-linux.tar.gz
|
||||
[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
|
||||
|
@ -112,16 +112,16 @@ pub fn app(version: &str) -> Command {
|
||||
)
|
||||
.arg(
|
||||
clap::Arg::new("client_cert_file")
|
||||
.short('E')
|
||||
.long("cert")
|
||||
.value_name("FILE")
|
||||
.value_name("CERTIFICATE[:PASSWORD]")
|
||||
.help("Client certificate file and password")
|
||||
.num_args(1)
|
||||
.short('E')
|
||||
)
|
||||
.arg(
|
||||
clap::Arg::new("client_key_file")
|
||||
.long("key")
|
||||
.value_name("FILE")
|
||||
.value_name("KEY")
|
||||
.help("Private key file name")
|
||||
.num_args(1)
|
||||
)
|
||||
@ -343,7 +343,7 @@ pub fn app(version: &str) -> Command {
|
||||
.arg(
|
||||
clap::Arg::new("ssl_no_revoke")
|
||||
.long("ssl-no-revoke")
|
||||
.help("(Schannel) This option tells curl to disable certificate revocation checks. WARNING: this option loosens the SSL security, and by using this flag you ask for exactly that.")
|
||||
.help("(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.")
|
||||
.action(ArgAction::SetTrue)
|
||||
)
|
||||
.arg(
|
||||
|
Loading…
Reference in New Issue
Block a user