7568 lines
519 KiB
HTML
7568 lines
519 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<meta name="color-scheme" content="dark light" />
|
||
<title>Hurl 6.0.0</title>
|
||
<style>
|
||
body,
|
||
h1,
|
||
h2,
|
||
h3,
|
||
blockquote,
|
||
p,
|
||
ol,
|
||
ul,
|
||
pre,
|
||
figure {
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
|
||
html, html[data-theme=light] {
|
||
--background-color: #fff;
|
||
--primary-color: #ff0288;
|
||
--body-text: #222;
|
||
--secondary-color: royalblue;
|
||
--code-background-color: #f5f5f5;
|
||
--footer-background-color: #f0f0f0;
|
||
--separator-color: #b3b3b3;
|
||
--hurl-string: darkgreen;
|
||
--hurl-regex: darkgreen;
|
||
--hurl-name: darkgreen;
|
||
--hurl-number: blue;
|
||
--hurl-boolean: blue;
|
||
--hurl-null: blue;
|
||
--hurl-json: darkgreen;
|
||
--hurl-xml: darkgreen;
|
||
--hurl-hex: darkgreen;
|
||
--hurl-base64: darkgreen;
|
||
--hurl-filename: darkgreen;
|
||
--hurl-url: darkblue;
|
||
--hurl-method: #222;
|
||
--hurl-version: #222;
|
||
--hurl-section-header: darkmagenta;
|
||
--hurl-query-type: teal;
|
||
--hurl-filter-type: darkblue;
|
||
--hurl-not: darkblue;
|
||
--hurl-predicate-type: darkblue;
|
||
--hurl-comment: dimgray;
|
||
--bash-comment-single: dimgray;
|
||
--bash-keyword: teal;
|
||
--bash-literal-number: blue;
|
||
--bash-literal-string-double: darkgreen;
|
||
--bash-name-builtin: teal;
|
||
--shell-prompt: dimgray;
|
||
--ansi-green: darkgreen;
|
||
--ansi-gray: dimgray;
|
||
--ansi-bright-cyan: #35bbc7;
|
||
--ansi-bright-green: #33bd25;
|
||
--ansi-bright-red: #c33820;
|
||
--ansi-bright-blue: #4427b7;
|
||
--ansi-bright-magenta: #bb34b9;
|
||
--rust-comment-single: dimgray;
|
||
--rust-keyword: teal;
|
||
--rust-literal-number: blue;
|
||
--rust-literal-string-double: darkgreen;
|
||
--rust-literal-constant: blue;
|
||
--rust-name-builtin: teal;
|
||
--marked-background: #fdff00;
|
||
--marked-text: #222;
|
||
--row-n0: #f5f5f5;
|
||
--row-n1: #fff;
|
||
--schema-token-1: #0000ff;
|
||
--schema-token-2: #009900;
|
||
--schema-token-3: #ff8000;
|
||
--hurl-structure-0-front: #ff0288;
|
||
--hurl-structure-0-back: #f5f5f5;
|
||
--hurl-structure-1-front: #009900;
|
||
--hurl-structure-1-back: #f5f5f5;
|
||
--hurl-structure-2-front: #ff8000;
|
||
--hurl-structure-2-back: #f5f5f5;
|
||
--hurl-structure-3-front: dodgerblue;
|
||
--hurl-structure-3-back: #f5f5f5;
|
||
}
|
||
html .u-theme-img, html[data-theme=light] .u-theme-img {
|
||
display: inline-block;
|
||
}
|
||
html .u-theme-dark, html[data-theme=light] .u-theme-dark {
|
||
display: none;
|
||
}
|
||
|
||
html[data-theme=dark] {
|
||
--background-color: #19191c;
|
||
--primary-color: #ff0288;
|
||
--body-text: #c2c2c2;
|
||
--secondary-color: #34a7ff;
|
||
--code-background-color: #27272c;
|
||
--footer-background-color: #0a0a0a;
|
||
--separator-color: #444;
|
||
--hurl-string: forestgreen;
|
||
--hurl-regex: forestgreen;
|
||
--hurl-name: forestgreen;
|
||
--hurl-number: dodgerblue;
|
||
--hurl-boolean: dodgerblue;
|
||
--hurl-null: dodgerblue;
|
||
--hurl-json: forestgreen;
|
||
--hurl-xml: forestgreen;
|
||
--hurl-hex: forestgreen;
|
||
--hurl-base64: forestgreen;
|
||
--hurl-filename: forestgreen;
|
||
--hurl-url: cyan;
|
||
--hurl-method: orange;
|
||
--hurl-version: white;
|
||
--hurl-section-header: magenta;
|
||
--hurl-query-type: cyan;
|
||
--hurl-filter-type: orange;
|
||
--hurl-not: orange;
|
||
--hurl-predicate-type: orange;
|
||
--hurl-comment: dimgray;
|
||
--bash-comment-single: dimgray;
|
||
--bash-keyword: #ff8000;
|
||
--bash-literal-number: dodgerblue;
|
||
--bash-literal-string-double: forestgreen;
|
||
--bash-name-builtin: #ff8000;
|
||
--shell-prompt: dimgray;
|
||
--ansi-green: #00c300;
|
||
--ansi-gray: dimgray;
|
||
--ansi-bright-cyan: cyan;
|
||
--ansi-bright-green: lime;
|
||
--ansi-bright-red: #ff6e67;
|
||
--ansi-bright-blue: #7277cc;
|
||
--ansi-bright-magenta: #ff76ff;
|
||
--rust-comment-single: dimgray;
|
||
--rust-keyword: #ff8000;
|
||
--rust-literal-number: dodgerblue;
|
||
--rust-literal-string-double: forestgreen;
|
||
--rust-literal-constant: dodgerblue;
|
||
--rust-name-builtin: #ff8000;
|
||
--marked-background: #fdff00;
|
||
--marked-text: #222;
|
||
--row-n0: #27272c;
|
||
--row-n1: #19191c;
|
||
--schema-token-1: #007fff;
|
||
--schema-token-2: #009900;
|
||
--schema-token-3: #ff8000;
|
||
--hurl-structure-0-front: #ff0288;
|
||
--hurl-structure-0-back: #27272c;
|
||
--hurl-structure-1-front: #009900;
|
||
--hurl-structure-1-back: #27272c;
|
||
--hurl-structure-2-front: #ff8000;
|
||
--hurl-structure-2-back: #27272c;
|
||
--hurl-structure-3-front: dodgerblue;
|
||
--hurl-structure-3-back: #27272c;
|
||
}
|
||
html[data-theme=dark] .u-theme-light {
|
||
display: none;
|
||
}
|
||
html[data-theme=dark] .u-theme-dark {
|
||
display: inline-block;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
html, html[data-theme=dark] {
|
||
--background-color: #19191c;
|
||
--primary-color: #ff0288;
|
||
--body-text: #c2c2c2;
|
||
--secondary-color: #34a7ff;
|
||
--code-background-color: #27272c;
|
||
--footer-background-color: #0a0a0a;
|
||
--separator-color: #444;
|
||
--hurl-string: forestgreen;
|
||
--hurl-regex: forestgreen;
|
||
--hurl-name: forestgreen;
|
||
--hurl-number: dodgerblue;
|
||
--hurl-boolean: dodgerblue;
|
||
--hurl-null: dodgerblue;
|
||
--hurl-json: forestgreen;
|
||
--hurl-xml: forestgreen;
|
||
--hurl-hex: forestgreen;
|
||
--hurl-base64: forestgreen;
|
||
--hurl-filename: forestgreen;
|
||
--hurl-url: cyan;
|
||
--hurl-method: orange;
|
||
--hurl-version: white;
|
||
--hurl-section-header: magenta;
|
||
--hurl-query-type: cyan;
|
||
--hurl-filter-type: orange;
|
||
--hurl-not: orange;
|
||
--hurl-predicate-type: orange;
|
||
--hurl-comment: dimgray;
|
||
--bash-comment-single: dimgray;
|
||
--bash-keyword: #ff8000;
|
||
--bash-literal-number: dodgerblue;
|
||
--bash-literal-string-double: forestgreen;
|
||
--bash-name-builtin: #ff8000;
|
||
--shell-prompt: dimgray;
|
||
--ansi-green: #00c300;
|
||
--ansi-gray: dimgray;
|
||
--ansi-bright-cyan: cyan;
|
||
--ansi-bright-green: lime;
|
||
--ansi-bright-red: #ff6e67;
|
||
--ansi-bright-blue: #7277cc;
|
||
--ansi-bright-magenta: #ff76ff;
|
||
--rust-comment-single: dimgray;
|
||
--rust-keyword: #ff8000;
|
||
--rust-literal-number: dodgerblue;
|
||
--rust-literal-string-double: forestgreen;
|
||
--rust-literal-constant: dodgerblue;
|
||
--rust-name-builtin: #ff8000;
|
||
--marked-background: #fdff00;
|
||
--marked-text: #222;
|
||
--row-n0: #27272c;
|
||
--row-n1: #19191c;
|
||
--schema-token-1: #007fff;
|
||
--schema-token-2: #009900;
|
||
--schema-token-3: #ff8000;
|
||
--hurl-structure-0-front: #ff0288;
|
||
--hurl-structure-0-back: #27272c;
|
||
--hurl-structure-1-front: #009900;
|
||
--hurl-structure-1-back: #27272c;
|
||
--hurl-structure-2-front: #ff8000;
|
||
--hurl-structure-2-back: #27272c;
|
||
--hurl-structure-3-front: dodgerblue;
|
||
--hurl-structure-3-back: #27272c;
|
||
}
|
||
html .u-theme-light, html[data-theme=dark] .u-theme-light {
|
||
display: none;
|
||
}
|
||
html .u-theme-dark, html[data-theme=dark] .u-theme-dark {
|
||
display: inline-block;
|
||
}
|
||
html[data-theme=light] {
|
||
--background-color: #fff;
|
||
--primary-color: #ff0288;
|
||
--body-text: #222;
|
||
--secondary-color: royalblue;
|
||
--code-background-color: #f5f5f5;
|
||
--footer-background-color: #f0f0f0;
|
||
--separator-color: #b3b3b3;
|
||
--hurl-string: darkgreen;
|
||
--hurl-regex: darkgreen;
|
||
--hurl-name: darkgreen;
|
||
--hurl-number: blue;
|
||
--hurl-boolean: blue;
|
||
--hurl-null: blue;
|
||
--hurl-json: darkgreen;
|
||
--hurl-xml: darkgreen;
|
||
--hurl-hex: darkgreen;
|
||
--hurl-base64: darkgreen;
|
||
--hurl-filename: darkgreen;
|
||
--hurl-url: darkblue;
|
||
--hurl-method: #222;
|
||
--hurl-version: #222;
|
||
--hurl-section-header: darkmagenta;
|
||
--hurl-query-type: teal;
|
||
--hurl-filter-type: darkblue;
|
||
--hurl-not: darkblue;
|
||
--hurl-predicate-type: darkblue;
|
||
--hurl-comment: dimgray;
|
||
--bash-comment-single: dimgray;
|
||
--bash-keyword: teal;
|
||
--bash-literal-number: blue;
|
||
--bash-literal-string-double: darkgreen;
|
||
--bash-name-builtin: teal;
|
||
--shell-prompt: dimgray;
|
||
--ansi-green: darkgreen;
|
||
--ansi-gray: dimgray;
|
||
--ansi-bright-cyan: #35bbc7;
|
||
--ansi-bright-green: #33bd25;
|
||
--ansi-bright-red: #c33820;
|
||
--ansi-bright-blue: #4427b7;
|
||
--ansi-bright-magenta: #bb34b9;
|
||
--rust-comment-single: dimgray;
|
||
--rust-keyword: teal;
|
||
--rust-literal-number: blue;
|
||
--rust-literal-string-double: darkgreen;
|
||
--rust-literal-constant: blue;
|
||
--rust-name-builtin: teal;
|
||
--marked-background: #fdff00;
|
||
--marked-text: #222;
|
||
--row-n0: #f5f5f5;
|
||
--row-n1: #fff;
|
||
--schema-token-1: #0000ff;
|
||
--schema-token-2: #009900;
|
||
--schema-token-3: #ff8000;
|
||
--hurl-structure-0-front: #ff0288;
|
||
--hurl-structure-0-back: #f5f5f5;
|
||
--hurl-structure-1-front: #009900;
|
||
--hurl-structure-1-back: #f5f5f5;
|
||
--hurl-structure-2-front: #ff8000;
|
||
--hurl-structure-2-back: #f5f5f5;
|
||
--hurl-structure-3-front: dodgerblue;
|
||
--hurl-structure-3-back: #f5f5f5;
|
||
}
|
||
html[data-theme=light] .u-theme-img {
|
||
display: inline-block;
|
||
}
|
||
html[data-theme=light] .u-theme-dark {
|
||
display: none;
|
||
}
|
||
}
|
||
html {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
box-sizing: inherit;
|
||
}
|
||
|
||
.u-d-block-md {
|
||
display: none;
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.u-d-block-md {
|
||
display: block;
|
||
}
|
||
}
|
||
|
||
.u-d-block-lg {
|
||
display: none;
|
||
}
|
||
@media only screen and (min-width: 1024px) {
|
||
.u-d-block-lg {
|
||
display: block;
|
||
}
|
||
}
|
||
|
||
.u-d-none-md {
|
||
display: block;
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.u-d-none-md {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
.u-d-none {
|
||
display: none;
|
||
}
|
||
|
||
.u-underline {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.u-pointer {
|
||
cursor: pointer;
|
||
}
|
||
|
||
.u-align-center {
|
||
text-align: center;
|
||
}
|
||
|
||
.u-font-size-0 {
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.u-font-size-1 {
|
||
font-size: 1.125rem;
|
||
}
|
||
|
||
@media only screen and (min-width: 375px) {
|
||
.u-font-size-1-sm {
|
||
font-size: 1.125rem;
|
||
}
|
||
}
|
||
|
||
@media only screen and (min-width: 768px) {
|
||
.u-font-size-1-md {
|
||
font-size: 1.125rem;
|
||
}
|
||
}
|
||
|
||
.u-font-size-2 {
|
||
font-size: 1.25rem;
|
||
}
|
||
|
||
@media only screen and (min-width: 375px) {
|
||
.u-font-size-2-sm {
|
||
font-size: 1.25rem;
|
||
}
|
||
}
|
||
|
||
@media only screen and (min-width: 768px) {
|
||
.u-font-size-2-md {
|
||
font-size: 1.25rem;
|
||
}
|
||
}
|
||
|
||
.u-font-size-3 {
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
@media only screen and (min-width: 375px) {
|
||
.u-font-size-3-sm {
|
||
font-size: 1.5rem;
|
||
}
|
||
}
|
||
|
||
@media only screen and (min-width: 768px) {
|
||
.u-font-size-3-md {
|
||
font-size: 1.5rem;
|
||
}
|
||
}
|
||
|
||
.u-drop-shadow {
|
||
box-shadow: 0 4px 8px -8px gray;
|
||
}
|
||
|
||
.u-border {
|
||
border: 1px solid #b3b3b3;
|
||
border: 1px solid var(--separator-color);
|
||
}
|
||
|
||
.u-list-style-none {
|
||
list-style-type: none;
|
||
}
|
||
|
||
.u-invisible {
|
||
display: block;
|
||
position: absolute;
|
||
height: 0;
|
||
width: 0;
|
||
margin: 0;
|
||
padding: 0;
|
||
border: none;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.u-mt-4 {
|
||
margin-top: 2rem;
|
||
}
|
||
|
||
.u-greyed {
|
||
color: #8c8c8c;
|
||
}
|
||
|
||
.u-max-width-100 {
|
||
max-width: 100%;
|
||
}
|
||
|
||
html {
|
||
/* Add some space to the anchor */
|
||
scroll-padding-top: 20px;
|
||
/* Enable smooth scrolling for anchors */
|
||
scroll-behavior: smooth;
|
||
/* Disable smooth scrolling when users have prefers-reduced-motion enabled */
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
html {
|
||
/* Take fixed header into account */
|
||
scroll-padding-top: 92px;
|
||
}
|
||
}
|
||
@media screen and (prefers-reduced-motion: reduce) {
|
||
html {
|
||
scroll-behavior: auto;
|
||
}
|
||
}
|
||
|
||
body {
|
||
font-family: Helvetica, Arial, sans-serif;
|
||
font-size: 1.125rem; /* 18 px */
|
||
line-height: 1.4;
|
||
background-color: #fff;
|
||
background-color: var(--background-color);
|
||
color: #222;
|
||
color: var(--body-text);
|
||
}
|
||
|
||
a, a:visited, a:focus, a:hover, a:active {
|
||
color: royalblue;
|
||
color: var(--secondary-color);
|
||
}
|
||
|
||
a[aria-selected=true] {
|
||
color: #ff0288;
|
||
color: var(--primary-color);
|
||
font-weight: bold;
|
||
}
|
||
|
||
@font-face {
|
||
font-family: "Open Sans";
|
||
font-style: normal;
|
||
font-weight: 700;
|
||
font-stretch: 100%;
|
||
font-display: swap;
|
||
src: url("../font/opensans-700.woff2") format("woff2");
|
||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||
}
|
||
h1 {
|
||
font-family: "Open Sans", Helvetica, Arial, sans-serif;
|
||
}
|
||
h1 a, h1 a:visited, h1 a:focus, h1 a:hover, h1 a:active {
|
||
color: #ff0288;
|
||
color: var(--primary-color);
|
||
text-decoration: none;
|
||
}
|
||
|
||
h2 a, h2 a:visited, h2 a:focus, h2 a:hover, h2 a:active, h3 a, h3 a:visited, h3 a:focus, h3 a:hover, h3 a:active, h4 a, h4 a:visited, h4 a:focus, h4 a:hover, h4 a:active, h5 a, h5 a:visited, h5 a:focus, h5 a:hover, h5 a:active, h6 a, h6 a:visited, h6 a:focus, h6 a:hover, h6 a:active {
|
||
color: #222;
|
||
color: var(--body-text);
|
||
text-decoration: none;
|
||
}
|
||
|
||
h1, h2, h3, h4, h5, h6 {
|
||
line-height: 1.25;
|
||
}
|
||
|
||
h1 {
|
||
font-size: 2.5rem; /* 40px */
|
||
font-weight: 700;
|
||
color: #ff0288;
|
||
color: var(--primary-color);
|
||
margin: 3.5rem 0 1.5rem;
|
||
}
|
||
|
||
h1:first-of-type {
|
||
margin-top: 0;
|
||
}
|
||
|
||
h2 {
|
||
margin: 3rem 0 1rem;
|
||
}
|
||
|
||
h3 {
|
||
margin: 2.5rem 0 1rem;
|
||
}
|
||
|
||
p {
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
ul, ol {
|
||
padding-left: 40px;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.picture {
|
||
margin-top: 1rem;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
blockquote {
|
||
border-left: 4px solid;
|
||
border-left-color: #b3b3b3;
|
||
border-left-color: var(--separator-color);
|
||
padding-left: 1rem;
|
||
color: #8c8c8c;
|
||
margin-top: 1.5rem;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
select {
|
||
font-size: 0.8rem;
|
||
font-weight: bold;
|
||
-moz-appearance: none;
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
background-color: #fff;
|
||
background-color: var(--background-color);
|
||
border-style: solid;
|
||
border-width: 1px;
|
||
border-color: #b3b3b3;
|
||
padding: 6px 6px 6px 12px;
|
||
border-radius: 6px;
|
||
color: #b3b3b3;
|
||
max-width: 100%;
|
||
}
|
||
|
||
.emoji {
|
||
vertical-align: middle;
|
||
margin-top: -4px;
|
||
}
|
||
|
||
.top-nav {
|
||
padding: 1rem;
|
||
top: 0;
|
||
width: 100%;
|
||
margin: 0;
|
||
background-color: #fff;
|
||
background-color: var(--background-color);
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.top-nav {
|
||
position: fixed;
|
||
padding-left: 2rem;
|
||
padding-right: 2rem;
|
||
z-index: 1;
|
||
}
|
||
}
|
||
|
||
.top-nav-header {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
height: 37px;
|
||
}
|
||
|
||
.top-nav-logo {
|
||
margin-right: auto;
|
||
line-height: 44px;
|
||
}
|
||
|
||
.top-nav-logo-img source, .top-nav-logo-img img {
|
||
width: 120px;
|
||
}
|
||
@media only screen and (max-width: 320px) {
|
||
.top-nav-logo-img source, .top-nav-logo-img img {
|
||
width: 80px;
|
||
}
|
||
}
|
||
|
||
.top-nav-links {
|
||
display: flex;
|
||
font-weight: bold;
|
||
line-height: 37px;
|
||
color: royalblue;
|
||
color: var(--secondary-color);
|
||
}
|
||
|
||
.top-nav-link {
|
||
margin-left: 1rem;
|
||
fill: currentColor;
|
||
}
|
||
|
||
.top-nav-toc ul {
|
||
padding: 0;
|
||
}
|
||
.top-nav-toc ul li {
|
||
list-style-type: none;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.top-nav-link-a {
|
||
display: flex;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.svg-icon {
|
||
margin-top: 3px;
|
||
}
|
||
|
||
details summary {
|
||
cursor: pointer;
|
||
}
|
||
|
||
details summary > * {
|
||
display: inline;
|
||
}
|
||
|
||
/* Height of side nav is 100% less the height of top nav */
|
||
.side-nav {
|
||
position: fixed;
|
||
width: 250px;
|
||
height: calc(100vh - 69px);
|
||
overflow-y: auto;
|
||
padding: 1.5rem 1rem 2rem 2rem;
|
||
}
|
||
@media only screen and (min-width: 1024px) {
|
||
.side-nav {
|
||
width: 300px;
|
||
}
|
||
}
|
||
.side-nav details {
|
||
margin: 2.5rem 0 1rem;
|
||
}
|
||
.side-nav details summary {
|
||
margin-bottom: 1rem;
|
||
}
|
||
.side-nav details:first-child {
|
||
margin-top: 0;
|
||
}
|
||
.side-nav ul {
|
||
padding: 0;
|
||
}
|
||
.side-nav ul li {
|
||
list-style-type: none;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
footer {
|
||
margin: 0 -1rem 0 -1rem;
|
||
}
|
||
|
||
.footer-content {
|
||
display: flex;
|
||
margin-left: 0;
|
||
margin-top: 2.5rem;
|
||
padding: 2rem 1rem;
|
||
color: #8c8c8c;
|
||
border-top: 1px solid;
|
||
border-top-color: #b3b3b3;
|
||
border-top-color: var(--separator-color);
|
||
background-color: #f0f0f0;
|
||
background-color: var(--footer-background-color);
|
||
}
|
||
|
||
.footer-dev-by {
|
||
margin-left: auto;
|
||
}
|
||
|
||
.home {
|
||
display: flex;
|
||
padding: 0;
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.home {
|
||
margin-top: 72px;
|
||
}
|
||
}
|
||
|
||
.home-logo {
|
||
margin-top: 2rem;
|
||
margin-bottom: 4rem;
|
||
}
|
||
|
||
.home-picker {
|
||
text-align: right;
|
||
margin-top: 2rem;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.home-picker-label {
|
||
font-size: 0.8rem;
|
||
font-weight: bold;
|
||
color: #b3b3b3;
|
||
}
|
||
|
||
.home-sample {
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.home-content {
|
||
margin-left: 0;
|
||
padding: 1rem 1rem 0 1rem;
|
||
width: 100%;
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.home-content {
|
||
margin-left: 250px;
|
||
width: calc(100% - 250px);
|
||
}
|
||
}
|
||
@media only screen and (min-width: 1024px) {
|
||
.home-content {
|
||
margin-left: 300px;
|
||
width: calc(85% - 300px);
|
||
}
|
||
}
|
||
|
||
#home-demo {
|
||
margin-top: 1.5rem;
|
||
margin-bottom: 2.5rem;
|
||
}
|
||
|
||
.home-content-col {
|
||
max-width: 800px;
|
||
margin-left: auto;
|
||
margin-right: auto;
|
||
}
|
||
|
||
.showcase-container {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
list-style: none;
|
||
padding: 0;
|
||
}
|
||
|
||
.showcase-item {
|
||
width: 100%;
|
||
margin: 0;
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.showcase-item {
|
||
width: 31%;
|
||
margin-left: 0.5rem;
|
||
margin-right: 0.5rem;
|
||
}
|
||
}
|
||
|
||
@media only screen and (min-width: 768px) {
|
||
.showcase-item:first-child {
|
||
margin-left: 0;
|
||
}
|
||
}
|
||
|
||
@media only screen and (min-width: 768px) {
|
||
.showcase-item:last-child {
|
||
margin-right: 0;
|
||
}
|
||
}
|
||
|
||
.showcase-item-title {
|
||
margin-top: 1rem;
|
||
}
|
||
|
||
.doc {
|
||
display: flex;
|
||
padding: 0;
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.doc {
|
||
margin-top: 72px;
|
||
}
|
||
}
|
||
|
||
.doc-content {
|
||
margin-left: 0;
|
||
padding: 1rem 1rem 0 1rem;
|
||
width: 100%;
|
||
min-height: calc(100vh - 244px);
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.doc-content {
|
||
margin-left: 250px;
|
||
width: calc(100% - 250px);
|
||
}
|
||
}
|
||
@media only screen and (min-width: 1024px) {
|
||
.doc-content {
|
||
margin-left: 300px;
|
||
width: calc(85% - 300px);
|
||
}
|
||
}
|
||
|
||
.doc-content-col {
|
||
max-width: 800px;
|
||
margin-left: auto;
|
||
margin-right: auto;
|
||
}
|
||
|
||
.doc-content-edit-page {
|
||
text-align: right;
|
||
margin: 2rem 0;
|
||
}
|
||
|
||
.doc-content-browse {
|
||
display: flex;
|
||
margin-top: 2.5rem;
|
||
}
|
||
|
||
.doc-content-browse-next {
|
||
margin-left: auto;
|
||
}
|
||
|
||
.doc-toc {
|
||
position: fixed;
|
||
right: 0;
|
||
font-size: 0.9rem;
|
||
padding: 30px 1rem 2rem 1rem;
|
||
color: #b3b3b3;
|
||
width: 15%;
|
||
max-height: calc(100% - 64px);
|
||
overflow-y: auto;
|
||
}
|
||
.doc-toc h3:first-child {
|
||
margin-top: 0;
|
||
}
|
||
.doc-toc ul {
|
||
padding: 0;
|
||
}
|
||
.doc-toc ul li {
|
||
list-style-type: none;
|
||
margin: 0.5rem 0;
|
||
}
|
||
.doc-toc ul li ul li {
|
||
margin-left: 0.5rem;
|
||
}
|
||
.doc-toc a, .doc-toc a:visited, .doc-toc a:focus, .doc-toc a:hover, .doc-toc a:active {
|
||
color: #8c8c8c;
|
||
width: 100%;
|
||
display: inline-block;
|
||
border-right-width: 4px;
|
||
border-right-style: solid;
|
||
border-right-color: #fff;
|
||
border-right-color: var(--background-color);
|
||
}
|
||
.doc-toc .visible > a {
|
||
color: #ff0288;
|
||
color: var(--primary-color);
|
||
border-right-color: #ff0288;
|
||
border-right-color: var(--primary-color);
|
||
}
|
||
|
||
.doc-picker {
|
||
text-align: right;
|
||
margin-top: 1rem;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.player {
|
||
margin: 0 auto;
|
||
max-width: 800px;
|
||
padding: 1rem 1rem 0 1rem;
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.player {
|
||
margin-top: 72px;
|
||
padding: 1rem 2rem 0 2rem;
|
||
}
|
||
}
|
||
|
||
.player-content {
|
||
min-height: calc(100vh - 202px);
|
||
}
|
||
|
||
.search {
|
||
margin: 0 auto;
|
||
max-width: 800px;
|
||
padding: 1rem 1rem 0 1rem;
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.search {
|
||
margin-top: 72px;
|
||
padding: 1rem 2rem 0 2rem;
|
||
}
|
||
}
|
||
.search ul {
|
||
padding: 0;
|
||
}
|
||
.search ul li {
|
||
margin-bottom: 2.5rem;
|
||
margin-left: 2rem;
|
||
}
|
||
|
||
.search-content {
|
||
min-height: calc(100vh - 202px);
|
||
}
|
||
|
||
.search-results summary {
|
||
margin-top: 2rem;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.search-result-link {
|
||
font-size: 1.375rem;
|
||
font-weight: bold;
|
||
}
|
||
|
||
#search-input {
|
||
font-size: 1.125rem; /* 18 px */
|
||
min-width: 50%;
|
||
}
|
||
|
||
.blog {
|
||
margin: 0 auto;
|
||
max-width: 800px;
|
||
padding: 1rem 1rem 0 1rem;
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.blog {
|
||
margin-top: 72px;
|
||
padding: 1rem 2rem 0 2rem;
|
||
}
|
||
}
|
||
|
||
.blog-content {
|
||
min-height: calc(100vh - 276px);
|
||
}
|
||
|
||
.blog-post-link {
|
||
margin-left: 1rem;
|
||
}
|
||
|
||
.blog-post-date {
|
||
color: #b3b3b3;
|
||
line-height: 1.25;
|
||
font-size: 1.2rem; /* 40px */
|
||
margin: 1.5rem 0;
|
||
text-align: right;
|
||
}
|
||
|
||
.blog-feed-link {
|
||
display: flex;
|
||
justify-content: end;
|
||
margin: 2rem 0;
|
||
}
|
||
|
||
.blog-feed-link .svg-icon {
|
||
color: royalblue;
|
||
color: var(--secondary-color);
|
||
}
|
||
|
||
.marked {
|
||
background-color: #fdff00;
|
||
background-color: var(--marked-background);
|
||
color: #222;
|
||
color: var(--marked-text);
|
||
font-weight: bold;
|
||
}
|
||
|
||
.drawing {
|
||
text-align: center;
|
||
}
|
||
.drawing source, .drawing img {
|
||
max-width: 100%;
|
||
}
|
||
table {
|
||
display: block;
|
||
width: 100%;
|
||
max-width: 100%;
|
||
overflow: auto;
|
||
border-collapse: collapse;
|
||
margin-top: 2rem;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
th, td {
|
||
border-width: 1px;
|
||
border-style: solid;
|
||
border-color: #b3b3b3;
|
||
border-color: var(--separator-color);
|
||
}
|
||
|
||
th {
|
||
background-color: #f5f5f5;
|
||
background-color: var(--row-n0);
|
||
padding: 12px 1rem;
|
||
}
|
||
|
||
td {
|
||
padding: 12px 1rem;
|
||
}
|
||
|
||
table tr:nth-child(2n) {
|
||
background-color: #f5f5f5;
|
||
background-color: var(--row-n0);
|
||
}
|
||
|
||
table tr:nth-child(2n+1) {
|
||
background-color: #fff;
|
||
background-color: var(--row-n1);
|
||
}
|
||
|
||
svg.defs-only {
|
||
display: block;
|
||
position: absolute;
|
||
height: 0;
|
||
width: 0;
|
||
margin: 0;
|
||
padding: 0;
|
||
border: none;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* Temporary id, to clean and remove*/
|
||
#running-test-1 {
|
||
max-width: 670px;
|
||
width: 100%;
|
||
}
|
||
|
||
#running-test-2 {
|
||
max-width: 380px;
|
||
width: 100%;
|
||
}
|
||
|
||
html, html[data-theme=light] {
|
||
--background-color: #fff;
|
||
--primary-color: #ff0288;
|
||
--body-text: #222;
|
||
--secondary-color: royalblue;
|
||
--code-background-color: #f5f5f5;
|
||
--footer-background-color: #f0f0f0;
|
||
--separator-color: #b3b3b3;
|
||
--hurl-string: darkgreen;
|
||
--hurl-regex: darkgreen;
|
||
--hurl-name: darkgreen;
|
||
--hurl-number: blue;
|
||
--hurl-boolean: blue;
|
||
--hurl-null: blue;
|
||
--hurl-json: darkgreen;
|
||
--hurl-xml: darkgreen;
|
||
--hurl-hex: darkgreen;
|
||
--hurl-base64: darkgreen;
|
||
--hurl-filename: darkgreen;
|
||
--hurl-url: darkblue;
|
||
--hurl-method: #222;
|
||
--hurl-version: #222;
|
||
--hurl-section-header: darkmagenta;
|
||
--hurl-query-type: teal;
|
||
--hurl-filter-type: darkblue;
|
||
--hurl-not: darkblue;
|
||
--hurl-predicate-type: darkblue;
|
||
--hurl-comment: dimgray;
|
||
--bash-comment-single: dimgray;
|
||
--bash-keyword: teal;
|
||
--bash-literal-number: blue;
|
||
--bash-literal-string-double: darkgreen;
|
||
--bash-name-builtin: teal;
|
||
--shell-prompt: dimgray;
|
||
--ansi-green: darkgreen;
|
||
--ansi-gray: dimgray;
|
||
--ansi-bright-cyan: #35bbc7;
|
||
--ansi-bright-green: #33bd25;
|
||
--ansi-bright-red: #c33820;
|
||
--ansi-bright-blue: #4427b7;
|
||
--ansi-bright-magenta: #bb34b9;
|
||
--rust-comment-single: dimgray;
|
||
--rust-keyword: teal;
|
||
--rust-literal-number: blue;
|
||
--rust-literal-string-double: darkgreen;
|
||
--rust-literal-constant: blue;
|
||
--rust-name-builtin: teal;
|
||
--marked-background: #fdff00;
|
||
--marked-text: #222;
|
||
--row-n0: #f5f5f5;
|
||
--row-n1: #fff;
|
||
--schema-token-1: #0000ff;
|
||
--schema-token-2: #009900;
|
||
--schema-token-3: #ff8000;
|
||
--hurl-structure-0-front: #ff0288;
|
||
--hurl-structure-0-back: #f5f5f5;
|
||
--hurl-structure-1-front: #009900;
|
||
--hurl-structure-1-back: #f5f5f5;
|
||
--hurl-structure-2-front: #ff8000;
|
||
--hurl-structure-2-back: #f5f5f5;
|
||
--hurl-structure-3-front: dodgerblue;
|
||
--hurl-structure-3-back: #f5f5f5;
|
||
}
|
||
html .u-theme-img, html[data-theme=light] .u-theme-img {
|
||
display: inline-block;
|
||
}
|
||
html .u-theme-dark, html[data-theme=light] .u-theme-dark {
|
||
display: none;
|
||
}
|
||
|
||
html[data-theme=dark] {
|
||
--background-color: #19191c;
|
||
--primary-color: #ff0288;
|
||
--body-text: #c2c2c2;
|
||
--secondary-color: #34a7ff;
|
||
--code-background-color: #27272c;
|
||
--footer-background-color: #0a0a0a;
|
||
--separator-color: #444;
|
||
--hurl-string: forestgreen;
|
||
--hurl-regex: forestgreen;
|
||
--hurl-name: forestgreen;
|
||
--hurl-number: dodgerblue;
|
||
--hurl-boolean: dodgerblue;
|
||
--hurl-null: dodgerblue;
|
||
--hurl-json: forestgreen;
|
||
--hurl-xml: forestgreen;
|
||
--hurl-hex: forestgreen;
|
||
--hurl-base64: forestgreen;
|
||
--hurl-filename: forestgreen;
|
||
--hurl-url: cyan;
|
||
--hurl-method: orange;
|
||
--hurl-version: white;
|
||
--hurl-section-header: magenta;
|
||
--hurl-query-type: cyan;
|
||
--hurl-filter-type: orange;
|
||
--hurl-not: orange;
|
||
--hurl-predicate-type: orange;
|
||
--hurl-comment: dimgray;
|
||
--bash-comment-single: dimgray;
|
||
--bash-keyword: #ff8000;
|
||
--bash-literal-number: dodgerblue;
|
||
--bash-literal-string-double: forestgreen;
|
||
--bash-name-builtin: #ff8000;
|
||
--shell-prompt: dimgray;
|
||
--ansi-green: #00c300;
|
||
--ansi-gray: dimgray;
|
||
--ansi-bright-cyan: cyan;
|
||
--ansi-bright-green: lime;
|
||
--ansi-bright-red: #ff6e67;
|
||
--ansi-bright-blue: #7277cc;
|
||
--ansi-bright-magenta: #ff76ff;
|
||
--rust-comment-single: dimgray;
|
||
--rust-keyword: #ff8000;
|
||
--rust-literal-number: dodgerblue;
|
||
--rust-literal-string-double: forestgreen;
|
||
--rust-literal-constant: dodgerblue;
|
||
--rust-name-builtin: #ff8000;
|
||
--marked-background: #fdff00;
|
||
--marked-text: #222;
|
||
--row-n0: #27272c;
|
||
--row-n1: #19191c;
|
||
--schema-token-1: #007fff;
|
||
--schema-token-2: #009900;
|
||
--schema-token-3: #ff8000;
|
||
--hurl-structure-0-front: #ff0288;
|
||
--hurl-structure-0-back: #27272c;
|
||
--hurl-structure-1-front: #009900;
|
||
--hurl-structure-1-back: #27272c;
|
||
--hurl-structure-2-front: #ff8000;
|
||
--hurl-structure-2-back: #27272c;
|
||
--hurl-structure-3-front: dodgerblue;
|
||
--hurl-structure-3-back: #27272c;
|
||
}
|
||
html[data-theme=dark] .u-theme-light {
|
||
display: none;
|
||
}
|
||
html[data-theme=dark] .u-theme-dark {
|
||
display: inline-block;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
html, html[data-theme=dark] {
|
||
--background-color: #19191c;
|
||
--primary-color: #ff0288;
|
||
--body-text: #c2c2c2;
|
||
--secondary-color: #34a7ff;
|
||
--code-background-color: #27272c;
|
||
--footer-background-color: #0a0a0a;
|
||
--separator-color: #444;
|
||
--hurl-string: forestgreen;
|
||
--hurl-regex: forestgreen;
|
||
--hurl-name: forestgreen;
|
||
--hurl-number: dodgerblue;
|
||
--hurl-boolean: dodgerblue;
|
||
--hurl-null: dodgerblue;
|
||
--hurl-json: forestgreen;
|
||
--hurl-xml: forestgreen;
|
||
--hurl-hex: forestgreen;
|
||
--hurl-base64: forestgreen;
|
||
--hurl-filename: forestgreen;
|
||
--hurl-url: cyan;
|
||
--hurl-method: orange;
|
||
--hurl-version: white;
|
||
--hurl-section-header: magenta;
|
||
--hurl-query-type: cyan;
|
||
--hurl-filter-type: orange;
|
||
--hurl-not: orange;
|
||
--hurl-predicate-type: orange;
|
||
--hurl-comment: dimgray;
|
||
--bash-comment-single: dimgray;
|
||
--bash-keyword: #ff8000;
|
||
--bash-literal-number: dodgerblue;
|
||
--bash-literal-string-double: forestgreen;
|
||
--bash-name-builtin: #ff8000;
|
||
--shell-prompt: dimgray;
|
||
--ansi-green: #00c300;
|
||
--ansi-gray: dimgray;
|
||
--ansi-bright-cyan: cyan;
|
||
--ansi-bright-green: lime;
|
||
--ansi-bright-red: #ff6e67;
|
||
--ansi-bright-blue: #7277cc;
|
||
--ansi-bright-magenta: #ff76ff;
|
||
--rust-comment-single: dimgray;
|
||
--rust-keyword: #ff8000;
|
||
--rust-literal-number: dodgerblue;
|
||
--rust-literal-string-double: forestgreen;
|
||
--rust-literal-constant: dodgerblue;
|
||
--rust-name-builtin: #ff8000;
|
||
--marked-background: #fdff00;
|
||
--marked-text: #222;
|
||
--row-n0: #27272c;
|
||
--row-n1: #19191c;
|
||
--schema-token-1: #007fff;
|
||
--schema-token-2: #009900;
|
||
--schema-token-3: #ff8000;
|
||
--hurl-structure-0-front: #ff0288;
|
||
--hurl-structure-0-back: #27272c;
|
||
--hurl-structure-1-front: #009900;
|
||
--hurl-structure-1-back: #27272c;
|
||
--hurl-structure-2-front: #ff8000;
|
||
--hurl-structure-2-back: #27272c;
|
||
--hurl-structure-3-front: dodgerblue;
|
||
--hurl-structure-3-back: #27272c;
|
||
}
|
||
html .u-theme-light, html[data-theme=dark] .u-theme-light {
|
||
display: none;
|
||
}
|
||
html .u-theme-dark, html[data-theme=dark] .u-theme-dark {
|
||
display: inline-block;
|
||
}
|
||
html[data-theme=light] {
|
||
--background-color: #fff;
|
||
--primary-color: #ff0288;
|
||
--body-text: #222;
|
||
--secondary-color: royalblue;
|
||
--code-background-color: #f5f5f5;
|
||
--footer-background-color: #f0f0f0;
|
||
--separator-color: #b3b3b3;
|
||
--hurl-string: darkgreen;
|
||
--hurl-regex: darkgreen;
|
||
--hurl-name: darkgreen;
|
||
--hurl-number: blue;
|
||
--hurl-boolean: blue;
|
||
--hurl-null: blue;
|
||
--hurl-json: darkgreen;
|
||
--hurl-xml: darkgreen;
|
||
--hurl-hex: darkgreen;
|
||
--hurl-base64: darkgreen;
|
||
--hurl-filename: darkgreen;
|
||
--hurl-url: darkblue;
|
||
--hurl-method: #222;
|
||
--hurl-version: #222;
|
||
--hurl-section-header: darkmagenta;
|
||
--hurl-query-type: teal;
|
||
--hurl-filter-type: darkblue;
|
||
--hurl-not: darkblue;
|
||
--hurl-predicate-type: darkblue;
|
||
--hurl-comment: dimgray;
|
||
--bash-comment-single: dimgray;
|
||
--bash-keyword: teal;
|
||
--bash-literal-number: blue;
|
||
--bash-literal-string-double: darkgreen;
|
||
--bash-name-builtin: teal;
|
||
--shell-prompt: dimgray;
|
||
--ansi-green: darkgreen;
|
||
--ansi-gray: dimgray;
|
||
--ansi-bright-cyan: #35bbc7;
|
||
--ansi-bright-green: #33bd25;
|
||
--ansi-bright-red: #c33820;
|
||
--ansi-bright-blue: #4427b7;
|
||
--ansi-bright-magenta: #bb34b9;
|
||
--rust-comment-single: dimgray;
|
||
--rust-keyword: teal;
|
||
--rust-literal-number: blue;
|
||
--rust-literal-string-double: darkgreen;
|
||
--rust-literal-constant: blue;
|
||
--rust-name-builtin: teal;
|
||
--marked-background: #fdff00;
|
||
--marked-text: #222;
|
||
--row-n0: #f5f5f5;
|
||
--row-n1: #fff;
|
||
--schema-token-1: #0000ff;
|
||
--schema-token-2: #009900;
|
||
--schema-token-3: #ff8000;
|
||
--hurl-structure-0-front: #ff0288;
|
||
--hurl-structure-0-back: #f5f5f5;
|
||
--hurl-structure-1-front: #009900;
|
||
--hurl-structure-1-back: #f5f5f5;
|
||
--hurl-structure-2-front: #ff8000;
|
||
--hurl-structure-2-back: #f5f5f5;
|
||
--hurl-structure-3-front: dodgerblue;
|
||
--hurl-structure-3-back: #f5f5f5;
|
||
}
|
||
html[data-theme=light] .u-theme-img {
|
||
display: inline-block;
|
||
}
|
||
html[data-theme=light] .u-theme-dark {
|
||
display: none;
|
||
}
|
||
}
|
||
pre {
|
||
background-color: #f5f5f5;
|
||
background-color: var(--code-background-color);
|
||
margin: 1rem 0;
|
||
padding: 1rem;
|
||
word-wrap: normal;
|
||
overflow-x: auto;
|
||
white-space: pre;
|
||
}
|
||
|
||
pre, code {
|
||
font-family: Menlo, Monaco, Consolas, "Liberation Mono", " Courier New", monospace;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.language-hurl {
|
||
color: #222;
|
||
color: var(--body-text);
|
||
}
|
||
.language-hurl .string {
|
||
color: darkgreen;
|
||
color: var(--hurl-string);
|
||
}
|
||
.language-hurl .name {
|
||
color: darkgreen;
|
||
color: var(--hurl-name);
|
||
}
|
||
.language-hurl .multiline {
|
||
color: darkgreen;
|
||
color: var(--hurl-string);
|
||
}
|
||
.language-hurl .number {
|
||
color: blue;
|
||
color: var(--hurl-number);
|
||
}
|
||
.language-hurl .unit {
|
||
color: blue;
|
||
color: var(--hurl-number);
|
||
}
|
||
.language-hurl .boolean {
|
||
color: blue;
|
||
color: var(--hurl-boolean);
|
||
}
|
||
.language-hurl .null {
|
||
color: blue;
|
||
color: var(--hurl-null);
|
||
}
|
||
.language-hurl .json {
|
||
color: darkgreen;
|
||
color: var(--hurl-json);
|
||
}
|
||
.language-hurl .xml {
|
||
color: darkgreen;
|
||
color: var(--hurl-xml);
|
||
}
|
||
.language-hurl .hex {
|
||
color: darkgreen;
|
||
color: var(--hurl-hex);
|
||
}
|
||
.language-hurl .base64 {
|
||
color: darkgreen;
|
||
color: var(--hurl-base64);
|
||
}
|
||
.language-hurl .filename {
|
||
color: darkgreen;
|
||
color: var(--hurl-filename);
|
||
}
|
||
.language-hurl .url {
|
||
color: darkblue;
|
||
color: var(--hurl-url);
|
||
}
|
||
.language-hurl .method {
|
||
color: #222;
|
||
color: var(--hurl-method);
|
||
}
|
||
.language-hurl .version {
|
||
color: #222;
|
||
color: var(--hurl-version);
|
||
}
|
||
.language-hurl .regex {
|
||
color: darkgreen;
|
||
color: var(--hurl-regex);
|
||
}
|
||
.language-hurl .section-header {
|
||
color: darkmagenta;
|
||
color: var(--hurl-section-header);
|
||
}
|
||
.language-hurl .query-type {
|
||
color: teal;
|
||
color: var(--hurl-query-type);
|
||
}
|
||
.language-hurl .filter-type {
|
||
color: darkblue;
|
||
color: var(--hurl-filter-type);
|
||
}
|
||
.language-hurl .not {
|
||
color: darkblue;
|
||
color: var(--hurl-not);
|
||
}
|
||
.language-hurl .predicate-type {
|
||
color: darkblue;
|
||
color: var(--hurl-predicate-type);
|
||
}
|
||
.language-hurl .comment {
|
||
color: dimgray;
|
||
color: var(--hurl-comment);
|
||
}
|
||
|
||
.language-bash .comment-hashbang {
|
||
font-weight: bold;
|
||
}
|
||
.language-bash .comment-single {
|
||
color: dimgray;
|
||
color: var(--bash-comment-single);
|
||
}
|
||
.language-bash .keyword {
|
||
color: teal;
|
||
color: var(--bash-keyword);
|
||
}
|
||
.language-bash .literal-number {
|
||
color: blue;
|
||
color: var(--bash-literal-number);
|
||
}
|
||
.language-bash .literal-string-double {
|
||
color: darkgreen;
|
||
color: var(--bash-literal-string-double);
|
||
}
|
||
.language-bash .name-builtin {
|
||
color: teal;
|
||
color: var(--bash-name-builtin);
|
||
}
|
||
|
||
.language-shell .prompt {
|
||
pointer-events: none;
|
||
-webkit-user-select: none;
|
||
-webkit-touch-callout: none;
|
||
-moz-user-select: none;
|
||
-ms-user-select: none;
|
||
user-select: none;
|
||
color: dimgray;
|
||
color: var(--shell-prompt);
|
||
}
|
||
.language-shell .bold {
|
||
font-weight: bold;
|
||
}
|
||
.language-shell .green {
|
||
color: darkgreen;
|
||
color: var(--ansi-green);
|
||
}
|
||
.language-shell .gray {
|
||
color: dimgray;
|
||
color: var(--ansi-gray);
|
||
}
|
||
.language-shell .bright-cyan {
|
||
color: #35bbc7;
|
||
color: var(--ansi-bright-cyan);
|
||
font-weight: bold;
|
||
}
|
||
.language-shell .bright-green {
|
||
color: #33bd25;
|
||
color: var(--ansi-bright-green);
|
||
font-weight: bold;
|
||
}
|
||
.language-shell .bright-red {
|
||
color: #c33820;
|
||
color: var(--ansi-bright-red);
|
||
font-weight: bold;
|
||
}
|
||
.language-shell .bright-blue {
|
||
color: #4427b7;
|
||
color: var(--ansi-bright-blue);
|
||
font-weight: bold;
|
||
}
|
||
.language-shell .bright-magenta {
|
||
color: #bb34b9;
|
||
color: var(--ansi-bright-magenta);
|
||
font-weight: bold;
|
||
}
|
||
|
||
.language-rust .comment-single {
|
||
color: dimgray;
|
||
color: var(--rust-comment-single);
|
||
}
|
||
.language-rust .keyword {
|
||
color: teal;
|
||
color: var(--rust-keyword);
|
||
}
|
||
.language-rust .literal-number {
|
||
color: blue;
|
||
color: var(--rust-literal-number);
|
||
}
|
||
.language-rust .literal-string-double {
|
||
color: darkgreen;
|
||
color: var(--rust-literal-string-double);
|
||
}
|
||
.language-rust .literal-constant {
|
||
color: blue;
|
||
color: var(--rust-literal-constant);
|
||
}
|
||
.language-rust .name-builtin {
|
||
color: teal;
|
||
color: var(--rust-name-builtin);
|
||
}
|
||
|
||
/*
|
||
.grammar {
|
||
font-family: Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
|
||
margin-top: $m4;
|
||
margin-bottom: $m4;
|
||
.rule {
|
||
display: table;
|
||
margin-bottom: 20px;
|
||
}
|
||
.non-terminal {
|
||
display: table-cell;
|
||
white-space: nowrap;
|
||
font-weight: bold;
|
||
}
|
||
.terminal {
|
||
color: #009c00;
|
||
}
|
||
.definition {
|
||
color: darkcyan;
|
||
}
|
||
.tokens {
|
||
display: table-cell;
|
||
width: 100%;
|
||
}
|
||
}
|
||
*/
|
||
.grammar-usedby {
|
||
color: #999;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.grammar-ruleset {
|
||
margin-bottom: 40px;
|
||
}
|
||
|
||
.grammar-rule {
|
||
font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||
margin-top: 10px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.grammar-rule-id {
|
||
font-weight: bold;
|
||
}
|
||
|
||
.grammar-rule-expression {
|
||
margin-left: 20px;
|
||
}
|
||
|
||
.grammar-literal {
|
||
color: #009c00;
|
||
}
|
||
|
||
.grammar-regex {
|
||
color: darkcyan;
|
||
}
|
||
|
||
html, html[data-theme=light] {
|
||
--background-color: #fff;
|
||
--primary-color: #ff0288;
|
||
--body-text: #222;
|
||
--secondary-color: royalblue;
|
||
--code-background-color: #f5f5f5;
|
||
--footer-background-color: #f0f0f0;
|
||
--separator-color: #b3b3b3;
|
||
--hurl-string: darkgreen;
|
||
--hurl-regex: darkgreen;
|
||
--hurl-name: darkgreen;
|
||
--hurl-number: blue;
|
||
--hurl-boolean: blue;
|
||
--hurl-null: blue;
|
||
--hurl-json: darkgreen;
|
||
--hurl-xml: darkgreen;
|
||
--hurl-hex: darkgreen;
|
||
--hurl-base64: darkgreen;
|
||
--hurl-filename: darkgreen;
|
||
--hurl-url: darkblue;
|
||
--hurl-method: #222;
|
||
--hurl-version: #222;
|
||
--hurl-section-header: darkmagenta;
|
||
--hurl-query-type: teal;
|
||
--hurl-filter-type: darkblue;
|
||
--hurl-not: darkblue;
|
||
--hurl-predicate-type: darkblue;
|
||
--hurl-comment: dimgray;
|
||
--bash-comment-single: dimgray;
|
||
--bash-keyword: teal;
|
||
--bash-literal-number: blue;
|
||
--bash-literal-string-double: darkgreen;
|
||
--bash-name-builtin: teal;
|
||
--shell-prompt: dimgray;
|
||
--ansi-green: darkgreen;
|
||
--ansi-gray: dimgray;
|
||
--ansi-bright-cyan: #35bbc7;
|
||
--ansi-bright-green: #33bd25;
|
||
--ansi-bright-red: #c33820;
|
||
--ansi-bright-blue: #4427b7;
|
||
--ansi-bright-magenta: #bb34b9;
|
||
--rust-comment-single: dimgray;
|
||
--rust-keyword: teal;
|
||
--rust-literal-number: blue;
|
||
--rust-literal-string-double: darkgreen;
|
||
--rust-literal-constant: blue;
|
||
--rust-name-builtin: teal;
|
||
--marked-background: #fdff00;
|
||
--marked-text: #222;
|
||
--row-n0: #f5f5f5;
|
||
--row-n1: #fff;
|
||
--schema-token-1: #0000ff;
|
||
--schema-token-2: #009900;
|
||
--schema-token-3: #ff8000;
|
||
--hurl-structure-0-front: #ff0288;
|
||
--hurl-structure-0-back: #f5f5f5;
|
||
--hurl-structure-1-front: #009900;
|
||
--hurl-structure-1-back: #f5f5f5;
|
||
--hurl-structure-2-front: #ff8000;
|
||
--hurl-structure-2-back: #f5f5f5;
|
||
--hurl-structure-3-front: dodgerblue;
|
||
--hurl-structure-3-back: #f5f5f5;
|
||
}
|
||
html .u-theme-img, html[data-theme=light] .u-theme-img {
|
||
display: inline-block;
|
||
}
|
||
html .u-theme-dark, html[data-theme=light] .u-theme-dark {
|
||
display: none;
|
||
}
|
||
|
||
html[data-theme=dark] {
|
||
--background-color: #19191c;
|
||
--primary-color: #ff0288;
|
||
--body-text: #c2c2c2;
|
||
--secondary-color: #34a7ff;
|
||
--code-background-color: #27272c;
|
||
--footer-background-color: #0a0a0a;
|
||
--separator-color: #444;
|
||
--hurl-string: forestgreen;
|
||
--hurl-regex: forestgreen;
|
||
--hurl-name: forestgreen;
|
||
--hurl-number: dodgerblue;
|
||
--hurl-boolean: dodgerblue;
|
||
--hurl-null: dodgerblue;
|
||
--hurl-json: forestgreen;
|
||
--hurl-xml: forestgreen;
|
||
--hurl-hex: forestgreen;
|
||
--hurl-base64: forestgreen;
|
||
--hurl-filename: forestgreen;
|
||
--hurl-url: cyan;
|
||
--hurl-method: orange;
|
||
--hurl-version: white;
|
||
--hurl-section-header: magenta;
|
||
--hurl-query-type: cyan;
|
||
--hurl-filter-type: orange;
|
||
--hurl-not: orange;
|
||
--hurl-predicate-type: orange;
|
||
--hurl-comment: dimgray;
|
||
--bash-comment-single: dimgray;
|
||
--bash-keyword: #ff8000;
|
||
--bash-literal-number: dodgerblue;
|
||
--bash-literal-string-double: forestgreen;
|
||
--bash-name-builtin: #ff8000;
|
||
--shell-prompt: dimgray;
|
||
--ansi-green: #00c300;
|
||
--ansi-gray: dimgray;
|
||
--ansi-bright-cyan: cyan;
|
||
--ansi-bright-green: lime;
|
||
--ansi-bright-red: #ff6e67;
|
||
--ansi-bright-blue: #7277cc;
|
||
--ansi-bright-magenta: #ff76ff;
|
||
--rust-comment-single: dimgray;
|
||
--rust-keyword: #ff8000;
|
||
--rust-literal-number: dodgerblue;
|
||
--rust-literal-string-double: forestgreen;
|
||
--rust-literal-constant: dodgerblue;
|
||
--rust-name-builtin: #ff8000;
|
||
--marked-background: #fdff00;
|
||
--marked-text: #222;
|
||
--row-n0: #27272c;
|
||
--row-n1: #19191c;
|
||
--schema-token-1: #007fff;
|
||
--schema-token-2: #009900;
|
||
--schema-token-3: #ff8000;
|
||
--hurl-structure-0-front: #ff0288;
|
||
--hurl-structure-0-back: #27272c;
|
||
--hurl-structure-1-front: #009900;
|
||
--hurl-structure-1-back: #27272c;
|
||
--hurl-structure-2-front: #ff8000;
|
||
--hurl-structure-2-back: #27272c;
|
||
--hurl-structure-3-front: dodgerblue;
|
||
--hurl-structure-3-back: #27272c;
|
||
}
|
||
html[data-theme=dark] .u-theme-light {
|
||
display: none;
|
||
}
|
||
html[data-theme=dark] .u-theme-dark {
|
||
display: inline-block;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
html, html[data-theme=dark] {
|
||
--background-color: #19191c;
|
||
--primary-color: #ff0288;
|
||
--body-text: #c2c2c2;
|
||
--secondary-color: #34a7ff;
|
||
--code-background-color: #27272c;
|
||
--footer-background-color: #0a0a0a;
|
||
--separator-color: #444;
|
||
--hurl-string: forestgreen;
|
||
--hurl-regex: forestgreen;
|
||
--hurl-name: forestgreen;
|
||
--hurl-number: dodgerblue;
|
||
--hurl-boolean: dodgerblue;
|
||
--hurl-null: dodgerblue;
|
||
--hurl-json: forestgreen;
|
||
--hurl-xml: forestgreen;
|
||
--hurl-hex: forestgreen;
|
||
--hurl-base64: forestgreen;
|
||
--hurl-filename: forestgreen;
|
||
--hurl-url: cyan;
|
||
--hurl-method: orange;
|
||
--hurl-version: white;
|
||
--hurl-section-header: magenta;
|
||
--hurl-query-type: cyan;
|
||
--hurl-filter-type: orange;
|
||
--hurl-not: orange;
|
||
--hurl-predicate-type: orange;
|
||
--hurl-comment: dimgray;
|
||
--bash-comment-single: dimgray;
|
||
--bash-keyword: #ff8000;
|
||
--bash-literal-number: dodgerblue;
|
||
--bash-literal-string-double: forestgreen;
|
||
--bash-name-builtin: #ff8000;
|
||
--shell-prompt: dimgray;
|
||
--ansi-green: #00c300;
|
||
--ansi-gray: dimgray;
|
||
--ansi-bright-cyan: cyan;
|
||
--ansi-bright-green: lime;
|
||
--ansi-bright-red: #ff6e67;
|
||
--ansi-bright-blue: #7277cc;
|
||
--ansi-bright-magenta: #ff76ff;
|
||
--rust-comment-single: dimgray;
|
||
--rust-keyword: #ff8000;
|
||
--rust-literal-number: dodgerblue;
|
||
--rust-literal-string-double: forestgreen;
|
||
--rust-literal-constant: dodgerblue;
|
||
--rust-name-builtin: #ff8000;
|
||
--marked-background: #fdff00;
|
||
--marked-text: #222;
|
||
--row-n0: #27272c;
|
||
--row-n1: #19191c;
|
||
--schema-token-1: #007fff;
|
||
--schema-token-2: #009900;
|
||
--schema-token-3: #ff8000;
|
||
--hurl-structure-0-front: #ff0288;
|
||
--hurl-structure-0-back: #27272c;
|
||
--hurl-structure-1-front: #009900;
|
||
--hurl-structure-1-back: #27272c;
|
||
--hurl-structure-2-front: #ff8000;
|
||
--hurl-structure-2-back: #27272c;
|
||
--hurl-structure-3-front: dodgerblue;
|
||
--hurl-structure-3-back: #27272c;
|
||
}
|
||
html .u-theme-light, html[data-theme=dark] .u-theme-light {
|
||
display: none;
|
||
}
|
||
html .u-theme-dark, html[data-theme=dark] .u-theme-dark {
|
||
display: inline-block;
|
||
}
|
||
html[data-theme=light] {
|
||
--background-color: #fff;
|
||
--primary-color: #ff0288;
|
||
--body-text: #222;
|
||
--secondary-color: royalblue;
|
||
--code-background-color: #f5f5f5;
|
||
--footer-background-color: #f0f0f0;
|
||
--separator-color: #b3b3b3;
|
||
--hurl-string: darkgreen;
|
||
--hurl-regex: darkgreen;
|
||
--hurl-name: darkgreen;
|
||
--hurl-number: blue;
|
||
--hurl-boolean: blue;
|
||
--hurl-null: blue;
|
||
--hurl-json: darkgreen;
|
||
--hurl-xml: darkgreen;
|
||
--hurl-hex: darkgreen;
|
||
--hurl-base64: darkgreen;
|
||
--hurl-filename: darkgreen;
|
||
--hurl-url: darkblue;
|
||
--hurl-method: #222;
|
||
--hurl-version: #222;
|
||
--hurl-section-header: darkmagenta;
|
||
--hurl-query-type: teal;
|
||
--hurl-filter-type: darkblue;
|
||
--hurl-not: darkblue;
|
||
--hurl-predicate-type: darkblue;
|
||
--hurl-comment: dimgray;
|
||
--bash-comment-single: dimgray;
|
||
--bash-keyword: teal;
|
||
--bash-literal-number: blue;
|
||
--bash-literal-string-double: darkgreen;
|
||
--bash-name-builtin: teal;
|
||
--shell-prompt: dimgray;
|
||
--ansi-green: darkgreen;
|
||
--ansi-gray: dimgray;
|
||
--ansi-bright-cyan: #35bbc7;
|
||
--ansi-bright-green: #33bd25;
|
||
--ansi-bright-red: #c33820;
|
||
--ansi-bright-blue: #4427b7;
|
||
--ansi-bright-magenta: #bb34b9;
|
||
--rust-comment-single: dimgray;
|
||
--rust-keyword: teal;
|
||
--rust-literal-number: blue;
|
||
--rust-literal-string-double: darkgreen;
|
||
--rust-literal-constant: blue;
|
||
--rust-name-builtin: teal;
|
||
--marked-background: #fdff00;
|
||
--marked-text: #222;
|
||
--row-n0: #f5f5f5;
|
||
--row-n1: #fff;
|
||
--schema-token-1: #0000ff;
|
||
--schema-token-2: #009900;
|
||
--schema-token-3: #ff8000;
|
||
--hurl-structure-0-front: #ff0288;
|
||
--hurl-structure-0-back: #f5f5f5;
|
||
--hurl-structure-1-front: #009900;
|
||
--hurl-structure-1-back: #f5f5f5;
|
||
--hurl-structure-2-front: #ff8000;
|
||
--hurl-structure-2-back: #f5f5f5;
|
||
--hurl-structure-3-front: dodgerblue;
|
||
--hurl-structure-3-back: #f5f5f5;
|
||
}
|
||
html[data-theme=light] .u-theme-img {
|
||
display: inline-block;
|
||
}
|
||
html[data-theme=light] .u-theme-dark {
|
||
display: none;
|
||
}
|
||
}
|
||
.schema-container {
|
||
text-align: center;
|
||
margin-top: 0;
|
||
margin-bottom: 0;
|
||
margin-left: -1rem;
|
||
margin-right: -1rem;
|
||
}
|
||
|
||
.schema {
|
||
display: inline-block;
|
||
height: 120px;
|
||
margin: 1em auto;
|
||
}
|
||
|
||
.schema-token {
|
||
position: relative;
|
||
}
|
||
|
||
.schema-color-1 {
|
||
color: #0000ff;
|
||
color: var(--schema-token-1);
|
||
}
|
||
|
||
.schema-color-2 {
|
||
color: #009900;
|
||
color: var(--schema-token-2);
|
||
}
|
||
|
||
.schema-color-3 {
|
||
color: #ff8000;
|
||
color: var(--schema-token-3);
|
||
}
|
||
|
||
.schema-token::after {
|
||
content: "";
|
||
position: absolute;
|
||
top: 2.2rem;
|
||
width: 94%;
|
||
left: 3%;
|
||
height: 0.5em;
|
||
border-bottom: 2px solid #222;
|
||
border-left: 1px solid #222;
|
||
border-right: 1px solid #222;
|
||
border-bottom: 2px solid var(--body-text);
|
||
border-left: 1px solid var(--body-text);
|
||
border-right: 1px solid var(--body-text);
|
||
border-bottom-left-radius: 20px;
|
||
border-bottom-right-radius: 20px;
|
||
}
|
||
|
||
.schema-label {
|
||
font-family: Helvetica, Arial, sans-serif;
|
||
color: #222;
|
||
color: var(--body-text);
|
||
position: absolute;
|
||
top: 3.4rem;
|
||
left: 3%;
|
||
width: 94%;
|
||
text-align: center;
|
||
font-size: 75%;
|
||
}
|
||
|
||
.hurl-structure-schema {
|
||
margin-top: 3rem;
|
||
margin-bottom: 3rem;
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.hurl-structure-schema {
|
||
margin: 3rem 2rem;
|
||
}
|
||
}
|
||
|
||
.hurl-structure {
|
||
display: flex;
|
||
}
|
||
|
||
.hurl-structure-col-0 {
|
||
font-family: Menlo, Monaco, Consolas, "Liberation Mono", " Courier New", monospace;
|
||
font-size: 0.85rem;
|
||
line-height: 1.5;
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.hurl-structure-col-0 {
|
||
font-size: 1rem;
|
||
}
|
||
}
|
||
|
||
.hurl-structure-col-1 {
|
||
font-family: Helvetica, Arial, sans-serif;
|
||
font-size: 0.85rem;
|
||
line-height: 1.5;
|
||
}
|
||
@media only screen and (min-width: 768px) {
|
||
.hurl-structure-col-1 {
|
||
font-size: 1rem;
|
||
}
|
||
}
|
||
|
||
.hurl-part-0 {
|
||
background-color: #f5f5f5;
|
||
background-color: var(--hurl-structure-0-back);
|
||
color: #ff0288;
|
||
color: var(--hurl-structure-0-front);
|
||
border-right: 4px solid;
|
||
border-color: #ff0288;
|
||
border-color: var(--hurl-structure-0-front);
|
||
padding-top: 10px;
|
||
padding-right: 40px;
|
||
padding-left: 10px;
|
||
padding-bottom: 2px;
|
||
border-bottom: dashed 1px;
|
||
border-bottom-color: #8c8c8c;
|
||
}
|
||
|
||
.hurl-request-explanation-part-0 {
|
||
padding: 10px 10px 2px;
|
||
}
|
||
|
||
.hurl-part-1 {
|
||
background-color: #f5f5f5;
|
||
background-color: var(--hurl-structure-1-back);
|
||
color: #009900;
|
||
color: var(--hurl-structure-1-front);
|
||
border-right: 4px solid;
|
||
border-color: #009900;
|
||
border-color: var(--hurl-structure-1-front);
|
||
padding-top: 2px;
|
||
padding-right: 40px;
|
||
padding-left: 10px;
|
||
padding-bottom: 2px;
|
||
border-bottom: dashed 1px;
|
||
border-bottom-color: #8c8c8c;
|
||
}
|
||
|
||
.hurl-request-explanation-part-1 {
|
||
padding: 2px 10px;
|
||
}
|
||
|
||
.hurl-part-2 {
|
||
background-color: #f5f5f5;
|
||
background-color: var(--hurl-structure-2-back);
|
||
color: #ff8000;
|
||
color: var(--hurl-structure-2-front);
|
||
border-right: 4px solid;
|
||
border-color: #ff8000;
|
||
border-color: var(--hurl-structure-2-front);
|
||
padding-top: 1px;
|
||
padding-right: 40px;
|
||
padding-left: 10px;
|
||
padding-bottom: 1px;
|
||
}
|
||
|
||
.hurl-request-explanation-part-2 {
|
||
padding: 2px 10px;
|
||
}
|
||
|
||
.hurl-part-3 {
|
||
background-color: #f5f5f5;
|
||
background-color: var(--hurl-structure-3-back);
|
||
color: dodgerblue;
|
||
color: var(--hurl-structure-3-front);
|
||
border-right: 4px solid;
|
||
border-color: dodgerblue;
|
||
border-color: var(--hurl-structure-3-front);
|
||
padding-top: 2px;
|
||
padding-right: 40px;
|
||
padding-left: 10px;
|
||
padding-bottom: 2px;
|
||
border-top: dashed 1px;
|
||
border-top-color: #8c8c8c;
|
||
}
|
||
|
||
.hurl-request-explanation-part-3 {
|
||
padding: 2px 10px;
|
||
}
|
||
|
||
.row {
|
||
display: flex;
|
||
}
|
||
|
||
.col {
|
||
flex: 1;
|
||
}
|
||
|
||
.col1 {
|
||
flex: 1;
|
||
}
|
||
|
||
.col2 {
|
||
flex: 2;
|
||
}
|
||
|
||
.col3 {
|
||
flex: 3;
|
||
}
|
||
|
||
.col4 {
|
||
flex: 4;
|
||
}
|
||
|
||
.col5 {
|
||
flex: 5;
|
||
}
|
||
|
||
.col6 {
|
||
flex: 6;
|
||
}
|
||
|
||
@media print {
|
||
body {
|
||
zoom: 60%;
|
||
}
|
||
h1 {
|
||
page-break-before: always;
|
||
}
|
||
hr {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div>
|
||
<div class="doc-content-col">
|
||
<h1 id="hurl-documentation"><a href="#hurl-documentation">Hurl Documentation</a></h1>
|
||
|
||
<h2 id="version-600-02-12-2024"><a href="#version-600-02-12-2024">Version 6.0.0 - 02-12-2024</a></h2>
|
||
|
||
<h1 id="table-of-contents"><a href="#table-of-contents">Table of Contents</a></h1>
|
||
|
||
<ul>
|
||
<li><a href="#introduction">Introduction</a>
|
||
<ul>
|
||
<li><a href="#introduction-home-whats-hurl">What’s Hurl?</a></li>
|
||
<li><a href="#introduction-home-also-an-http-test-tool">Also an HTTP Test Tool</a></li>
|
||
<li><a href="#introduction-home-why-hurl">Why Hurl?</a></li>
|
||
<li><a href="#introduction-home-powered-by-curl">Powered by curl</a></li>
|
||
<li><a href="#introduction-home-feedbacks">Feedbacks</a></li>
|
||
<li><a href="#introduction-home-resources">Resources</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started">Getting Started</a>
|
||
<ul>
|
||
<li><a href="#getting-started-installation-installation">Installation</a>
|
||
<ul>
|
||
<li><a href="#getting-started-installation-binaries-installation">Binaries Installation</a>
|
||
<ul>
|
||
<li><a href="#getting-started-installation-linux">Linux</a>
|
||
<ul>
|
||
<li><a href="#getting-started-installation-debian--ubuntu">Debian / Ubuntu</a></li>
|
||
<li><a href="#getting-started-installation-alpine">Alpine</a></li>
|
||
<li><a href="#getting-started-installation-arch-linux--manjaro">Arch Linux / Manjaro</a></li>
|
||
<li><a href="#getting-started-installation-nixos--nix">NixOS / Nix</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-installation-macos">macOS</a>
|
||
<ul>
|
||
<li><a href="#getting-started-installation-homebrew">Homebrew</a></li>
|
||
<li><a href="#getting-started-installation-macports">MacPorts</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-installation-freebsd">FreeBSD</a></li>
|
||
<li><a href="#getting-started-installation-windows">Windows</a>
|
||
<ul>
|
||
<li><a href="#getting-started-installation-zip-file">Zip File</a></li>
|
||
<li><a href="#getting-started-installation-installer">Installer</a></li>
|
||
<li><a href="#getting-started-installation-chocolatey">Chocolatey</a></li>
|
||
<li><a href="#getting-started-installation-scoop">Scoop</a></li>
|
||
<li><a href="#getting-started-installation-windows-package-manager">Windows Package Manager</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-installation-cargo">Cargo</a></li>
|
||
<li><a href="#getting-started-installation-conda-forge">conda-forge</a></li>
|
||
<li><a href="#getting-started-installation-docker">Docker</a></li>
|
||
<li><a href="#getting-started-installation-npm">npm</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-installation-building-from-sources">Building From Sources</a>
|
||
<ul>
|
||
<li><a href="#getting-started-installation-build-on-linux">Build on Linux</a>
|
||
<ul>
|
||
<li><a href="#getting-started-installation-debian-based-distributions">Debian based distributions</a></li>
|
||
<li><a href="#getting-started-installation-fedora-based-distributions">Fedora based distributions</a></li>
|
||
<li><a href="#getting-started-installation-red-hat-based-distributions">Red Hat based distributions</a></li>
|
||
<li><a href="#getting-started-installation-arch-based-distributions">Arch based distributions</a></li>
|
||
<li><a href="#getting-started-installation-alpine-based-distributions">Alpine based distributions</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-installation-build-on-macos">Build on macOS</a></li>
|
||
<li><a href="#getting-started-installation-build-on-windows">Build on Windows</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-manual-manual">Manual</a>
|
||
<ul>
|
||
<li><a href="#getting-started-manual-name">Name</a></li>
|
||
<li><a href="#getting-started-manual-synopsis">Synopsis</a></li>
|
||
<li><a href="#getting-started-manual-description">Description</a></li>
|
||
<li><a href="#getting-started-manual-hurl-file-format">Hurl File Format</a>
|
||
<ul>
|
||
<li><a href="#getting-started-manual-capturing-values">Capturing values</a></li>
|
||
<li><a href="#getting-started-manual-asserts">Asserts</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-manual-options">Options</a></li>
|
||
<li><a href="#getting-started-manual-environment">Environment</a></li>
|
||
<li><a href="#getting-started-manual-exit-codes">Exit Codes</a></li>
|
||
<li><a href="#getting-started-manual-www">WWW</a></li>
|
||
<li><a href="#getting-started-manual-see-also">See Also</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-samples-samples">Samples</a>
|
||
<ul>
|
||
<li><a href="#getting-started-samples-getting-data">Getting Data</a>
|
||
<ul>
|
||
<li><a href="#getting-started-samples-http-headers">HTTP Headers</a></li>
|
||
<li><a href="#getting-started-samples-query-params">Query Params</a></li>
|
||
<li><a href="#getting-started-samples-basic-authentication">Basic Authentication</a></li>
|
||
<li><a href="#getting-started-samples-passing-data-between-requests">Passing Data between Requests </a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-samples-sending-data">Sending Data</a>
|
||
<ul>
|
||
<li><a href="#getting-started-samples-sending-html-form-data">Sending HTML Form Data</a></li>
|
||
<li><a href="#getting-started-samples-sending-multipart-form-data">Sending Multipart Form Data</a></li>
|
||
<li><a href="#getting-started-samples-posting-a-json-body">Posting a JSON Body</a></li>
|
||
<li><a href="#getting-started-samples-templating-a-json-body">Templating a JSON Body</a></li>
|
||
<li><a href="#getting-started-samples-templating-a-xml-body">Templating a XML Body</a></li>
|
||
<li><a href="#getting-started-samples-using-graphql-query">Using GraphQL Query</a></li>
|
||
<li><a href="#getting-started-samples-using-dynamic-datas">Using Dynamic Datas</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-samples-testing-response">Testing Response</a>
|
||
<ul>
|
||
<li><a href="#getting-started-samples-testing-status-code">Testing Status Code</a></li>
|
||
<li><a href="#getting-started-samples-testing-response-headers">Testing Response Headers</a></li>
|
||
<li><a href="#getting-started-samples-testing-rest-apis">Testing REST APIs</a></li>
|
||
<li><a href="#getting-started-samples-testing-html-response">Testing HTML Response</a></li>
|
||
<li><a href="#getting-started-samples-testing-set-cookie-attributes">Testing Set-Cookie Attributes</a></li>
|
||
<li><a href="#getting-started-samples-testing-bytes-content">Testing Bytes Content</a></li>
|
||
<li><a href="#getting-started-samples-ssl-certificate">SSL Certificate</a></li>
|
||
<li><a href="#getting-started-samples-checking-full-body">Checking Full Body</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-samples-reports">Reports</a>
|
||
<ul>
|
||
<li><a href="#getting-started-samples-html-report">HTML Report</a></li>
|
||
<li><a href="#getting-started-samples-json-report">JSON Report</a></li>
|
||
<li><a href="#getting-started-samples-junit-report">JUnit Report</a></li>
|
||
<li><a href="#getting-started-samples-tap-report">TAP Report</a></li>
|
||
<li><a href="#getting-started-samples-json-output">JSON Output</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-samples-others">Others</a>
|
||
<ul>
|
||
<li><a href="#getting-started-samples-http-version">HTTP Version</a></li>
|
||
<li><a href="#getting-started-samples-polling-and-retry">Polling and Retry</a></li>
|
||
<li><a href="#getting-started-samples-delaying-requests">Delaying Requests</a></li>
|
||
<li><a href="#getting-started-samples-skipping-requests">Skipping Requests</a></li>
|
||
<li><a href="#getting-started-samples-testing-endpoint-performance">Testing Endpoint Performance</a></li>
|
||
<li><a href="#getting-started-samples-using-soap-apis">Using SOAP APIs</a></li>
|
||
<li><a href="#getting-started-samples-capturing-and-using-a-csrf-token">Capturing and Using a CSRF Token</a></li>
|
||
<li><a href="#getting-started-samples-checking-byte-order-mark-bom-in-response-body">Checking Byte Order Mark (BOM) in Response Body</a></li>
|
||
<li><a href="#getting-started-samples-aws-signature-version-4-requests">AWS Signature Version 4 Requests</a></li>
|
||
<li><a href="#getting-started-samples-using-curl-options">Using curl Options</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-running-tests-running-tests">Running Tests</a>
|
||
<ul>
|
||
<li><a href="#getting-started-running-tests-use-test-option">Use --test Option</a>
|
||
<ul>
|
||
<li><a href="#getting-started-running-tests-selecting-tests">Selecting Tests</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-running-tests-debugging">Debugging</a>
|
||
<ul>
|
||
<li><a href="#getting-started-running-tests-debug-logs">Debug Logs</a></li>
|
||
<li><a href="#getting-started-running-tests-http-responses">HTTP Responses</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-running-tests-generating-report">Generating Report</a>
|
||
<ul>
|
||
<li><a href="#getting-started-running-tests-html-report">HTML Report</a></li>
|
||
<li><a href="#getting-started-running-tests-json-report">JSON Report</a></li>
|
||
<li><a href="#getting-started-running-tests-junit-report">JUnit Report</a></li>
|
||
<li><a href="#getting-started-running-tests-tap-report">TAP Report</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-running-tests-use-variables-in-tests">Use Variables in Tests</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-frequently-asked-questions-frequently-asked-questions">Frequently Asked Questions</a>
|
||
<ul>
|
||
<li><a href="#getting-started-frequently-asked-questions-general">General</a>
|
||
<ul>
|
||
<li><a href="#getting-started-frequently-asked-questions-why-hurl">Why “Hurl”?</a></li>
|
||
<li><a href="#getting-started-frequently-asked-questions-yet-another-tool-i-already-use-x">Yet Another Tool, I already use X</a></li>
|
||
<li><a href="#getting-started-frequently-asked-questions-hurl-is-build-on-top-of-libcurl-but-what-is-added">Hurl is build on top of libcurl, but what is added?</a></li>
|
||
<li><a href="#getting-started-frequently-asked-questions-why-shouldnt-i-use-hurl">Why shouldn’t I use Hurl?</a></li>
|
||
<li><a href="#getting-started-frequently-asked-questions-i-have-a-large-numbers-of-tests-how-to-run-just-specific-tests">I have a large numbers of tests, how to run just specific tests?</a></li>
|
||
<li><a href="#getting-started-frequently-asked-questions-how-can-i-use-my-hurl-files-outside-hurl">How can I use my Hurl files outside Hurl?</a></li>
|
||
<li><a href="#getting-started-frequently-asked-questions-can-i-do-calculation-within-a-hurl-file">Can I do calculation within a Hurl file?</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#getting-started-frequently-asked-questions-macos">macOS</a>
|
||
<ul>
|
||
<li><a href="#getting-started-frequently-asked-questions-how-can-i-use-a-custom-libcurl-from-homebrew-by-instance">How can I use a custom libcurl (from Homebrew by instance)?</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format">File Format</a>
|
||
<ul>
|
||
<li><a href="#file-format-hurl-file-hurl-file">Hurl File</a>
|
||
<ul>
|
||
<li><a href="#file-format-hurl-file-character-encoding">Character Encoding</a></li>
|
||
<li><a href="#file-format-hurl-file-file-extension">File Extension</a></li>
|
||
<li><a href="#file-format-hurl-file-comments">Comments</a></li>
|
||
<li><a href="#file-format-hurl-file-special-characters-in-strings">Special Characters in Strings</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-entry-entry">Entry</a>
|
||
<ul>
|
||
<li><a href="#file-format-entry-definition">Definition</a></li>
|
||
<li><a href="#file-format-entry-example">Example</a></li>
|
||
<li><a href="#file-format-entry-description">Description</a>
|
||
<ul>
|
||
<li><a href="#file-format-entry-options">Options</a></li>
|
||
<li><a href="#file-format-entry-cookie-storage">Cookie storage</a></li>
|
||
<li><a href="#file-format-entry-redirects">Redirects</a></li>
|
||
<li><a href="#file-format-entry-retry">Retry</a></li>
|
||
<li><a href="#file-format-entry-control-flow">Control flow</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-request-request">Request</a>
|
||
<ul>
|
||
<li><a href="#file-format-request-definition">Definition</a></li>
|
||
<li><a href="#file-format-request-example">Example</a></li>
|
||
<li><a href="#file-format-request-structure">Structure</a></li>
|
||
<li><a href="#file-format-request-description">Description</a>
|
||
<ul>
|
||
<li><a href="#file-format-request-method">Method</a></li>
|
||
<li><a href="#file-format-request-url">URL</a></li>
|
||
<li><a href="#file-format-request-headers">Headers</a></li>
|
||
<li><a href="#file-format-request-options">Options</a></li>
|
||
<li><a href="#file-format-request-query-parameters">Query parameters</a></li>
|
||
<li><a href="#file-format-request-form-parameters">Form parameters</a></li>
|
||
<li><a href="#file-format-request-multipart-form-data">Multipart Form Data</a></li>
|
||
<li><a href="#file-format-request-cookies">Cookies</a></li>
|
||
<li><a href="#file-format-request-basic-authentication">Basic Authentication</a></li>
|
||
<li><a href="#file-format-request-body">Body</a>
|
||
<ul>
|
||
<li><a href="#file-format-request-json-body">JSON body</a></li>
|
||
<li><a href="#file-format-request-xml-body">XML body</a></li>
|
||
<li><a href="#file-format-request-graphql-query">GraphQL query</a></li>
|
||
<li><a href="#file-format-request-multiline-string-body">Multiline string body</a></li>
|
||
<li><a href="#file-format-request-oneline-string-body">Oneline string body</a></li>
|
||
<li><a href="#file-format-request-base64-body">Base64 body</a></li>
|
||
<li><a href="#file-format-request-hex-body">Hex body</a></li>
|
||
<li><a href="#file-format-request-file-body">File body</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-response-response">Response</a>
|
||
<ul>
|
||
<li><a href="#file-format-response-definition">Definition</a></li>
|
||
<li><a href="#file-format-response-example">Example</a></li>
|
||
<li><a href="#file-format-response-structure">Structure</a></li>
|
||
<li><a href="#file-format-response-capture-and-assertion">Capture and Assertion</a>
|
||
<ul>
|
||
<li><a href="#file-format-response-body-compression">Body compression</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-response-timings">Timings</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-capturing-response-capturing-response">Capturing Response</a>
|
||
<ul>
|
||
<li><a href="#file-format-capturing-response-captures">Captures</a>
|
||
<ul>
|
||
<li><a href="#file-format-capturing-response-query">Query</a></li>
|
||
<li><a href="#file-format-capturing-response-status-capture">Status capture</a></li>
|
||
<li><a href="#file-format-capturing-response-header-capture">Header capture</a></li>
|
||
<li><a href="#file-format-capturing-response-url-capture">URL capture</a></li>
|
||
<li><a href="#file-format-capturing-response-cookie-capture">Cookie capture</a></li>
|
||
<li><a href="#file-format-capturing-response-body-capture">Body capture</a></li>
|
||
<li><a href="#file-format-capturing-response-bytes-capture">Bytes capture</a></li>
|
||
<li><a href="#file-format-capturing-response-xpath-capture">XPath capture</a></li>
|
||
<li><a href="#file-format-capturing-response-jsonpath-capture">JSONPath capture</a></li>
|
||
<li><a href="#file-format-capturing-response-regex-capture">Regex capture</a></li>
|
||
<li><a href="#file-format-capturing-response-variable-capture">Variable capture</a></li>
|
||
<li><a href="#file-format-capturing-response-duration-capture">Duration capture</a></li>
|
||
<li><a href="#file-format-capturing-response-ssl-certificate-capture">SSL certificate capture</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-asserting-response-asserting-response">Asserting Response</a>
|
||
<ul>
|
||
<li><a href="#file-format-asserting-response-asserts">Asserts</a></li>
|
||
<li><a href="#file-format-asserting-response-implicit-asserts">Implicit asserts</a>
|
||
<ul>
|
||
<li><a href="#file-format-asserting-response-version-status">Version - Status</a></li>
|
||
<li><a href="#file-format-asserting-response-headers">Headers</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-asserting-response-explicit-asserts">Explicit asserts</a>
|
||
<ul>
|
||
<li><a href="#file-format-asserting-response-predicates">Predicates</a></li>
|
||
<li><a href="#file-format-asserting-response-status-assert">Status assert</a></li>
|
||
<li><a href="#file-format-asserting-response-header-assert">Header assert</a></li>
|
||
<li><a href="#file-format-asserting-response-url-assert">URL assert</a></li>
|
||
<li><a href="#file-format-asserting-response-cookie-assert">Cookie assert</a></li>
|
||
<li><a href="#file-format-asserting-response-body-assert">Body assert</a></li>
|
||
<li><a href="#file-format-asserting-response-bytes-assert">Bytes assert</a></li>
|
||
<li><a href="#file-format-asserting-response-xpath-assert">XPath assert</a></li>
|
||
<li><a href="#file-format-asserting-response-jsonpath-assert">JSONPath assert</a></li>
|
||
<li><a href="#file-format-asserting-response-regex-assert">Regex assert</a></li>
|
||
<li><a href="#file-format-asserting-response-sha-256-assert">SHA-256 assert</a></li>
|
||
<li><a href="#file-format-asserting-response-md5-assert">MD5 assert</a></li>
|
||
<li><a href="#file-format-asserting-response-variable-assert">Variable assert</a></li>
|
||
<li><a href="#file-format-asserting-response-duration-assert">Duration assert</a></li>
|
||
<li><a href="#file-format-asserting-response-ssl-certificate-assert">SSL certificate assert</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-asserting-response-body">Body</a>
|
||
<ul>
|
||
<li><a href="#file-format-asserting-response-json-body">JSON body</a></li>
|
||
<li><a href="#file-format-asserting-response-xml-body">XML body</a></li>
|
||
<li><a href="#file-format-asserting-response-multiline-string-body">Multiline string body</a>
|
||
<ul>
|
||
<li><a href="#file-format-asserting-response-oneline-string-body">Oneline string body</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-asserting-response-base64-body">Base64 body</a></li>
|
||
<li><a href="#file-format-asserting-response-file-body">File body</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-filters-filters">Filters</a>
|
||
<ul>
|
||
<li><a href="#file-format-filters-definition">Definition</a></li>
|
||
<li><a href="#file-format-filters-example">Example</a></li>
|
||
<li><a href="#file-format-filters-description">Description</a>
|
||
<ul>
|
||
<li><a href="#file-format-filters-count">count</a></li>
|
||
<li><a href="#file-format-filters-daysafternow">daysAfterNow</a></li>
|
||
<li><a href="#file-format-filters-daysbeforenow">daysBeforeNow</a></li>
|
||
<li><a href="#file-format-filters-decode">decode</a></li>
|
||
<li><a href="#file-format-filters-format">format</a></li>
|
||
<li><a href="#file-format-filters-htmlescape">htmlEscape</a></li>
|
||
<li><a href="#file-format-filters-htmlunescape">htmlUnescape</a></li>
|
||
<li><a href="#file-format-filters-jsonpath">jsonpath </a></li>
|
||
<li><a href="#file-format-filters-nth">nth</a></li>
|
||
<li><a href="#file-format-filters-regex">regex</a></li>
|
||
<li><a href="#file-format-filters-replace">replace</a></li>
|
||
<li><a href="#file-format-filters-split">split</a></li>
|
||
<li><a href="#file-format-filters-todate">toDate</a></li>
|
||
<li><a href="#file-format-filters-tofloat">toFloat</a></li>
|
||
<li><a href="#file-format-filters-toint">toInt</a></li>
|
||
<li><a href="#file-format-filters-urldecode">urlDecode</a></li>
|
||
<li><a href="#file-format-filters-urlencode">urlEncode</a></li>
|
||
<li><a href="#file-format-filters-xpath">xpath</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-templates-templates">Templates</a>
|
||
<ul>
|
||
<li><a href="#file-format-templates-variables">Variables</a></li>
|
||
<li><a href="#file-format-templates-functions">Functions</a></li>
|
||
<li><a href="#file-format-templates-types">Types</a></li>
|
||
<li><a href="#file-format-templates-injecting-variables">Injecting Variables</a>
|
||
<ul>
|
||
<li><a href="#file-format-templates-variable-option"><code>variable</code> option</a></li>
|
||
<li><a href="#file-format-templates-variables-file-option"><code>variables-file</code> option</a></li>
|
||
<li><a href="#file-format-templates-environment-variable">Environment variable</a></li>
|
||
<li><a href="#file-format-templates-options-sections">Options sections</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-templates-templating-body">Templating Body</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#file-format-grammar-grammar">Grammar</a>
|
||
<ul>
|
||
<li><a href="#file-format-grammar-definitions">Definitions</a></li>
|
||
<li><a href="#file-format-grammar-syntax-grammar">Syntax Grammar</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#resources">Resources</a>
|
||
<ul>
|
||
<li><a href="#resources-license-license">License</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h1 id="introduction"><a href="#introduction">Introduction</a></h1>
|
||
|
||
<div class="home-logo">
|
||
<img class="u-theme-light" src="https://hurl.dev/assets/img/logo-light.svg" width="277px" height="72px" alt="Hurl logo" />
|
||
<img class="u-theme-dark" src="https://hurl.dev/assets/img/logo-dark.svg" width="277px" height="72px" alt="Hurl logo" />
|
||
</div>
|
||
|
||
<h2 id="introduction-home-whats-hurl"><a href="#introduction-home-whats-hurl">What’s Hurl?</a></h2>
|
||
|
||
<p>Hurl is a command line tool that runs <b>HTTP requests</b> defined in a simple <b>plain text format</b>.</p>
|
||
|
||
<p>It can chain requests, capture values and evaluate queries on headers and body response. Hurl is very
|
||
versatile: it can be used for both <b>fetching data</b> and <b>testing HTTP</b> sessions.</p>
|
||
|
||
<p>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.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Get home:</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">csrf_token</span>: <span class="query-type">xpath</span> <span class="string">"string(//meta[@name='_csrf_token']/@content)"</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Do login!</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://example.org/login?user=toto&password=1234</span></span>
|
||
<span class="line"><span class="string">X-CSRF-TOKEN</span>: <span class="string">{{csrf_token}}</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">302</span></span></span></span></code></pre>
|
||
|
||
<p>Chaining multiple requests is easy:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/health</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/step1</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/step2</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/step3</span></span></span></span></code></pre>
|
||
|
||
<h2 id="introduction-home-also-an-http-test-tool"><a href="#introduction-home-also-an-http-test-tool">Also an HTTP Test Tool</a></h2>
|
||
|
||
<p>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 <a href="https://en.wikipedia.org/wiki/XPath">XPath</a> and <a href="https://goessner.net/articles/JsonPath/">JSONPath</a> on body response,
|
||
to assert on status code and response headers.</p>
|
||
|
||
<p>It is well adapted for <b>REST / JSON APIs</b></p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/api/tests</span></span>
|
||
<span class="json"><span class="line">{</span>
|
||
<span class="line"> "id": "4568",</span>
|
||
<span class="line"> "evaluate": true</span>
|
||
<span class="line">}</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"X-Frame-Options"</span> <span class="predicate-type">==</span> <span class="string">"SAMEORIGIN"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.status"</span> <span class="predicate-type">==</span> <span class="string">"RUNNING"</span></span> <span class="comment"># Check the status code</span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.tests"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">25</span></span> <span class="comment"># Check the number of items</span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.id"</span> <span class="predicate-type">matches</span> <span class="regex">/\d{4}/</span></span> <span class="comment"># Check the format of the id</span></span></span></code></pre>
|
||
|
||
<p><b>HTML content</b></p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"normalize-space(//head/title)"</span> <span class="predicate-type">==</span> <span class="string">"Hello world!"</span></span></span></span></code></pre>
|
||
|
||
<p><b>GraphQL</b></p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/graphql</span></span>
|
||
<span class="multiline"><span class="line">```graphql</span>
|
||
<span class="line">{</span>
|
||
<span class="line"> human(id: "1000") {</span>
|
||
<span class="line"> name</span>
|
||
<span class="line"> height(unit: FOOT)</span>
|
||
<span class="line"> }</span>
|
||
<span class="line">}</span>
|
||
<span class="line">```</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p>and even <b>SOAP APIs</b></p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/InStock</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">application/soap+xml; charset=utf-8</span></span>
|
||
<span class="line"><span class="string">SOAPAction</span>: <span class="string">"http://www.w3.org/2003/05/soap-envelope"</span></span>
|
||
<span class="xml"><span class="line"><?xml version="1.0" encoding="UTF-8"?></span>
|
||
<span class="line"><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="https://example.org"></span>
|
||
<span class="line"> <soap:Header></soap:Header></span>
|
||
<span class="line"> <soap:Body></span>
|
||
<span class="line"> <m:GetStockPrice></span>
|
||
<span class="line"> <m:StockName>GOOG</m:StockName></span>
|
||
<span class="line"> </m:GetStockPrice></span>
|
||
<span class="line"> </soap:Body></span>
|
||
<span class="line"></soap:Envelope></span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p>Hurl can also be used to test the <b>performance</b> of HTTP endpoints</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/v1/pets</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">duration</span> <span class="predicate-type"><</span> <span class="number">1000</span></span> <span class="comment"># Duration in ms</span></span></span></code></pre>
|
||
|
||
<p>And check response bytes</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/data.tar.gz</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">sha256</span> <span class="predicate-type">==</span> hex,<span class="hex">039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81</span>;</span></span></span></code></pre>
|
||
|
||
<p>Finally, Hurl is easy to <b>integrate in CI/CD</b>, with text, JUnit, TAP and HTML reports</p>
|
||
|
||
<div class="picture">
|
||
<picture>
|
||
<source srcset="https://hurl.dev/assets/img/home-waterfall-light.avif" type="image/avif" />
|
||
<source srcset="https://hurl.dev/assets/img/home-waterfall-light.webp" type="image/webp" />
|
||
<source srcset="https://hurl.dev/assets/img/home-waterfall-light.png" type="image/png" />
|
||
<img class="u-theme-light u-drop-shadow u-border u-max-width-100" src="https://hurl.dev/assets/img/home-waterfall-light.png" width="480" alt="HTML report" />
|
||
</picture>
|
||
<picture>
|
||
<source srcset="https://hurl.dev/assets/img/home-waterfall-dark.avif" type="image/avif" />
|
||
<source srcset="https://hurl.dev/assets/img/home-waterfall-dark.webp" type="image/webp" />
|
||
<source srcset="https://hurl.dev/assets/img/home-waterfall-dark.png" type="image/png" />
|
||
<img class="u-theme-dark u-drop-shadow u-border u-max-width-100" src="https://hurl.dev/assets/img/home-waterfall-dark.png" width="480" alt="HTML report" />
|
||
</picture>
|
||
</div>
|
||
|
||
<h2 id="introduction-home-why-hurl"><a href="#introduction-home-why-hurl">Why Hurl?</a></h2>
|
||
|
||
<ul class="showcase-container">
|
||
<li class="showcase-item"><h2 class="showcase-item-title">Text Format</h2>For both devops and developers</li>
|
||
<li class="showcase-item"><h2 class="showcase-item-title">Fast CLI</h2>A command line for local dev and continuous integration</li>
|
||
<li class="showcase-item"><h2 class="showcase-item-title">Single Binary</h2>Easy to install, with no runtime required</li>
|
||
</ul>
|
||
|
||
<h2 id="introduction-home-powered-by-curl"><a href="#introduction-home-powered-by-curl">Powered by curl</a></h2>
|
||
|
||
<p>Hurl is a lightweight binary written in <a href="https://www.rust-lang.org">Rust</a>. Under the hood, Hurl HTTP engine is
|
||
powered by <a href="https://curl.se/libcurl/">libcurl</a>, one of the most powerful and reliable file transfer libraries.
|
||
With its text file format, Hurl adds syntactic sugar to run and test HTTP requests,
|
||
but it’s still the <a href="https://curl.se">curl</a> that we love: <strong>fast</strong>, <strong>efficient</strong> and <strong>HTTP/3 ready</strong>.</p>
|
||
|
||
<h2 id="introduction-home-feedbacks"><a href="#introduction-home-feedbacks">Feedbacks</a></h2>
|
||
|
||
<p>To support its development, <a href="https://github.com/Orange-OpenSource/hurl/stargazers">star Hurl on GitHub</a>!</p>
|
||
|
||
<p><a href="https://github.com/Orange-OpenSource/hurl/issues">Feedback, suggestion, bugs or improvements</a> are welcome.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://hurl.dev/api/feedback</span></span>
|
||
<span class="json"><span class="line">{</span>
|
||
<span class="line"> "name": "John Doe",</span>
|
||
<span class="line"> "feedback": "Hurl is awesome!"</span>
|
||
<span class="line">}</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<h2 id="introduction-home-resources"><a href="#introduction-home-resources">Resources</a></h2>
|
||
|
||
<p><a href="#resources-license">License</a></p>
|
||
|
||
<p><a href="https://hurl.dev/blog">Blog</a></p>
|
||
|
||
<p><a href="https://hurl.dev/docs/tutorial/your-first-hurl-file.html">Tutorial</a></p>
|
||
|
||
<p><a href="https://hurl.dev">Documentation</a></p>
|
||
|
||
<p><a href="https://github.com/Orange-OpenSource/hurl">GitHub</a></p>
|
||
|
||
<hr />
|
||
|
||
<h1 id="getting-started"><a href="#getting-started">Getting Started</a></h1>
|
||
|
||
<h2 id="getting-started-installation-installation"><a href="#getting-started-installation-installation">Installation</a></h2>
|
||
|
||
<h3 id="getting-started-installation-binaries-installation"><a href="#getting-started-installation-binaries-installation">Binaries Installation</a></h3>
|
||
|
||
<h4 id="getting-started-installation-linux"><a href="#getting-started-installation-linux">Linux</a></h4>
|
||
|
||
<p>Precompiled binary is available at <a href="https://github.com/Orange-OpenSource/hurl/releases/latest">Hurl latest GitHub release</a>:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>INSTALL_DIR=/tmp
|
||
<span class="prompt">$ </span>VERSION=5.0.1
|
||
<span class="prompt">$ </span>curl --silent --location https://github.com/Orange-OpenSource/hurl/releases/download/$VERSION/hurl-$VERSION-x86_64-unknown-linux-gnu.tar.gz | tar xvz -C $INSTALL_DIR
|
||
<span class="prompt">$ </span>export PATH=$INSTALL_DIR/hurl-$VERSION-x86_64-unknown-linux-gnu/bin:$PATH</code></pre>
|
||
|
||
<h5 id="getting-started-installation-debian-ubuntu"><a href="#getting-started-installation-debian-ubuntu">Debian / Ubuntu</a></h5>
|
||
|
||
<p>For Debian / Ubuntu, Hurl can be installed using a binary .deb file provided in each Hurl release.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>VERSION=5.0.1
|
||
<span class="prompt">$ </span>curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/$VERSION/hurl_${VERSION}_amd64.deb
|
||
<span class="prompt">$ </span>sudo apt update && sudo apt install ./hurl_${VERSION}_amd64.deb</code></pre>
|
||
|
||
<h5 id="getting-started-installation-alpine"><a href="#getting-started-installation-alpine">Alpine</a></h5>
|
||
|
||
<p>Hurl is available on <code>testing</code> channel.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>apk add --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing hurl</code></pre>
|
||
|
||
<h5 id="getting-started-installation-arch-linux-manjaro"><a href="#getting-started-installation-arch-linux-manjaro">Arch Linux / Manjaro</a></h5>
|
||
|
||
<p>Hurl is available on <a href="https://archlinux.org/packages/extra/x86_64/hurl/">extra</a> channel.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>pacman -Sy hurl</code></pre>
|
||
|
||
<h5 id="getting-started-installation-nixos-nix"><a href="#getting-started-installation-nixos-nix">NixOS / Nix</a></h5>
|
||
|
||
<p><a href="https://search.nixos.org/packages?from=0&size=1&sort=relevance&type=packages&query=hurl">NixOS / Nix package</a> is available on stable channel.</p>
|
||
|
||
<h4 id="getting-started-installation-macos"><a href="#getting-started-installation-macos">macOS</a></h4>
|
||
|
||
<p>Precompiled binaries for Intel and ARM CPUs are available at <a href="https://github.com/Orange-OpenSource/hurl/releases/latest">Hurl latest GitHub release</a>.</p>
|
||
|
||
<h5 id="getting-started-installation-homebrew"><a href="#getting-started-installation-homebrew">Homebrew</a></h5>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>brew install hurl</code></pre>
|
||
|
||
<h5 id="getting-started-installation-macports"><a href="#getting-started-installation-macports">MacPorts</a></h5>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>sudo port install hurl</code></pre>
|
||
|
||
<h4 id="getting-started-installation-freebsd"><a href="#getting-started-installation-freebsd">FreeBSD</a></h4>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>sudo pkg install hurl</code></pre>
|
||
|
||
<h4 id="getting-started-installation-windows"><a href="#getting-started-installation-windows">Windows</a></h4>
|
||
|
||
<p>Windows requires the <a href="https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version">Visual C++ Redistributable Package</a> to be installed manually, as this is not included in the installer.</p>
|
||
|
||
<h5 id="getting-started-installation-zip-file"><a href="#getting-started-installation-zip-file">Zip File</a></h5>
|
||
|
||
<p>Hurl can be installed from a standalone zip file at <a href="https://github.com/Orange-OpenSource/hurl/releases/latest">Hurl latest GitHub release</a>. You will need to update your <code>PATH</code> variable.</p>
|
||
|
||
<h5 id="getting-started-installation-installer"><a href="#getting-started-installation-installer">Installer</a></h5>
|
||
|
||
<p>An executable installer is also available at <a href="https://github.com/Orange-OpenSource/hurl/releases/latest">Hurl latest GitHub release</a>.</p>
|
||
|
||
<h5 id="getting-started-installation-chocolatey"><a href="#getting-started-installation-chocolatey">Chocolatey</a></h5>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>choco install hurl</code></pre>
|
||
|
||
<h5 id="getting-started-installation-scoop"><a href="#getting-started-installation-scoop">Scoop</a></h5>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>scoop install hurl</code></pre>
|
||
|
||
<h5 id="getting-started-installation-windows-package-manager"><a href="#getting-started-installation-windows-package-manager">Windows Package Manager</a></h5>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>winget install hurl</code></pre>
|
||
|
||
<h4 id="getting-started-installation-cargo"><a href="#getting-started-installation-cargo">Cargo</a></h4>
|
||
|
||
<p>If you’re a Rust programmer, Hurl can be installed with cargo.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>cargo install hurl</code></pre>
|
||
|
||
<h4 id="getting-started-installation-conda-forge"><a href="#getting-started-installation-conda-forge">conda-forge</a></h4>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>conda install -c conda-forge hurl</code></pre>
|
||
|
||
<p>Hurl can also be installed with <a href="https://conda-forge.org"><code>conda-forge</code></a> powered package manager like <a href="https://prefix.dev"><code>pixi</code></a>.</p>
|
||
|
||
<h4 id="getting-started-installation-docker"><a href="#getting-started-installation-docker">Docker</a></h4>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>docker pull ghcr.io/orange-opensource/hurl:latest</code></pre>
|
||
|
||
<h4 id="getting-started-installation-npm"><a href="#getting-started-installation-npm">npm</a></h4>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>npm install --save-dev @orangeopensource/hurl</code></pre>
|
||
|
||
<h3 id="getting-started-installation-building-from-sources"><a href="#getting-started-installation-building-from-sources">Building From Sources</a></h3>
|
||
|
||
<p>Hurl sources are available in <a href="https://github.com/Orange-OpenSource/hurl">GitHub</a>.</p>
|
||
|
||
<h4 id="getting-started-installation-build-on-linux"><a href="#getting-started-installation-build-on-linux">Build on Linux</a></h4>
|
||
|
||
<p>Hurl depends on libssl, libcurl and libxml2 native libraries. You will need their development files in your platform.</p>
|
||
|
||
<h5 id="getting-started-installation-debian-based-distributions"><a href="#getting-started-installation-debian-based-distributions">Debian based distributions</a></h5>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>apt install -y build-essential pkg-config libssl-dev libcurl4-openssl-dev libxml2-dev</code></pre>
|
||
|
||
<h5 id="getting-started-installation-fedora-based-distributions"><a href="#getting-started-installation-fedora-based-distributions">Fedora based distributions</a></h5>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>dnf install -y pkgconf-pkg-config gcc openssl-devel libxml2-devel</code></pre>
|
||
|
||
<h5 id="getting-started-installation-red-hat-based-distributions"><a href="#getting-started-installation-red-hat-based-distributions">Red Hat based distributions</a></h5>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>yum install -y pkg-config gcc openssl-devel libxml2-devel</code></pre>
|
||
|
||
<h5 id="getting-started-installation-arch-based-distributions"><a href="#getting-started-installation-arch-based-distributions">Arch based distributions</a></h5>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>pacman -S --noconfirm pkgconf gcc glibc openssl libxml2</code></pre>
|
||
|
||
<h5 id="getting-started-installation-alpine-based-distributions"><a href="#getting-started-installation-alpine-based-distributions">Alpine based distributions</a></h5>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>apk add curl-dev gcc libxml2-dev musl-dev openssl-dev</code></pre>
|
||
|
||
<h4 id="getting-started-installation-build-on-macos"><a href="#getting-started-installation-build-on-macos">Build on macOS</a></h4>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>xcode-select --install
|
||
<span class="prompt">$ </span>brew install pkg-config</code></pre>
|
||
|
||
<p>Hurl is written in <a href="https://www.rust-lang.org">Rust</a>. You should <a href="https://www.rust-lang.org/tools/install">install</a> the latest stable release.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||
<span class="prompt">$ </span>source $HOME/.cargo/env
|
||
<span class="prompt">$ </span>rustc --version
|
||
<span class="prompt">$ </span>cargo --version</code></pre>
|
||
|
||
<p>Then build hurl:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>git clone https://github.com/Orange-OpenSource/hurl
|
||
<span class="prompt">$ </span>cd hurl
|
||
<span class="prompt">$ </span>cargo build --release
|
||
<span class="prompt">$ </span>./target/release/hurl --version</code></pre>
|
||
|
||
<h4 id="getting-started-installation-build-on-windows"><a href="#getting-started-installation-build-on-windows">Build on Windows</a></h4>
|
||
|
||
<p>Please follow the <a href="https://github.com/Orange-OpenSource/hurl/blob/master/contrib/windows/README.md">contrib on Windows section</a>.</p>
|
||
|
||
<hr />
|
||
|
||
<h2 id="getting-started-manual-manual"><a href="#getting-started-manual-manual">Manual</a></h2>
|
||
|
||
<h3 id="getting-started-manual-name"><a href="#getting-started-manual-name">Name</a></h3>
|
||
|
||
<p>hurl - run and test HTTP requests.</p>
|
||
|
||
<h3 id="getting-started-manual-synopsis"><a href="#getting-started-manual-synopsis">Synopsis</a></h3>
|
||
|
||
<p><strong>hurl</strong> [options] [FILE...]</p>
|
||
|
||
<h3 id="getting-started-manual-description"><a href="#getting-started-manual-description">Description</a></h3>
|
||
|
||
<p><strong>Hurl</strong> is a command line tool that runs HTTP requests defined in a simple plain text format.</p>
|
||
|
||
<p>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.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl session.hurl</code></pre>
|
||
|
||
<p>If no input files are specified, input is read from stdin.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>echo GET http://httpbin.org/get | hurl
|
||
{
|
||
"args": {},
|
||
"headers": {
|
||
"Accept": "*/*",
|
||
"Accept-Encoding": "gzip",
|
||
"Content-Length": "0",
|
||
"Host": "httpbin.org",
|
||
"User-Agent": "hurl/0.99.10",
|
||
"X-Amzn-Trace-Id": "Root=1-5eedf4c7-520814d64e2f9249ea44e0"
|
||
},
|
||
"origin": "1.2.3.4",
|
||
"url": "http://httpbin.org/get"
|
||
}</code></pre>
|
||
|
||
<p>Hurl can take files as input, or directories. In the latter case, Hurl will search files with <code>.hurl</code> extension recursively.</p>
|
||
|
||
<p>Output goes to stdout by default. To have output go to a file, use the <a href="#getting-started-manual-output"><code>-o, --output</code></a> option:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl -o output input.hurl</code></pre>
|
||
|
||
<p>By default, Hurl executes all HTTP requests and outputs the response body of the last HTTP call.</p>
|
||
|
||
<p>To have a test oriented output, you can use <a href="#getting-started-manual-test"><code>--test</code></a> option:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test *.hurl</code></pre>
|
||
|
||
<h3 id="getting-started-manual-hurl-file-format"><a href="#getting-started-manual-hurl-file-format">Hurl File Format</a></h3>
|
||
|
||
<p>The Hurl file format is fully documented in <a href="https://hurl.dev/docs/hurl-file.html">https://hurl.dev/docs/hurl-file.html</a></p>
|
||
|
||
<p>It consists of one or several HTTP requests</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://example.org/endpoint1</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://example.org/endpoint2</span></span></span></span></code></pre>
|
||
|
||
<h4 id="getting-started-manual-capturing-values"><a href="#getting-started-manual-capturing-values">Capturing values</a></h4>
|
||
|
||
<p>A value from an HTTP response can be-reused for successive HTTP requests.</p>
|
||
|
||
<p>A typical example occurs with CSRF tokens.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"></span><span class="comment"># Capture the CSRF token value from html body.</span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">csrf_token</span>: <span class="query-type">xpath</span> <span class="string">"normalize-space(//meta[@name='_csrf_token']/@content)"</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Do the login !</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://example.org/login?user=toto&password=1234</span></span>
|
||
<span class="line"><span class="string">X-CSRF-TOKEN</span>: <span class="string">{{csrf_token}}</span></span></span></span></code></pre>
|
||
|
||
<p>More information on captures can be found here <a href="https://hurl.dev/docs/capturing-response.html">https://hurl.dev/docs/capturing-response.html</a></p>
|
||
|
||
<h4 id="getting-started-manual-asserts"><a href="#getting-started-manual-asserts">Asserts</a></h4>
|
||
|
||
<p>The HTTP response defined in the Hurl file are used to make asserts. Responses are optional.</p>
|
||
|
||
<p>At the minimum, response includes assert on the HTTP status code.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">301</span></span></span></span></code></pre>
|
||
|
||
<p>It can also include asserts on the response headers</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">301</span></span>
|
||
<span class="line"><span class="string">Location</span>: <span class="string">http://www.example.org</span></span></span></span></code></pre>
|
||
|
||
<p>Explicit asserts can be included by combining a query and a predicate</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">301</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"string(//title)"</span> <span class="predicate-type">==</span> <span class="string">"301 Moved"</span></span></span></span></code></pre>
|
||
|
||
<p>With the addition of asserts, Hurl can be used as a testing tool to run scenarios.</p>
|
||
|
||
<p>More information on asserts can be found here <a href="https://hurl.dev/docs/asserting-response.html">https://hurl.dev/docs/asserting-response.html</a></p>
|
||
|
||
<h3 id="getting-started-manual-options"><a href="#getting-started-manual-options">Options</a></h3>
|
||
|
||
<p>Options that exist in curl have exactly the same semantics.</p>
|
||
|
||
<p>Options specified on the command line are defined for every Hurl file’s entry,
|
||
except if they are tagged as cli-only (can not be defined in the Hurl request [Options] entry)</p>
|
||
|
||
<p>For instance:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --location foo.hurl</code></pre>
|
||
|
||
<p>will follow redirection for each entry in <code>foo.hurl</code>. You can also define an option only for a particular entry with an <code>[Options]</code> section. For instance, this Hurl file:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">301</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">location</span>: <span class="boolean">true</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p>will follow a redirection only for the second entry.</p>
|
||
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Option</th>
|
||
<th>Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-aws-sigv4" id="getting-started-manual-aws-sigv4"><code>--aws-sigv4 <PROVIDER1[:PROVIDER2[:REGION[:SERVICE]]]></code></a></td>
|
||
<td>Generate an <code>Authorization</code> header with an AWS SigV4 signature.<br /><br />Use <a href="#getting-started-manual-user"><code>-u, --user</code></a> to specify Access Key Id (username) and Secret Key (password).<br /><br />To use temporary session credentials (e.g. for an AWS IAM Role), add the <code>X-Amz-Security-Token</code> header containing the session token.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-cacert" id="getting-started-manual-cacert"><code>--cacert <FILE></code></a></td>
|
||
<td>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 /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-cert" id="getting-started-manual-cert"><code>-E, --cert <CERTIFICATE[:PASSWORD]></code></a></td>
|
||
<td>Client certificate file and password.<br /><br />See also <a href="#getting-started-manual-key"><code>--key</code></a>.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-color" id="getting-started-manual-color"><code>--color</code></a></td>
|
||
<td>Colorize debug output (the HTTP response output is not colorized).<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-compressed" id="getting-started-manual-compressed"><code>--compressed</code></a></td>
|
||
<td>Request a compressed response using one of the algorithms br, gzip, deflate and automatically decompress the content.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-connect-timeout" id="getting-started-manual-connect-timeout"><code>--connect-timeout <SECONDS></code></a></td>
|
||
<td>Maximum time in seconds that you allow Hurl’s connection to take.<br /><br />You can specify time units in the connect timeout expression. Set Hurl to use a connect timeout of 20 seconds with <code>--connect-timeout 20s</code> or set it to 35,000 milliseconds with <code>--connect-timeout 35000ms</code>. No spaces allowed.<br /><br />See also <a href="#getting-started-manual-max-time"><code>-m, --max-time</code></a>.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-connect-to" id="getting-started-manual-connect-to"><code>--connect-to <HOST1:PORT1:HOST2:PORT2></code></a></td>
|
||
<td>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 <a href="#getting-started-manual-resolve"><code>--resolve</code></a>.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-continue-on-error" id="getting-started-manual-continue-on-error"><code>--continue-on-error</code></a></td>
|
||
<td>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 /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-cookie" id="getting-started-manual-cookie"><code>-b, --cookie <FILE></code></a></td>
|
||
<td>Read cookies from FILE (using the Netscape cookie file format).<br /><br />Combined with <a href="#getting-started-manual-cookie-jar"><code>-c, --cookie-jar</code></a>, you can simulate a cookie storage between successive Hurl runs.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-cookie-jar" id="getting-started-manual-cookie-jar"><code>-c, --cookie-jar <FILE></code></a></td>
|
||
<td>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 <a href="#getting-started-manual-cookie"><code>-b, --cookie</code></a>, you can simulate a cookie storage between successive Hurl runs.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-curl" id="getting-started-manual-curl"><code>--curl <FILE></code></a></td>
|
||
<td>Export each request to a list of curl commands.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-delay" id="getting-started-manual-delay"><code>--delay <MILLISECONDS></code></a></td>
|
||
<td>Sets delay before each request. The delay is not applied to requests that have been retried because of <a href="#getting-started-manual-retry"><code>--retry</code></a>. See <a href="#getting-started-manual-retry-interval"><code>--retry-interval</code></a> to space retried requests.<br /><br />You can specify time units in the delay expression. Set Hurl to use a delay of 2 seconds with <code>--delay 2s</code> or set it to 500 milliseconds with <code>--delay 500ms</code>. No spaces allowed.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-error-format" id="getting-started-manual-error-format"><code>--error-format <FORMAT></code></a></td>
|
||
<td>Control the format of error message (short by default or long)<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-file-root" id="getting-started-manual-file-root"><code>--file-root <DIR></code></a></td>
|
||
<td>Set root directory to import files in Hurl. This is used for files in multipart form data, request body and response output.<br />When it is not explicitly defined, files are relative to the Hurl file’s directory.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-from-entry" id="getting-started-manual-from-entry"><code>--from-entry <ENTRY_NUMBER></code></a></td>
|
||
<td>Execute Hurl file from ENTRY_NUMBER (starting at 1).<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-glob" id="getting-started-manual-glob"><code>--glob <GLOB></code></a></td>
|
||
<td>Specify input files that match the given glob pattern.<br /><br />Multiple glob flags may be used. This flag supports common Unix glob patterns like *, ? and [].<br />However, to avoid your shell accidentally expanding glob patterns before Hurl handles them, you must use single quotes or double quotes around each pattern.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-http10" id="getting-started-manual-http10"><code>-0, --http1.0</code></a></td>
|
||
<td>Tells Hurl to use HTTP version 1.0 instead of using its internally preferred HTTP version.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-http11" id="getting-started-manual-http11"><code>--http1.1</code></a></td>
|
||
<td>Tells Hurl to use HTTP version 1.1.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-http2" id="getting-started-manual-http2"><code>--http2</code></a></td>
|
||
<td>Tells Hurl to use HTTP version 2.<br />For HTTPS, this means Hurl negotiates HTTP/2 in the TLS handshake. Hurl does this by default.<br />For HTTP, this means Hurl attempts to upgrade the request to HTTP/2 using the Upgrade: request header.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-http3" id="getting-started-manual-http3"><code>--http3</code></a></td>
|
||
<td>Tells Hurl to try HTTP/3 to the host in the URL, but fallback to earlier HTTP versions if the HTTP/3 connection establishment fails. HTTP/3 is only available for HTTPS and not for HTTP URLs.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-ignore-asserts" id="getting-started-manual-ignore-asserts"><code>--ignore-asserts</code></a></td>
|
||
<td>Ignore all asserts defined in the Hurl file.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-include" id="getting-started-manual-include"><code>-i, --include</code></a></td>
|
||
<td>Include the HTTP headers in the output<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-insecure" id="getting-started-manual-insecure"><code>-k, --insecure</code></a></td>
|
||
<td>This option explicitly allows Hurl to perform “insecure” SSL connections and transfers.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-interactive" id="getting-started-manual-interactive"><code>--interactive</code></a></td>
|
||
<td>Stop between requests.<br /><br />This is similar to a break point, You can then continue (Press C) or quit (Press Q).<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-ipv4" id="getting-started-manual-ipv4"><code>-4, --ipv4</code></a></td>
|
||
<td>This option tells Hurl to use IPv4 addresses only when resolving host names, and not for example try IPv6.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-ipv6" id="getting-started-manual-ipv6"><code>-6, --ipv6</code></a></td>
|
||
<td>This option tells Hurl to use IPv6 addresses only when resolving host names, and not for example try IPv4.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-jobs" id="getting-started-manual-jobs"><code>--jobs <NUM></code></a></td>
|
||
<td>Maximum number of parallel jobs in parallel mode. Default value corresponds (in most cases) to the<br />current amount of CPUs.<br /><br />See also <a href="#getting-started-manual-parallel"><code>--parallel</code></a>.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-json" id="getting-started-manual-json"><code>--json</code></a></td>
|
||
<td>Output each Hurl file result to JSON. The format is very closed to HAR format.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-key" id="getting-started-manual-key"><code>--key <KEY></code></a></td>
|
||
<td>Private key file name.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-limit-rate" id="getting-started-manual-limit-rate"><code>--limit-rate <SPEED></code></a></td>
|
||
<td>Specify the maximum transfer rate you want Hurl to use, for both downloads and uploads. This feature is useful if you have a limited pipe and you would like your transfer not to use your entire bandwidth. To make it slower than it otherwise would be.<br />The given speed is measured in bytes/second.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-location" id="getting-started-manual-location"><code>-L, --location</code></a></td>
|
||
<td>Follow redirect. To limit the amount of redirects to follow use the <a href="#getting-started-manual-max-redirs"><code>--max-redirs</code></a> option<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-location-trusted" id="getting-started-manual-location-trusted"><code>--location-trusted</code></a></td>
|
||
<td>Like <a href="#getting-started-manual-location"><code>-L, --location</code></a>, but allows sending the name + password to all hosts that the site may redirect to.<br />This may or may not introduce a security breach if the site redirects you to a site to which you send your authentication info (which is plaintext in the case of HTTP Basic authentication).<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-max-filesize" id="getting-started-manual-max-filesize"><code>--max-filesize <BYTES></code></a></td>
|
||
<td>Specify the maximum size in bytes of a file to download. If the file requested is larger than this value, the transfer does not start.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-max-redirs" id="getting-started-manual-max-redirs"><code>--max-redirs <NUM></code></a></td>
|
||
<td>Set maximum number of redirection-followings allowed<br /><br />By default, the limit is set to 50 redirections. Set this option to -1 to make it unlimited.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-max-time" id="getting-started-manual-max-time"><code>-m, --max-time <SECONDS></code></a></td>
|
||
<td>Maximum time in seconds that you allow a request/response to take. This is the standard timeout.<br /><br />You can specify time units in the maximum time expression. Set Hurl to use a maximum time of 20 seconds with <code>--max-time 20s</code> or set it to 35,000 milliseconds with <code>--max-time 35000ms</code>. No spaces allowed.<br /><br />See also <a href="#getting-started-manual-connect-timeout"><code>--connect-timeout</code></a>.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-netrc" id="getting-started-manual-netrc"><code>-n, --netrc</code></a></td>
|
||
<td>Scan the .netrc file in the user’s home directory for the username and password.<br /><br />See also <a href="#getting-started-manual-netrc-file"><code>--netrc-file</code></a> and <a href="#getting-started-manual-netrc-optional"><code>--netrc-optional</code></a>.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-netrc-file" id="getting-started-manual-netrc-file"><code>--netrc-file <FILE></code></a></td>
|
||
<td>Like <a href="#getting-started-manual-netrc"><code>--netrc</code></a>, but provide the path to the netrc file.<br /><br />See also <a href="#getting-started-manual-netrc-optional"><code>--netrc-optional</code></a>.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-netrc-optional" id="getting-started-manual-netrc-optional"><code>--netrc-optional</code></a></td>
|
||
<td>Similar to <a href="#getting-started-manual-netrc"><code>--netrc</code></a>, but make the .netrc usage optional.<br /><br />See also <a href="#getting-started-manual-netrc-file"><code>--netrc-file</code></a>.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-no-color" id="getting-started-manual-no-color"><code>--no-color</code></a></td>
|
||
<td>Do not colorize output.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-no-output" id="getting-started-manual-no-output"><code>--no-output</code></a></td>
|
||
<td>Suppress output. By default, Hurl outputs the body of the last response.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-noproxy" id="getting-started-manual-noproxy"><code>--noproxy <HOST(S)></code></a></td>
|
||
<td>Comma-separated list of hosts which do not use a proxy.<br /><br />Override value from Environment variable no_proxy.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-output" id="getting-started-manual-output"><code>-o, --output <FILE></code></a></td>
|
||
<td>Write output to FILE instead of stdout.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-parallel" id="getting-started-manual-parallel"><code>--parallel</code></a></td>
|
||
<td>Run files in parallel.<br /><br />Each Hurl file is executed in its own worker thread, without sharing anything with the other workers. The default run mode is sequential. Parallel execution is by default in <a href="#getting-started-manual-test"><code>--test</code></a> mode.<br /><br />See also <a href="#getting-started-manual-jobs"><code>--jobs</code></a>.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-path-as-is" id="getting-started-manual-path-as-is"><code>--path-as-is</code></a></td>
|
||
<td>Tell Hurl to not handle sequences of /../ or /./ in the given URL path. Normally Hurl will squash or merge them according to standards but with this option set you tell it not to do that.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-proxy" id="getting-started-manual-proxy"><code>-x, --proxy <[PROTOCOL://]HOST[:PORT]></code></a></td>
|
||
<td>Use the specified proxy.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-repeat" id="getting-started-manual-repeat"><code>--repeat <NUM></code></a></td>
|
||
<td>Repeat the input files sequence NUM times, -1 for infinite loop. Given a.hurl, b.hurl, c.hurl as input, repeat two<br />times will run a.hurl, b.hurl, c.hurl, a.hurl, b.hurl, c.hurl.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-report-html" id="getting-started-manual-report-html"><code>--report-html <DIR></code></a></td>
|
||
<td>Generate HTML report in DIR.<br /><br />If the HTML report already exists, it will be updated with the new test results.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-report-json" id="getting-started-manual-report-json"><code>--report-json <DIR></code></a></td>
|
||
<td>Generate JSON report in DIR.<br /><br />If the JSON report already exists, it will be updated with the new test results.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-report-junit" id="getting-started-manual-report-junit"><code>--report-junit <FILE></code></a></td>
|
||
<td>Generate JUnit File.<br /><br />If the FILE report already exists, it will be updated with the new test results.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-report-tap" id="getting-started-manual-report-tap"><code>--report-tap <FILE></code></a></td>
|
||
<td>Generate TAP report.<br /><br />If the FILE report already exists, it will be updated with the new test results.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-resolve" id="getting-started-manual-resolve"><code>--resolve <HOST:PORT:ADDR></code></a></td>
|
||
<td>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 /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-retry" id="getting-started-manual-retry"><code>--retry <NUM></code></a></td>
|
||
<td>Maximum number of retries, 0 for no retries, -1 for unlimited retries. Retry happens if any error occurs (asserts, captures, runtimes etc...).<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-retry-interval" id="getting-started-manual-retry-interval"><code>--retry-interval <MILLISECONDS></code></a></td>
|
||
<td>Duration in milliseconds between each retry. Default is 1000 ms.<br /><br />You can specify time units in the retry interval expression. Set Hurl to use a retry interval of 2 seconds with <code>--retry-interval 2s</code> or set it to 500 milliseconds with <code>--retry-interval 500ms</code>. No spaces allowed.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-ssl-no-revoke" id="getting-started-manual-ssl-no-revoke"><code>--ssl-no-revoke</code></a></td>
|
||
<td>(Windows) This option tells Hurl to disable certificate revocation checks. WARNING: this option loosens the SSL security, and by using this flag you ask for exactly that.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-test" id="getting-started-manual-test"><code>--test</code></a></td>
|
||
<td>Activate test mode: with this, the HTTP response is not outputted anymore, progress is reported for each Hurl file tested, and a text summary is displayed when all files have been run.<br /><br />In test mode, files are executed in parallel. To run test in a sequential way use <code>--job 1</code>.<br /><br />See also <a href="#getting-started-manual-jobs"><code>--jobs</code></a>.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-to-entry" id="getting-started-manual-to-entry"><code>--to-entry <ENTRY_NUMBER></code></a></td>
|
||
<td>Execute Hurl file to ENTRY_NUMBER (starting at 1).<br />Ignore the remaining of the file. It is useful for debugging a session.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-unix-socket" id="getting-started-manual-unix-socket"><code>--unix-socket <PATH></code></a></td>
|
||
<td>(HTTP) Connect through this Unix domain socket, instead of using the network.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-user" id="getting-started-manual-user"><code>-u, --user <USER:PASSWORD></code></a></td>
|
||
<td>Add basic Authentication header to each request.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-user-agent" id="getting-started-manual-user-agent"><code>-A, --user-agent <NAME></code></a></td>
|
||
<td>Specify the User-Agent string to send to the HTTP server.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-variable" id="getting-started-manual-variable"><code>--variable <NAME=VALUE></code></a></td>
|
||
<td>Define variable (name/value) to be used in Hurl templates.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-variables-file" id="getting-started-manual-variables-file"><code>--variables-file <FILE></code></a></td>
|
||
<td>Set properties file in which your define your variables.<br /><br />Each variable is defined as name=value exactly as with <a href="#getting-started-manual-variable"><code>--variable</code></a> option.<br /><br />Note that defining a variable twice produces an error.<br /><br />This is a cli-only option.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-verbose" id="getting-started-manual-verbose"><code>-v, --verbose</code></a></td>
|
||
<td>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, <a href="#getting-started-manual-include"><code>-i, --include</code></a> might be the option you’re looking for.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-very-verbose" id="getting-started-manual-very-verbose"><code>--very-verbose</code></a></td>
|
||
<td>Turn on more verbose output on standard error stream.<br /><br />In contrast to <a href="#getting-started-manual-verbose"><code>--verbose</code></a> option, this option outputs the full HTTP body request and response on standard error. In addition, lines starting with ‘**’ are libcurl debug logs.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-help" id="getting-started-manual-help"><code>-h, --help</code></a></td>
|
||
<td>Usage help. This lists all current command line options with a short description.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a href="#getting-started-manual-version" id="getting-started-manual-version"><code>-V, --version</code></a></td>
|
||
<td>Prints version information<br /></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3 id="getting-started-manual-environment"><a href="#getting-started-manual-environment">Environment</a></h3>
|
||
|
||
<p>Environment variables can only be specified in lowercase.</p>
|
||
|
||
<p>Using an environment variable to set the proxy has the same effect as using the <a href="#getting-started-manual-proxy"><code>-x, --proxy</code></a> option.</p>
|
||
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Variable</th>
|
||
<th>Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>http_proxy [PROTOCOL://]<HOST>[:PORT]</code></td>
|
||
<td>Sets the proxy server to use for HTTP.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>https_proxy [PROTOCOL://]<HOST>[:PORT]</code></td>
|
||
<td>Sets the proxy server to use for HTTPS.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>all_proxy [PROTOCOL://]<HOST>[:PORT]</code></td>
|
||
<td>Sets the proxy server to use if no protocol-specific proxy is set.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>no_proxy <comma-separated list of hosts></code></td>
|
||
<td>List of host names that shouldn’t go through any proxy.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>HURL_name value</code></td>
|
||
<td>Define variable (name/value) to be used in Hurl templates. This is similar than <a href="#getting-started-manual-variable"><code>--variable</code></a> and <a href="#getting-started-manual-variables-file"><code>--variables-file</code></a> options.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>NO_COLOR</code></td>
|
||
<td>When set to a non-empty string, do not colorize output (see <a href="#getting-started-manual-no-color"><code>--no-color</code></a> option).<br /></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3 id="getting-started-manual-exit-codes"><a href="#getting-started-manual-exit-codes">Exit Codes</a></h3>
|
||
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Value</th>
|
||
<th>Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>0</code></td>
|
||
<td>Success.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>1</code></td>
|
||
<td>Failed to parse command-line options.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>2</code></td>
|
||
<td>Input File Parsing Error.<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>3</code></td>
|
||
<td>Runtime error (such as failure to connect to host).<br /></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>4</code></td>
|
||
<td>Assert Error.<br /></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3 id="getting-started-manual-www"><a href="#getting-started-manual-www">WWW</a></h3>
|
||
|
||
<p><a href="https://hurl.dev">https://hurl.dev</a></p>
|
||
|
||
<h3 id="getting-started-manual-see-also"><a href="#getting-started-manual-see-also">See Also</a></h3>
|
||
|
||
<p>curl(1) hurlfmt(1)</p>
|
||
|
||
<hr />
|
||
|
||
<h2 id="getting-started-samples-samples"><a href="#getting-started-samples-samples">Samples</a></h2>
|
||
|
||
<p>To run a sample, edit a file with the sample content, and run Hurl:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>vi sample.hurl
|
||
|
||
GET https://example.org
|
||
|
||
<span class="prompt">$ </span>hurl sample.hurl</code></pre>
|
||
|
||
<p>By default, Hurl behaves like <a href="https://curl.se">curl</a> and outputs the last HTTP response’s <a href="#file-format-entry">entry</a>. To have a test
|
||
oriented output, you can use <a href="#getting-started-manual-test"><code>--test</code> option</a>:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test sample.hurl</code></pre>
|
||
|
||
<p>A particular response can be saved with <a href="#file-format-request-options"><code>[Options] section</code></a>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.ord/cats/123</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">output</span>: <span class="filename">cat123.txt</span></span> <span class="comment"># use - to output to stdout</span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.ord/dogs/567</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p>Finally, Hurl can take files as input, or directories. In the latter case, Hurl will search files with <code>.hurl</code> extension recursively.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test integration/*.hurl
|
||
<span class="prompt">$ </span>hurl --test .</code></pre>
|
||
|
||
<p>You can check <a href="https://github.com/Orange-OpenSource/hurl/tree/master/integration/hurl/tests_ok">Hurl tests suite</a> for more samples.</p>
|
||
|
||
<h3 id="getting-started-samples-getting-data"><a href="#getting-started-samples-getting-data">Getting Data</a></h3>
|
||
|
||
<p>A simple GET:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span></span></span></code></pre>
|
||
|
||
<p>Requests can be chained:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/a</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/b</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"><span class="method">HEAD</span> <span class="url">https://example.org/c</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/c</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-request-method">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-http-headers"><a href="#getting-started-samples-http-headers">HTTP Headers</a></h4>
|
||
|
||
<p>A simple GET with headers:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/news</span></span>
|
||
<span class="line"><span class="string">User-Agent</span>: <span class="string">Mozilla/5.0</span></span>
|
||
<span class="line"><span class="string">Accept</span>: <span class="string">*/*</span></span>
|
||
<span class="line"><span class="string">Accept-Language</span>: <span class="string">en-US,en;q=0.5</span></span>
|
||
<span class="line"><span class="string">Accept-Encoding</span>: <span class="string">gzip, deflate, br</span></span>
|
||
<span class="line"><span class="string">Connection</span>: <span class="string">keep-alive</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-request-headers">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-query-params"><a href="#getting-started-samples-query-params">Query Params</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/news</span></span>
|
||
<span class="line"><span class="section-header">[QueryStringParams]</span></span>
|
||
<span class="line"><span class="string">order</span>: <span class="string">newest</span></span>
|
||
<span class="line"><span class="string">search</span>: <span class="string">something to search</span></span>
|
||
<span class="line"><span class="string">count</span>: <span class="string">100</span></span></span></span></code></pre>
|
||
|
||
<p>Or:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/news?order=newest&search=something%20to%20search&count=100</span></span></span></span></code></pre>
|
||
|
||
<blockquote>
|
||
<p>With <code>[QueryStringParams]</code> section, params don’t need to be URL escaped.</p>
|
||
</blockquote>
|
||
|
||
<p><a href="#file-format-request-query-parameters">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-basic-authentication"><a href="#getting-started-samples-basic-authentication">Basic Authentication</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/protected</span></span>
|
||
<span class="line"><span class="section-header">[BasicAuth]</span></span>
|
||
<span class="line"><span class="string">bob</span>: <span class="string">secret</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-request-basic-authentication">Doc</a></p>
|
||
|
||
<p>This is equivalent to construct the request with a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization">Authorization</a> header:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Authorization header value can be computed with `echo -n 'bob:secret' | base64`</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/protected</span></span>
|
||
<span class="line"><span class="string">Authorization</span>: <span class="string">Basic Ym9iOnNlY3JldA==</span></span></span></span></code></pre>
|
||
|
||
<p>Basic authentication section allows per request authentication. If you want to add basic authentication to all the
|
||
requests of a Hurl file you could use <a href="#getting-started-manual-user"><code>-u/--user</code> option</a>:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --user bob:secret login.hurl</code></pre>
|
||
|
||
<p><a href="#getting-started-manual-user"><code>--user</code></a> option can also be set per request:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/login</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">user</span>: <span class="string">bob:secret</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/login</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">user</span>: <span class="string">alice:secret</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<h4 id="getting-started-samples-passing-data-between-requests"><a href="#getting-started-samples-passing-data-between-requests">Passing Data between Requests</a></h4>
|
||
|
||
<p><a href="#file-format-capturing-response">Captures</a> can be used to pass data from one request to another:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://sample.org/orders</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">201</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">order_id</span>: <span class="query-type">jsonpath</span> <span class="string">"$.order.id"</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://sample.org/orders/{{order_id}}</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-capturing-response">Doc</a></p>
|
||
|
||
<h3 id="getting-started-samples-sending-data"><a href="#getting-started-samples-sending-data">Sending Data</a></h3>
|
||
|
||
<h4 id="getting-started-samples-sending-html-form-data"><a href="#getting-started-samples-sending-html-form-data">Sending HTML Form Data</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/contact</span></span>
|
||
<span class="line"><span class="section-header">[FormParams]</span></span>
|
||
<span class="line"><span class="string">default</span>: <span class="string">false</span></span>
|
||
<span class="line"><span class="string">token</span>: <span class="string">{{token}}</span></span>
|
||
<span class="line"><span class="string">email</span>: <span class="string">john.doe@rookie.org</span></span>
|
||
<span class="line"><span class="string">number</span>: <span class="string">33611223344</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-request-form-parameters">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-sending-multipart-form-data"><a href="#getting-started-samples-sending-multipart-form-data">Sending Multipart Form Data</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/upload</span></span>
|
||
<span class="line"><span class="section-header">[MultipartFormData]</span></span>
|
||
<span class="line"><span class="string">field1</span>: <span class="string">value1</span></span>
|
||
<span class="line"><span class="string">field2</span>: file,<span class="filename">example.txt</span>;</span>
|
||
<span class="line"></span><span class="comment"># One can specify the file content type:</span>
|
||
<span class="line"><span class="string">field3</span>: file,<span class="filename">example.zip</span>; <span class="string">application/zip</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-request-multipart-form-data">Doc</a></p>
|
||
|
||
<p>Multipart forms can also be sent with a <a href="#file-format-request-multiline-string-body">multiline string body</a>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/upload</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">multipart/form-data; boundary="boundary"</span></span>
|
||
<span class="multiline"><span class="line">```</span>
|
||
<span class="line">--boundary</span>
|
||
<span class="line">Content-Disposition: form-data; name="key1"</span>
|
||
<span class="line"></span>
|
||
<span class="line">value1</span>
|
||
<span class="line">--boundary</span>
|
||
<span class="line">Content-Disposition: form-data; name="upload1"; filename="data.txt"</span>
|
||
<span class="line">Content-Type: text/plain</span>
|
||
<span class="line"></span>
|
||
<span class="line">Hello World!</span>
|
||
<span class="line">--boundary</span>
|
||
<span class="line">Content-Disposition: form-data; name="upload2"; filename="data.html"</span>
|
||
<span class="line">Content-Type: text/html</span>
|
||
<span class="line"></span>
|
||
<span class="line"><div>Hello <b>World</b>!</div></span>
|
||
<span class="line">--boundary--</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<p>In that case, files have to be inlined in the Hurl file.</p>
|
||
|
||
<p><a href="#file-format-request-multiline-string-body">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-posting-a-json-body"><a href="#getting-started-samples-posting-a-json-body">Posting a JSON Body</a></h4>
|
||
|
||
<p>With an inline JSON:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/api/tests</span></span>
|
||
<span class="json"><span class="line">{</span>
|
||
<span class="line"> "id": "456",</span>
|
||
<span class="line"> "evaluate": true</span>
|
||
<span class="line">}</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-request-json-body">Doc</a></p>
|
||
|
||
<p>With a local file:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/api/tests</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">application/json</span></span>
|
||
<span class="line">file,<span class="filename">data.json</span>;</span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-request-file-body">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-templating-a-json-body"><a href="#getting-started-samples-templating-a-json-body">Templating a JSON Body</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">PUT</span> <span class="url">https://example.org/api/hits</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">application/json</span></span>
|
||
<span class="json"><span class="line">{</span>
|
||
<span class="line"> "key0": "{{a_string}}",</span>
|
||
<span class="line"> "key1": {{a_bool}},</span>
|
||
<span class="line"> "key2": {{a_null}},</span>
|
||
<span class="line"> "key3": {{a_number}}</span>
|
||
<span class="line">}</span></span></span></span></code></pre>
|
||
|
||
<p>Variables can be initialized via command line:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --variable a_string=apple \
|
||
--variable a_bool=true \
|
||
--variable a_null=null \
|
||
--variable a_number=42 \
|
||
test.hurl</code></pre>
|
||
|
||
<p>Resulting in a PUT request with the following JSON body:</p>
|
||
|
||
<pre><code>{
|
||
"key0": "apple",
|
||
"key1": true,
|
||
"key2": null,
|
||
"key3": 42
|
||
}
|
||
</code></pre>
|
||
|
||
<p><a href="#file-format-templates">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-templating-a-xml-body"><a href="#getting-started-samples-templating-a-xml-body">Templating a XML Body</a></h4>
|
||
|
||
<p>Using templates with <a href="#file-format-request-xml-body">XML body</a> is not currently supported in Hurl. You can use templates in
|
||
<a href="#file-format-request-multiline-string-body">XML multiline string body</a> with variables to send a variable XML body:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/echo/post/xml</span></span>
|
||
<span class="multiline"><span class="line">```xml</span>
|
||
<span class="line"><?xml version="1.0" encoding="utf-8"?></span>
|
||
<span class="line"><Request></span>
|
||
<span class="line"> <Login>{{login}}</Login></span>
|
||
<span class="line"> <Password>{{password}}</Password></span>
|
||
<span class="line"></Request></span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-request-multiline-string-body">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-using-graphql-query"><a href="#getting-started-samples-using-graphql-query">Using GraphQL Query</a></h4>
|
||
|
||
<p>A simple GraphQL query:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/starwars/graphql</span></span>
|
||
<span class="multiline"><span class="line">```graphql</span>
|
||
<span class="line">{</span>
|
||
<span class="line"> human(id: "1000") {</span>
|
||
<span class="line"> name</span>
|
||
<span class="line"> height(unit: FOOT)</span>
|
||
<span class="line"> }</span>
|
||
<span class="line">}</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<p>A GraphQL query with variables:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/starwars/graphql</span></span>
|
||
<span class="multiline"><span class="line">```graphql</span>
|
||
<span class="line">query Hero($episode: Episode, $withFriends: Boolean!) {</span>
|
||
<span class="line"> hero(episode: $episode) {</span>
|
||
<span class="line"> name</span>
|
||
<span class="line"> friends @include(if: $withFriends) {</span>
|
||
<span class="line"> name</span>
|
||
<span class="line"> }</span>
|
||
<span class="line"> }</span>
|
||
<span class="line">}</span>
|
||
<span class="line"></span>
|
||
<span class="line">variables {</span>
|
||
<span class="line"> "episode": "JEDI",</span>
|
||
<span class="line"> "withFriends": false</span>
|
||
<span class="line">}</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<p>GraphQL queries can also use <a href="#file-format-templates">Hurl templates</a>.</p>
|
||
|
||
<p><a href="#file-format-request-graphql-body">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-using-dynamic-datas"><a href="#getting-started-samples-using-dynamic-datas">Using Dynamic Datas</a></h4>
|
||
|
||
<p><a href="#file-format-templates-functions">Functions</a> like <code>newUuid</code> and <code>newDate</code> can be used in templates to create dynamic datas:</p>
|
||
|
||
<p>A file that creates a dynamic email (i.e <code>0531f78f-7f87-44be-a7f2-969a1c4e6d97@test.com</code>):</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/api/foo</span></span>
|
||
<span class="json"><span class="line">{</span>
|
||
<span class="line"> "name": "foo",</span>
|
||
<span class="line"> "email": "{{newUuid}}@test.com"</span>
|
||
<span class="line">}</span></span></span></span></code></pre>
|
||
|
||
<p>A file that creates a dynamic query parameter (i.e <code>2024-12-02T10:35:44.461731Z</code>):</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/foo</span></span>
|
||
<span class="line"><span class="section-header">[QueryStringParams]</span></span>
|
||
<span class="line"><span class="string">date</span>: <span class="string">{{newDate}}</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-templates-functions">Doc</a></p>
|
||
|
||
<h3 id="getting-started-samples-testing-response"><a href="#getting-started-samples-testing-response">Testing Response</a></h3>
|
||
|
||
<p>Responses are optional, everything after <code>HTTP</code> is part of the response asserts.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># A request with (almost) no check:</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://foo.com</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># A status code check:</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://foo.com</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># A test on response body</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://foo.com</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.state"</span> <span class="predicate-type">==</span> <span class="string">"running"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="getting-started-samples-testing-status-code"><a href="#getting-started-samples-testing-status-code">Testing Status Code</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/order/435</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-version-status">Doc</a></p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/order/435</span></span>
|
||
</span><span class="response"><span class="line"></span><span class="comment"># Testing status code is in a 200-300 range</span>
|
||
<span class="line"><span class="version">HTTP</span> <span class="number">*</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">status</span> <span class="predicate-type">>=</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="query-type">status</span> <span class="predicate-type"><</span> <span class="number">300</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-status-assert">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-testing-response-headers"><a href="#getting-started-samples-testing-response-headers">Testing Response Headers</a></h4>
|
||
|
||
<p>Use implicit response asserts to test header values:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/index.html</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="string">Set-Cookie</span>: <span class="string">theme=light</span></span>
|
||
<span class="line"><span class="string">Set-Cookie</span>: <span class="string">sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-headers">Doc</a></p>
|
||
|
||
<p>Or use explicit response asserts with <a href="#file-format-asserting-response-predicates">predicates</a>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">302</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Location"</span> <span class="predicate-type">contains</span> <span class="string">"www.example.net"</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-header-assert">Doc</a></p>
|
||
|
||
<p>Implicit and explicit asserts can be combined:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/index.html</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="string">Set-Cookie</span>: <span class="string">theme=light</span></span>
|
||
<span class="line"><span class="string">Set-Cookie</span>: <span class="string">sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Location"</span> <span class="predicate-type">contains</span> <span class="string">"www.example.net"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="getting-started-samples-testing-rest-apis"><a href="#getting-started-samples-testing-rest-apis">Testing REST APIs</a></h4>
|
||
|
||
<p>Asserting JSON body response (node values, collection count etc...) with <a href="https://goessner.net/articles/JsonPath/">JSONPath</a>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/order</span></span>
|
||
<span class="line"><span class="string">screencapability</span>: <span class="string">low</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.validated"</span> <span class="predicate-type">==</span> <span class="boolean">true</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.userInfo.firstName"</span> <span class="predicate-type">==</span> <span class="string">"Franck"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.userInfo.lastName"</span> <span class="predicate-type">==</span> <span class="string">"Herbert"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.hasDevice"</span> <span class="predicate-type">==</span> <span class="boolean">false</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.links"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">12</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.state"</span> <span class="predicate-type">!=</span> <span class="null">null</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.order"</span> <span class="predicate-type">matches</span> <span class="string">"^order-\\d{8}$"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.order"</span> <span class="predicate-type">matches</span> <span class="regex">/^order-\d{8}$/</span></span> <span class="comment"># Alternative syntax with regex literal</span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.created"</span> <span class="predicate-type">isIsoDate</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-jsonpath-assert">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-testing-html-response"><a href="#getting-started-samples-testing-html-response">Testing HTML Response</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">text/html; charset=UTF-8</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"string(/html/head/title)"</span> <span class="predicate-type">contains</span> <span class="string">"Example"</span></span> <span class="comment"># Check title</span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"count(//p)"</span> <span class="predicate-type">==</span> <span class="number">2</span></span> <span class="comment"># Check the number of p</span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"//p"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">2</span></span> <span class="comment"># Similar assert for p</span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"boolean(count(//h2))"</span> <span class="predicate-type">==</span> <span class="boolean">false</span></span> <span class="comment"># Check there is no h2 </span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"//h2"</span> <span class="not">not</span> <span class="predicate-type">exists</span></span> <span class="comment"># Similar assert for h2</span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"string(//div[1])"</span> <span class="predicate-type">matches</span> <span class="regex">/Hello.*/</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-xpath-assert">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-testing-set-cookie-attributes"><a href="#getting-started-samples-testing-set-cookie-attributes">Testing Set-Cookie Attributes</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/home</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"JSESSIONID"</span> <span class="predicate-type">==</span> <span class="string">"8400BAFE2F66443613DC38AE3D9D6239"</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"JSESSIONID[Value]"</span> <span class="predicate-type">==</span> <span class="string">"8400BAFE2F66443613DC38AE3D9D6239"</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"JSESSIONID[Expires]"</span> <span class="predicate-type">contains</span> <span class="string">"Wed, 13 Jan 2021"</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"JSESSIONID[Secure]"</span> <span class="predicate-type">exists</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"JSESSIONID[HttpOnly]"</span> <span class="predicate-type">exists</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"JSESSIONID[SameSite]"</span> <span class="predicate-type">==</span> <span class="string">"Lax"</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-cookie-assert">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-testing-bytes-content"><a href="#getting-started-samples-testing-bytes-content">Testing Bytes Content</a></h4>
|
||
|
||
<p>Check the SHA-256 response body hash:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/data.tar.gz</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">sha256</span> <span class="predicate-type">==</span> hex,<span class="hex">039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81</span>;</span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-sha-256-assert">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-ssl-certificate"><a href="#getting-started-samples-ssl-certificate">SSL Certificate</a></h4>
|
||
|
||
<p>Check the properties of a SSL certificate:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">certificate</span> <span class="string">"Subject"</span> <span class="predicate-type">==</span> <span class="string">"CN=example.org"</span></span>
|
||
<span class="line"><span class="query-type">certificate</span> <span class="string">"Issuer"</span> <span class="predicate-type">==</span> <span class="string">"C=US, O=Let's Encrypt, CN=R3"</span></span>
|
||
<span class="line"><span class="query-type">certificate</span> <span class="string">"Expire-Date"</span> <span class="filter-type">daysAfterNow</span> <span class="predicate-type">></span> <span class="number">15</span></span>
|
||
<span class="line"><span class="query-type">certificate</span> <span class="string">"Serial-Number"</span> <span class="predicate-type">matches</span> <span class="regex">/[\da-f]+/</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-ssl-certificate-assert">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-checking-full-body"><a href="#getting-started-samples-checking-full-body">Checking Full Body</a></h4>
|
||
|
||
<p>Use implicit body to test an exact JSON body match:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/cats/123</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="json"><span class="line">{</span>
|
||
<span class="line"> "name" : "Purrsloud",</span>
|
||
<span class="line"> "species" : "Cat",</span>
|
||
<span class="line"> "favFoods" : ["wet food", "dry food", "<strong>any</strong> food"],</span>
|
||
<span class="line"> "birthYear" : 2016,</span>
|
||
<span class="line"> "photo" : "https://learnwebcode.github.io/json-example/images/cat-2.jpg"</span>
|
||
<span class="line">}</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-json-body">Doc</a></p>
|
||
|
||
<p>Or an explicit assert file:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/index.html</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">body</span> <span class="predicate-type">==</span> file,<span class="filename">cat.json</span>;</span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-body-assert">Doc</a></p>
|
||
|
||
<p>Implicit asserts supports XML body:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/catalog</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="xml"><span class="line"><?xml version="1.0" encoding="UTF-8"?></span>
|
||
<span class="line"><catalog></span>
|
||
<span class="line"> <book id="bk101"></span>
|
||
<span class="line"> <author>Gambardella, Matthew</author></span>
|
||
<span class="line"> <title>XML Developer's Guide</title></span>
|
||
<span class="line"> <genre>Computer</genre></span>
|
||
<span class="line"> <price>44.95</price></span>
|
||
<span class="line"> <publish_date>2000-10-01</publish_date></span>
|
||
<span class="line"> <description>An in-depth look at creating applications with XML.</description></span>
|
||
<span class="line"> </book></span>
|
||
<span class="line"></catalog></span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-xml-body">Doc</a></p>
|
||
|
||
<p>Plain text:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/models</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="multiline"><span class="line">```</span>
|
||
<span class="line">Year,Make,Model,Description,Price</span>
|
||
<span class="line">1997,Ford,E350,"ac, abs, moon",3000.00</span>
|
||
<span class="line">1999,Chevy,"Venture ""Extended Edition""","",4900.00</span>
|
||
<span class="line">1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00</span>
|
||
<span class="line">1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-multiline-string-body">Doc</a></p>
|
||
|
||
<p>One line:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/helloworld</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="string">`Hello world!`</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-oneline-string-body">Doc</a></p>
|
||
|
||
<p>File:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line">file,<span class="filename">data.bin</span>;</span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-file-body">Doc</a></p>
|
||
|
||
<h3 id="getting-started-samples-reports"><a href="#getting-started-samples-reports">Reports</a></h3>
|
||
|
||
<h4 id="getting-started-samples-html-report"><a href="#getting-started-samples-html-report">HTML Report</a></h4>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test --report-html build/report/ *.hurl</code></pre>
|
||
|
||
<p><a href="#getting-started-running-tests-generating-report">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-json-report"><a href="#getting-started-samples-json-report">JSON Report</a></h4>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test --report-json build/report/ *.hurl</code></pre>
|
||
|
||
<p><a href="#getting-started-running-tests-generating-report">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-junit-report"><a href="#getting-started-samples-junit-report">JUnit Report</a></h4>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test --report-junit build/report.xml *.hurl</code></pre>
|
||
|
||
<p><a href="#getting-started-running-tests-generating-report">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-tap-report"><a href="#getting-started-samples-tap-report">TAP Report</a></h4>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test --report-tap build/report.txt *.hurl</code></pre>
|
||
|
||
<p><a href="#getting-started-running-tests-generating-report">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-json-output"><a href="#getting-started-samples-json-output">JSON Output</a></h4>
|
||
|
||
<p>A structured output of running Hurl files can be obtained with <a href="#getting-started-manual-json"><code>--json</code> option</a>. Each file will produce a JSON export of the run.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --json *.hurl</code></pre>
|
||
|
||
<h3 id="getting-started-samples-others"><a href="#getting-started-samples-others">Others</a></h3>
|
||
|
||
<h4 id="getting-started-samples-http-version"><a href="#getting-started-samples-http-version">HTTP Version</a></h4>
|
||
|
||
<p>Testing HTTP version (HTTP/1.0, HTTP/1.1, HTTP/2 or HTTP/3):</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://foo.com</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP/3</span> <span class="number">200</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://bar.com</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP/2</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-version-status">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-polling-and-retry"><a href="#getting-started-samples-polling-and-retry">Polling and Retry</a></h4>
|
||
|
||
<p>Retry request on any errors (asserts, captures, status code, runtime etc...):</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Create a new job</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://api.example.org/jobs</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">201</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">job_id</span>: <span class="query-type">jsonpath</span> <span class="string">"$.id"</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.state"</span> <span class="predicate-type">==</span> <span class="string">"RUNNING"</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Pull job status until it is completed</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://api.example.org/jobs/{{job_id}}</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">retry</span>: <span class="number">10</span></span> <span class="comment"># maximum number of retry, -1 for unlimited</span>
|
||
<span class="line"><span class="string">retry-interval</span>: <span class="number">500</span><span class="unit">ms</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.state"</span> <span class="predicate-type">==</span> <span class="string">"COMPLETED"</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-entry-retry">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-delaying-requests"><a href="#getting-started-samples-delaying-requests">Delaying Requests</a></h4>
|
||
|
||
<p>Add delay for every request, or a particular request:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Delaying this request by 5 seconds</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/turtle</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">delay</span>: <span class="number">5</span><span class="unit">s</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># No delay!</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/turtle</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#getting-started-manual-delay">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-skipping-requests"><a href="#getting-started-samples-skipping-requests">Skipping Requests</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># a, c, d are run, b is skipped</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/a</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/b</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">skip</span>: <span class="boolean">true</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/c</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/d</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#getting-started-manual-skip">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-testing-endpoint-performance"><a href="#getting-started-samples-testing-endpoint-performance">Testing Endpoint Performance</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://sample.org/helloworld</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">*</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">duration</span> <span class="predicate-type"><</span> <span class="number">1000</span></span> <span class="comment"># Check that response time is less than one second</span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-duration-assert">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-using-soap-apis"><a href="#getting-started-samples-using-soap-apis">Using SOAP APIs</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/InStock</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">application/soap+xml; charset=utf-8</span></span>
|
||
<span class="line"><span class="string">SOAPAction</span>: <span class="string">"http://www.w3.org/2003/05/soap-envelope"</span></span>
|
||
<span class="xml"><span class="line"><?xml version="1.0" encoding="UTF-8"?></span>
|
||
<span class="line"><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="https://example.org"></span>
|
||
<span class="line"> <soap:Header></soap:Header></span>
|
||
<span class="line"> <soap:Body></span>
|
||
<span class="line"> <m:GetStockPrice></span>
|
||
<span class="line"> <m:StockName>GOOG</m:StockName></span>
|
||
<span class="line"> </m:GetStockPrice></span>
|
||
<span class="line"> </soap:Body></span>
|
||
<span class="line"></soap:Envelope></span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-request-xml-body">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-capturing-and-using-a-csrf-token"><a href="#getting-started-samples-capturing-and-using-a-csrf-token">Capturing and Using a CSRF Token</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">csrf_token</span>: <span class="query-type">xpath</span> <span class="string">"string(//meta[@name='_csrf_token']/@content)"</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://example.org/login?user=toto&password=1234</span></span>
|
||
<span class="line"><span class="string">X-CSRF-TOKEN</span>: <span class="string">{{csrf_token}}</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">302</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-capturing-response-xpath-capture">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-checking-byte-order-mark-bom-in-response-body"><a href="#getting-started-samples-checking-byte-order-mark-bom-in-response-body">Checking Byte Order Mark (BOM) in Response Body</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/data.bin</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">bytes</span> <span class="predicate-type">startsWith</span> hex,<span class="hex">efbbbf</span>;</span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-asserting-response-bytes-assert">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-aws-signature-version-4-requests"><a href="#getting-started-samples-aws-signature-version-4-requests">AWS Signature Version 4 Requests</a></h4>
|
||
|
||
<p>Generate signed API requests with <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html">AWS Signature Version 4</a>, as used by several cloud providers.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://sts.eu-central-1.amazonaws.com/</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">aws-sigv4</span>: <span class="string">aws:amz:eu-central-1:sts</span></span>
|
||
<span class="line"><span class="section-header">[FormParams]</span></span>
|
||
<span class="line"><span class="string">Action</span>: <span class="string">GetCallerIdentity</span></span>
|
||
<span class="line"><span class="string">Version</span>: <span class="string">2011-06-15</span></span></span></span></code></pre>
|
||
|
||
<p>The Access Key is given per <a href="#getting-started-manual-user"><code>--user</code></a>, either with command line option or within the <a href="#file-format-request-options"><code>[Options]</code></a> section:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://sts.eu-central-1.amazonaws.com/</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">aws-sigv4</span>: <span class="string">aws:amz:eu-central-1:sts</span></span>
|
||
<span class="line"><span class="string">user</span>: <span class="string">bob=secret</span></span>
|
||
<span class="line"><span class="section-header">[FormParams]</span></span>
|
||
<span class="line"><span class="string">Action</span>: <span class="string">GetCallerIdentity</span></span>
|
||
<span class="line"><span class="string">Version</span>: <span class="string">2011-06-15</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#getting-started-manual-aws-sigv4">Doc</a></p>
|
||
|
||
<h4 id="getting-started-samples-using-curl-options"><a href="#getting-started-samples-using-curl-options">Using curl Options</a></h4>
|
||
|
||
<p>curl options (for instance <a href="#getting-started-manual-resolve"><code>--resolve</code></a> or <a href="#getting-started-manual-connect-to"><code>--connect-to</code></a>) can be used as CLI argument. In this case, they’re applicable
|
||
to each request of an Hurl file.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --resolve foo.com:8000:127.0.0.1 foo.hurl</code></pre>
|
||
|
||
<p>Use <a href="#file-format-request-options"><code>[Options]</code> section</a> to configure a specific request:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://bar.com</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">http://foo.com:8000/resolve</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">resolve</span>: <span class="string">foo.com:8000:127.0.0.1</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="string">`Hello World!`</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#file-format-request-options">Doc</a></p>
|
||
|
||
<hr />
|
||
|
||
<h2 id="getting-started-running-tests-running-tests"><a href="#getting-started-running-tests-running-tests">Running Tests</a></h2>
|
||
|
||
<h3 id="getting-started-running-tests-use-test-option"><a href="#getting-started-running-tests-use-test-option">Use --test Option</a></h3>
|
||
|
||
<p>Hurl is run by default as an HTTP client, returning the body of the last HTTP response.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl hello.hurl
|
||
Hello World!</code></pre>
|
||
|
||
<p>When multiple input files are provided, Hurl outputs the body of the last HTTP response of each file.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl hello.hurl assert_json.hurl
|
||
Hello World![
|
||
{ "id": 1, "name": "Bob"},
|
||
{ "id": 2, "name": "Bill"}
|
||
]</code></pre>
|
||
|
||
<p>For testing, we are only interested in the asserts results, we don’t need the HTTP body response. To use Hurl as a
|
||
test tool with an adapted output, you can use <a href="#getting-started-manual-test"><code>--test</code> option</a>:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test hello.hurl assert_json.hurl
|
||
<span class="bold">hello.hurl</span>: <span class="bright-green">Success</span> (6 request(s) in 245 ms)
|
||
<span class="bold">assert_json.hurl</span>: <span class="bright-green">Success</span> (8 request(s) in 308 ms)
|
||
--------------------------------------------------------------------------------
|
||
Executed files: 2
|
||
Executed requests: 10 (17.82/s)
|
||
Succeeded files: 2 (100.0%)
|
||
Failed files: 0 (0.0%)
|
||
Duration: 561 ms</code></pre>
|
||
|
||
<p>Or, in case of errors:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test hello.hurl error_assert_status.hurl
|
||
<span class="bold">hello.hurl</span>: <span class="bright-green">Success</span> (4 request(s) in 5 ms)
|
||
<span class="bright-red">error</span>: <span class="bold">Assert status code</span>
|
||
<span class="bright-blue">--></span> error_assert_status.hurl:9:6
|
||
<span class="bright-blue"> |</span>
|
||
<span class="bright-blue"> |</span> <span class="gray">GET http://localhost:8000/not_found</span>
|
||
<span class="bright-blue"> |</span><span class="gray"> ...</span>
|
||
<span class="bright-blue"> 9 |</span> HTTP 200
|
||
<span class="bright-blue"> |</span><span class="bright-red"> ^^^ actual value is <404></span>
|
||
<span class="bright-blue"> |</span>
|
||
|
||
<span class="bold">error_assert_status.hurl</span>: <span class="bright-red">Failure</span> (1 request(s) in 2 ms)
|
||
--------------------------------------------------------------------------------
|
||
Executed files: 2
|
||
Executed requests: 5 (500.0/s)
|
||
Succeeded files: 1 (50.0%)
|
||
Failed files: 1 (50.0%)
|
||
Duration: 10 ms</code></pre>
|
||
|
||
<p>In test mode, files are executed in parallel to speed-ud the execution. If a sequential run is needed, you can use
|
||
<a href="#getting-started-manual-jobs"><code>--jobs 1</code></a> option to execute tests one by one.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test --jobs 1 *.hurl</code></pre>
|
||
|
||
<p><a href="#getting-started-manual-repeat"><code>--repeat</code> option</a> can be used to repeat run files and do performance check. For instance, this call will run 1000 tests
|
||
in parallel:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test --repeat 1000 stress.hurl</code></pre>
|
||
|
||
<h4 id="getting-started-running-tests-selecting-tests"><a href="#getting-started-running-tests-selecting-tests">Selecting Tests</a></h4>
|
||
|
||
<p>Hurl can take multiple files into inputs:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test test/integration/a.hurl test/integration/b.hurl test/integration/c.hurl</code></pre>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test test/integration/*.hurl</code></pre>
|
||
|
||
<p>Or you can simply give a directory and Hurl will find files with <code>.hurl</code> extension recursively:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test test/integration/</code></pre>
|
||
|
||
<p>Finally, you can use <a href="#getting-started-manual-glob"><code>--glob</code> option</a> to test files that match a given pattern:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test --glob "test/integration/**/*.hurl"</code></pre>
|
||
|
||
<h3 id="getting-started-running-tests-debugging"><a href="#getting-started-running-tests-debugging">Debugging</a></h3>
|
||
|
||
<h4 id="getting-started-running-tests-debug-logs"><a href="#getting-started-running-tests-debug-logs">Debug Logs</a></h4>
|
||
|
||
<p>If you need more error context, you can use <a href="#getting-started-manual-error-format"><code>--error-format long</code> option</a> to print HTTP bodies for failed asserts:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test --error-format long hello.hurl error_assert_status.hurl
|
||
<span class="bold">hello.hurl</span>: <span class="bright-green">Success</span> (4 request(s) in 6 ms)
|
||
<span class="bright-green">HTTP/1.1 404
|
||
</span><span class="bright-cyan">Server</span>: Werkzeug/3.0.3 Python/3.12.4
|
||
<span class="bright-cyan">Date</span>: Wed, 10 Jul 2024 15:42:41 GMT
|
||
<span class="bright-cyan">Content-Type</span>: text/html; charset=utf-8
|
||
<span class="bright-cyan">Content-Length</span>: 207
|
||
<span class="bright-cyan">Server</span>: Flask Server
|
||
<span class="bright-cyan">Connection</span>: close
|
||
|
||
<!doctype html>
|
||
<html lang=en>
|
||
<title>404 Not Found</title>
|
||
<h1>Not Found</h1>
|
||
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
|
||
|
||
|
||
<span class="bright-red">error</span>: <span class="bold">Assert status code</span>
|
||
<span class="bright-blue">--></span> error_assert_status.hurl:9:6
|
||
<span class="bright-blue"> |</span>
|
||
<span class="bright-blue"> |</span> <span class="gray">GET http://localhost:8000/not_found</span>
|
||
<span class="bright-blue"> |</span><span class="gray"> ...</span>
|
||
<span class="bright-blue"> 9 |</span> HTTP 200
|
||
<span class="bright-blue"> |</span><span class="bright-red"> ^^^ actual value is <404></span>
|
||
<span class="bright-blue"> |</span>
|
||
|
||
<span class="bold">error_assert_status.hurl</span>: <span class="bright-red">Failure</span> (1 request(s) in 2 ms)
|
||
--------------------------------------------------------------------------------
|
||
Executed files: 2
|
||
Executed requests: 5 (454.5/s)
|
||
Succeeded files: 1 (50.0%)
|
||
Failed files: 1 (50.0%)
|
||
Duration: 11 ms</code></pre>
|
||
|
||
<p>Individual requests can be modified with [<code>[Options]</code> section]<a href="#file-format-request-options">options</a> to turn on logs for a particular request, using
|
||
<a href="#getting-started-manual-verbose"><code>verbose</code></a> and <a href="#getting-started-manual-very-verbose"><code>very-verbose</code></a> option.</p>
|
||
|
||
<p>With this Hurl file:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://foo.com</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://bar.com</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">very-verbose</span>: <span class="boolean">true</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://baz.com</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p>Running <code>hurl --test .</code> will output debug logs for the request to <code>https://bar.com</code>.</p>
|
||
|
||
<p><a href="#getting-started-manual-verbose"><code>--verbose</code></a> / <a href="#getting-started-manual-very-verbose"><code>--very-verbose</code></a> can also be enabled globally, for every requests of every tested files:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test --very-verbose .</code></pre>
|
||
|
||
<h4 id="getting-started-running-tests-http-responses"><a href="#getting-started-running-tests-http-responses">HTTP Responses</a></h4>
|
||
|
||
<p>In test mode, HTTP responses are not displayed. One way to get HTTP responses even in test mode is to use
|
||
<a href="#getting-started-manual-output"><code>--output</code> option</a> of <code>[Options]</code> section: <code>--output file</code> allows to save a particular response to a file, while
|
||
<code>--output -</code> allows to redirect HTTP responses to standard output.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://foo.com</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://bar.com</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">output</span>: <span class="filename">-</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test .
|
||
<html><head><meta http-equiv="content-type" content="text/html;charset=utf-8">
|
||
<title>301 Moved</TITLE></head><body>
|
||
<h1>301 Moved</h1>
|
||
The document has moved
|
||
<a HREF="https://www.bar.com/">here</a>.
|
||
</body></html>
|
||
<span class="bold">/tmp/test.hurl</span>: <span class="bright-green">Success</span> (2 request(s) in 184 ms)
|
||
--------------------------------------------------------------------------------
|
||
Executed files: 1
|
||
Executed requests: 2 (10.7/s)
|
||
Succeeded files: 1 (100.0%)
|
||
Failed files: 0 (0.0%)
|
||
Duration: 187 ms</code></pre>
|
||
|
||
<h3 id="getting-started-running-tests-generating-report"><a href="#getting-started-running-tests-generating-report">Generating Report</a></h3>
|
||
|
||
<p>In the different reports, files are always referenced in the input order (which, as tests are executed in parallel, can
|
||
be different from the execution order).</p>
|
||
|
||
<h4 id="getting-started-running-tests-html-report"><a href="#getting-started-running-tests-html-report">HTML Report</a></h4>
|
||
|
||
<p>Hurl can generate an HTML report by using the <a href="#getting-started-manual-report-html"><code>--report-html DIR</code></a> option.</p>
|
||
|
||
<p>If the HTML report already exists, the test results will be appended to it.</p>
|
||
|
||
<div class="picture">
|
||
<img class="u-drop-shadow u-border u-max-width-100" src="https://hurl.dev/assets/img/hurl-html-report.png" width="670" alt="Hurl HTML Report" />
|
||
</div>
|
||
|
||
<p>The input Hurl files (HTML version) are also included and are easily accessed from the main page.</p>
|
||
|
||
<div class="picture">
|
||
<img class="u-drop-shadow u-border u-max-width-100" src="https://hurl.dev/assets/img/hurl-html-file.png" width="380" alt="Hurl HTML file" />
|
||
</div>
|
||
|
||
<h4 id="getting-started-running-tests-json-report"><a href="#getting-started-running-tests-json-report">JSON Report</a></h4>
|
||
|
||
<p>A JSON report can be produced by using the <a href="#getting-started-manual-report-json"><code>--report-json DIR</code></a>. The report directory will contain a <code>report.json</code>
|
||
file, including each test file executed with <a href="#getting-started-manual-json"><code>--json</code></a> option and a reference to each HTTP response of the run dumped
|
||
to disk.</p>
|
||
|
||
<p>If the JSON report already exists, it will be updated with the new test results.</p>
|
||
|
||
<h4 id="getting-started-running-tests-junit-report"><a href="#getting-started-running-tests-junit-report">JUnit Report</a></h4>
|
||
|
||
<p>A JUnit report can be produced by using the <a href="#getting-started-manual-report-junit"><code>--report-junit FILE</code></a> option.</p>
|
||
|
||
<p>If the JUnit report already exists, it will be updated with the new test results.</p>
|
||
|
||
<h4 id="getting-started-running-tests-tap-report"><a href="#getting-started-running-tests-tap-report">TAP Report</a></h4>
|
||
|
||
<p>A TAP report (<a href="https://testanything.org">Test Anything Protocol</a>) can be produced by using the <a href="#getting-started-manual-report-tap"><code>--report-tap FILE</code></a> option.</p>
|
||
|
||
<p>If the TAP report already exists, it will be updated with the new test results.</p>
|
||
|
||
<h3 id="getting-started-running-tests-use-variables-in-tests"><a href="#getting-started-running-tests-use-variables-in-tests">Use Variables in Tests</a></h3>
|
||
|
||
<p>To use variables in your tests, you can:</p>
|
||
|
||
<ul>
|
||
<li>use <a href="#getting-started-manual-variable"><code>--variable</code> option</a></li>
|
||
<li>use <a href="#getting-started-manual-variables-file"><code>--variables-file</code> option</a></li>
|
||
<li>define environment variables, for instance <code>HURL_foo=bar</code></li>
|
||
</ul>
|
||
|
||
<p>You will find a detailed description in the <a href="#file-format-templates-injecting-variables">Injecting Variables</a> section of the docs.</p>
|
||
|
||
<hr />
|
||
|
||
<h2 id="getting-started-frequently-asked-questions-frequently-asked-questions"><a href="#getting-started-frequently-asked-questions-frequently-asked-questions">Frequently Asked Questions</a></h2>
|
||
|
||
<h3 id="getting-started-frequently-asked-questions-general"><a href="#getting-started-frequently-asked-questions-general">General</a></h3>
|
||
|
||
<h4 id="getting-started-frequently-asked-questions-why-hurl"><a href="#getting-started-frequently-asked-questions-why-hurl">Why “Hurl”?</a></h4>
|
||
|
||
<p>The name Hurl is a tribute to the awesome <a href="https://curl.haxx.se">curl</a>, with a focus on the HTTP protocol.
|
||
While it may have an informal meaning not particularly elegant, <a href="https://git.wiki.kernel.org/index.php/GitFaq#Why_the_.27Git.27_name.3F">other eminent tools</a> have set a precedent in naming.</p>
|
||
|
||
<h4 id="getting-started-frequently-asked-questions-yet-another-tool-i-already-use-x"><a href="#getting-started-frequently-asked-questions-yet-another-tool-i-already-use-x">Yet Another Tool, I already use X</a></h4>
|
||
|
||
<p>We think that Hurl has some advantages compared to similar tools.</p>
|
||
|
||
<p>Hurl is foremost a command line tool and should be easy to use on a local computer, or in a CI/CD pipeline. Some
|
||
tools in the same space as Hurl (<a href="https://www.postman.com">Postman</a> for instance), are GUI oriented, and we find it
|
||
less attractive than CLI. As a command line tool, Hurl can be used to get HTTP data (like <a href="https://curl.haxx.se">curl</a>),
|
||
but also as a test tool for HTTP sessions, or even as documentation.</p>
|
||
|
||
<p>Having a text based <a href="#file-format-hurl-file">file format</a> is another advantage. The Hurl format is simple,
|
||
focused on the HTTP domain, can serve as documentation and can be read or written by non-technical people.</p>
|
||
|
||
<p>For instance posting JSON data with Hurl can be done with this simple file:</p>
|
||
|
||
<pre><code>POST http://localhost:3000/api/login
|
||
{
|
||
"username": "xyz",
|
||
"password": "xyz"
|
||
}
|
||
</code></pre>
|
||
|
||
<p>With <a href="https://curl.haxx.se">curl</a>:</p>
|
||
|
||
<pre><code>curl --header "Content-Type: application/json" \
|
||
--request POST \
|
||
--data '{"username": "xyz","password": "xyz"}' \
|
||
http://localhost:3000/api/login
|
||
</code></pre>
|
||
|
||
<p><a href="https://github.com/intuit/karate">Karate</a>, a tool combining API test automation, mocking, performance-testing, has
|
||
similar features but offers also much more at a cost of an increased complexity.</p>
|
||
|
||
<p>Comparing Karate file format:</p>
|
||
|
||
<pre><code>Scenario: create and retrieve a cat
|
||
|
||
Given url 'http://myhost.com/v1/cats'
|
||
And request { name: 'Billie' }
|
||
When method post
|
||
Then status 201
|
||
And match response == { id: '#notnull', name: 'Billie }
|
||
|
||
Given path response.id
|
||
When method get
|
||
Then status 200
|
||
</code></pre>
|
||
|
||
<p>And Hurl:</p>
|
||
|
||
<pre><code># Scenario: create and retrieve a cat
|
||
|
||
POST http://myhost.com/v1/cats
|
||
{ "name": "Billie" }
|
||
HTTP 201
|
||
[Captures]
|
||
cat_id: jsonpath "$.id"
|
||
[Asserts]
|
||
jsonpath "$.name" == "Billie"
|
||
|
||
GET http://myshost.com/v1/cats/{{cat_id}}
|
||
HTTP 200
|
||
</code></pre>
|
||
|
||
<p>A key point of Hurl is to work on the HTTP domain. In particular, there is no JavaScript runtime, Hurl works on the
|
||
raw HTTP requests/responses, and not on a DOM managed by a HTML engine. For security, this can be seen as a feature:
|
||
let’s say you want to test backend validation, you want to be able to bypass the browser or javascript validations and
|
||
directly test a backend endpoint.</p>
|
||
|
||
<p>Finally, with no headless browser and working on the raw HTTP data, Hurl is also
|
||
really reliable with a very small probability of false positives. Integration tests with tools like
|
||
<a href="https://www.selenium.dev">Selenium</a> can, in this regard, be challenging to maintain.</p>
|
||
|
||
<p>Just use what is convenient for you. In our case, it’s Hurl!</p>
|
||
|
||
<h4 id="getting-started-frequently-asked-questions-hurl-is-build-on-top-of-libcurl-but-what-is-added"><a href="#getting-started-frequently-asked-questions-hurl-is-build-on-top-of-libcurl-but-what-is-added">Hurl is build on top of libcurl, but what is added?</a></h4>
|
||
|
||
<p>Hurl has two main functionalities on top of <a href="https://curl.haxx.se">curl</a>:</p>
|
||
|
||
<ol>
|
||
<li>
|
||
<p>Chain several requests:</p>
|
||
|
||
<p>With its <a href="#file-format-capturing-response">captures</a>, it enables to inject data received from a response into
|
||
following requests. <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF tokens</a>
|
||
are typical examples in a standard web session.</p>
|
||
</li>
|
||
<li>
|
||
<p>Test HTTP responses:</p>
|
||
|
||
<p>With its <a href="#file-format-asserting-response">asserts</a>, responses can be easily tested.</p>
|
||
</li>
|
||
</ol>
|
||
|
||
<p>Hurl benefits from the features of the <code>libcurl</code> against it is linked. You can check <code>libcurl</code> version with <code>hurl --version</code>.</p>
|
||
|
||
<p>For instance on macOS:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --version
|
||
hurl 2.0.0 libcurl/7.79.1 (SecureTransport) LibreSSL/3.3.6 zlib/1.2.11 nghttp2/1.45.1
|
||
Features (libcurl): alt-svc AsynchDNS HSTS HTTP2 IPv6 Largefile libz NTLM NTLM_WB SPNEGO SSL UnixSockets
|
||
Features (built-in): brotli</code></pre>
|
||
|
||
<p>You can also check which <code>libcurl</code> is used.</p>
|
||
|
||
<p>On macOS:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>which hurl
|
||
/opt/homebrew/bin/hurl
|
||
<span class="prompt">$ </span>otool -L /opt/homebrew/bin/hurl:
|
||
/usr/lib/libxml2.2.dylib (compatibility version 10.0.0, current version 10.9.0)
|
||
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1858.112.0)
|
||
/usr/lib/libcurl.4.dylib (compatibility version 7.0.0, current version 9.0.0)
|
||
/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
|
||
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.100.3)</code></pre>
|
||
|
||
<p>On Linux:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>which hurl
|
||
/root/.cargo/bin/hurl
|
||
<span class="prompt">$ </span>ldd /root/.cargo/bin/hurl
|
||
ldd /root/.cargo/bin/hurl
|
||
linux-vdso.so.1 (0x0000ffff8656a000)
|
||
libxml2.so.2 => /usr/lib/aarch64-linux-gnu/libxml2.so.2 (0x0000ffff85fe8000)
|
||
libcurl.so.4 => /usr/lib/aarch64-linux-gnu/libcurl.so.4 (0x0000ffff85f45000)
|
||
libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x0000ffff85f21000)
|
||
...
|
||
libkeyutils.so.1 => /lib/aarch64-linux-gnu/libkeyutils.so.1 (0x0000ffff82ed5000)
|
||
libffi.so.7 => /usr/lib/aarch64-linux-gnu/libffi.so.7 (0x0000ffff82ebc000)</code></pre>
|
||
|
||
<p>Note that some Hurl features are dependent on <code>libcurl</code> capacities: for instance, if your <code>libcurl</code> doesn’t support
|
||
HTTP/2 Hurl won’t be able to send HTTP/2 request.</p>
|
||
|
||
<h4 id="getting-started-frequently-asked-questions-why-shouldnt-i-use-hurl"><a href="#getting-started-frequently-asked-questions-why-shouldnt-i-use-hurl">Why shouldn’t I use Hurl?</a></h4>
|
||
|
||
<p>If you need a GUI. Currently, Hurl does not offer a GUI version (like <a href="https://www.postman.com">Postman</a>). While we
|
||
think that it can be useful, we prefer to focus for the time-being on the core, keeping something simple and fast.
|
||
Contributions to build a GUI are welcome.</p>
|
||
|
||
<h4 id="getting-started-frequently-asked-questions-i-have-a-large-numbers-of-tests-how-to-run-just-specific-tests"><a href="#getting-started-frequently-asked-questions-i-have-a-large-numbers-of-tests-how-to-run-just-specific-tests">I have a large numbers of tests, how to run just specific tests?</a></h4>
|
||
|
||
<p>By convention, you can organize Hurl files into different folders or prefix them.</p>
|
||
|
||
<p>For example, you can split your tests into two folders critical and additional.</p>
|
||
|
||
<pre><code>critical/test1.hurl
|
||
critical/test2.hurl
|
||
additional/test1.hurl
|
||
additional/test2.hurl
|
||
</code></pre>
|
||
|
||
<p>You can simply run your critical tests with</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --test critical/*.hurl</code></pre>
|
||
|
||
<h4 id="getting-started-frequently-asked-questions-how-can-i-use-my-hurl-files-outside-hurl"><a href="#getting-started-frequently-asked-questions-how-can-i-use-my-hurl-files-outside-hurl">How can I use my Hurl files outside Hurl?</a></h4>
|
||
|
||
<p>Hurl file can be exported to a JSON file with <code>hurlfmt</code>.
|
||
This JSON file can then be easily parsed for converting a different format, getting ad-hoc information,...</p>
|
||
|
||
<p>For example, the Hurl file</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/users/1</span></span>
|
||
<span class="line"><span class="string">User-Agent</span>: <span class="string">Custom</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.name"</span> <span class="predicate-type">==</span> <span class="string">"Bob"</span></span></span></span></code></pre>
|
||
|
||
<p>will be converted to JSON with the following command:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurlfmt test.hurl --out json | jq
|
||
{
|
||
"entries": [
|
||
{
|
||
"request": {
|
||
"method": "GET",
|
||
"url": "https://example.org/api/users/1",
|
||
"headers": [
|
||
{
|
||
"name": "User-Agent",
|
||
"value": "Custom"
|
||
}
|
||
]
|
||
},
|
||
"response": {
|
||
"version": "HTTP",
|
||
"status": 200,
|
||
"asserts": [
|
||
{
|
||
"query": {
|
||
"type": "jsonpath",
|
||
"expr": "$.name"
|
||
},
|
||
"predicate": {
|
||
"type": "==",
|
||
"value": "Bob"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
}
|
||
]
|
||
}</code></pre>
|
||
|
||
<h4 id="getting-started-frequently-asked-questions-can-i-do-calculation-within-a-hurl-file"><a href="#getting-started-frequently-asked-questions-can-i-do-calculation-within-a-hurl-file">Can I do calculation within a Hurl file?</a></h4>
|
||
|
||
<p>Currently, the templating is very simple, only accessing variables.
|
||
Calculations can be done beforehand, before running the Hurl File.</p>
|
||
|
||
<p>For example, with date calculations, variables <code>now</code> and <code>tomorrow</code> can be used as param or expected value.</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>TODAY=$(date '+%y%m%d')
|
||
<span class="prompt">$ </span>TOMORROW=$(date '+%y%m%d' -d"+1days")
|
||
<span class="prompt">$ </span>hurl --variable "today=$TODAY" --variable "tomorrow=$TOMORROW" test.hurl</code></pre>
|
||
|
||
<p>You can also use environment variables that begins with <code>HURL_</code> to inject data in an Hurl file.
|
||
For instance, to inject <code>today</code> and <code>tomorrow</code> variables:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>export HURL_today=$(date '+%y%m%d')
|
||
<span class="prompt">$ </span>export HURL_tomorrow=$(date '+%y%m%d' -d"+1days")
|
||
<span class="prompt">$ </span>hurl test.hurl</code></pre>
|
||
|
||
<p>You can also use <a href="#file-format-filters">filters</a> to process HTTP responses in asserts and captures.</p>
|
||
|
||
<h3 id="getting-started-frequently-asked-questions-macos"><a href="#getting-started-frequently-asked-questions-macos">macOS</a></h3>
|
||
|
||
<h4 id="getting-started-frequently-asked-questions-how-can-i-use-a-custom-libcurl-from-homebrew-by-instance"><a href="#getting-started-frequently-asked-questions-how-can-i-use-a-custom-libcurl-from-homebrew-by-instance">How can I use a custom libcurl (from Homebrew by instance)?</a></h4>
|
||
|
||
<p>No matter how you’ve installed Hurl (using the precompiled binary for macOS or with <a href="https://brew.sh">Homebrew</a>)
|
||
Hurl is linked against the built-in system libcurl. If you want to use another libcurl (for instance,
|
||
if you’ve installed curl with Homebrew and want Hurl to use Homebrew’s libcurl), you can patch Hurl with
|
||
the following command:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>sudo install_name_tool -change /usr/lib/libcurl.4.dylib PATH_TO_CUSTOM_LIBCURL PATH_TO_HURL_BIN</code></pre>
|
||
|
||
<p>For instance:</p>
|
||
|
||
<pre><code class="language-shell"># /usr/local/opt/curl/lib/libcurl.4.dylib is installed by `brew install curl`
|
||
<span class="prompt">$ </span>sudo install_name_tool -change /usr/lib/libcurl.4.dylib /usr/local/opt/curl/lib/libcurl.4.dylib /usr/local/bin/hurl</code></pre>
|
||
|
||
<hr />
|
||
|
||
<h1 id="file-format"><a href="#file-format">File Format</a></h1>
|
||
|
||
<h2 id="file-format-hurl-file-hurl-file"><a href="#file-format-hurl-file-hurl-file">Hurl File</a></h2>
|
||
|
||
<h3 id="file-format-hurl-file-character-encoding"><a href="#file-format-hurl-file-character-encoding">Character Encoding</a></h3>
|
||
|
||
<p>Hurl file should be encoded in UTF-8, without a byte order mark at the beginning
|
||
(while Hurl ignores the presence of a byte order mark rather than treating it as an error)</p>
|
||
|
||
<h3 id="file-format-hurl-file-file-extension"><a href="#file-format-hurl-file-file-extension">File Extension</a></h3>
|
||
|
||
<p>Hurl file extension is <code>.hurl</code></p>
|
||
|
||
<h3 id="file-format-hurl-file-comments"><a href="#file-format-hurl-file-comments">Comments</a></h3>
|
||
|
||
<p>Comments begin with <code>#</code> and continue until the end of line. Hurl file can serve as
|
||
a documentation for HTTP based workflows so it can be useful to be very descriptive.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># A very simple Hurl file</span>
|
||
<span class="line"></span><span class="comment"># with tasty comments...</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://www.sample.net</span></span>
|
||
<span class="line"><span class="string">x-app</span>: <span class="string">MY_APP</span></span> <span class="comment"># Add a dummy header</span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">302</span></span> <span class="comment"># Check that we have a redirection</span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Location"</span> <span class="predicate-type">exists</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Location"</span> <span class="predicate-type">contains</span> <span class="string">"login"</span></span> <span class="comment"># Check that we are redirected to the login page</span></span></span></code></pre>
|
||
|
||
<h3 id="file-format-hurl-file-special-characters-in-strings"><a href="#file-format-hurl-file-special-characters-in-strings">Special Characters in Strings</a></h3>
|
||
|
||
<p>String can include the following special characters:</p>
|
||
|
||
<ul>
|
||
<li>The escaped special characters " (double quotation mark), \ (backslash), \b (backspace), \f (form feed),
|
||
\n (line feed), \r (carriage return), and \t (horizontal tab)</li>
|
||
<li>An arbitrary Unicode scalar value, written as \u{n}, where n is a 1–8 digit hexadecimal number</li>
|
||
</ul>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"></span><span class="comment"># The following assert are equivalent:</span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.slideshow.title"</span> <span class="predicate-type">==</span> <span class="string">"A beautiful ✈!"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.slideshow.title"</span> <span class="predicate-type">==</span> <span class="string">"A beautiful \u{2708}!"</span></span></span></span></code></pre>
|
||
|
||
<p>In some case, (in headers value, etc..), you will also need to escape # to distinguish it from a comment.
|
||
In the following example:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api</span></span>
|
||
<span class="line"><span class="string">x-token</span>: <span class="string">BEEF \#STEACK</span></span> <span class="comment"># Some comment</span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p>We’re sending a header <code>x-token</code> with value <code>BEEF #STEACK</code></p>
|
||
|
||
<hr />
|
||
|
||
<h2 id="file-format-entry-entry"><a href="#file-format-entry-entry">Entry</a></h2>
|
||
|
||
<h3 id="file-format-entry-definition"><a href="#file-format-entry-definition">Definition</a></h3>
|
||
|
||
<p>A Hurl file is a list of entries, each entry being a mandatory <a href="#file-format-request">request</a>, optionally followed by a <a href="#file-format-response">response</a>.</p>
|
||
|
||
<p>Responses are not mandatory, a Hurl file consisting only of requests is perfectly valid. To sum up, responses can be used
|
||
to <a href="#file-format-capturing-response">capture values</a> to perform subsequent requests, or <a href="#file-format-asserting-response">add asserts to HTTP responses</a>.</p>
|
||
|
||
<h3 id="file-format-entry-example"><a href="#file-format-entry-example">Example</a></h3>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># First, test home title.</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://acmecorp.net</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"normalize-space(//head/title)"</span> <span class="predicate-type">==</span> <span class="string">"Hello world!"</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Get some news, response description is optional</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://acmecorp.net/news</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Do a POST request without CSRF token and check</span>
|
||
<span class="line"></span><span class="comment"># that status code is Forbidden 403</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://acmecorp.net/contact</span></span>
|
||
<span class="line"><span class="section-header">[FormParams]</span></span>
|
||
<span class="line"><span class="string">default</span>: <span class="string">false</span></span>
|
||
<span class="line"><span class="string">email</span>: <span class="string">john.doe@rookie.org</span></span>
|
||
<span class="line"><span class="string">number</span>: <span class="string">33611223344</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">403</span></span></span></span></code></pre>
|
||
|
||
<h3 id="file-format-entry-description"><a href="#file-format-entry-description">Description</a></h3>
|
||
|
||
<h4 id="file-format-entry-options"><a href="#file-format-entry-options">Options</a></h4>
|
||
|
||
<p><a href="#getting-started-manual-options">Options</a> specified on the command line apply to every entry in an Hurl file. For instance, with <a href="#getting-started-manual-location"><code>--location</code> option</a>,
|
||
every entry of a given file will follow redirection:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --location foo.hurl</code></pre>
|
||
|
||
<p>You can use an [<code>[Options]</code> section]<a href="#file-format-request-options">options</a> to set option only for a specified request. For instance, in this Hurl file,
|
||
the second entry will follow location (so we can test the status code to be 200 instead of 301).</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://google.fr</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">301</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://google.fr</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">location</span>: <span class="boolean">true</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://google.fr</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">301</span></span></span></span></code></pre>
|
||
|
||
<p>You can use the <code>[Options](#getting-started-manual-options)</code> section to log a specific entry:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># ... previous entries</span>
|
||
<span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://api.example.org</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">very-verbose</span>: <span class="boolean">true</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
</span></span><span class="line"></span>
|
||
<span class="line"><br /></span><span class="comment"># ... next entries</span></code></pre>
|
||
|
||
<h4 id="file-format-entry-cookie-storage"><a href="#file-format-entry-cookie-storage">Cookie storage</a></h4>
|
||
|
||
<p>Requests in the same Hurl file share the cookie storage, enabling, for example, session based scenario.</p>
|
||
|
||
<h4 id="file-format-entry-redirects"><a href="#file-format-entry-redirects">Redirects</a></h4>
|
||
|
||
<p>By default, Hurl doesn’t follow redirection. To effectively run a redirection, entries should describe each step
|
||
of the redirection, allowing insertion of asserts in each response.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># First entry, test the redirection (status code and 'Location' header)</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://google.fr</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">301</span></span>
|
||
<span class="line"><span class="string">Location</span>: <span class="string">https://www.google.fr/</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Second entry, the 200 OK response</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://www.google.fr</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p>Alternatively, one can use <a href="#getting-started-manual-location"><code>--location</code></a> / <a href="#getting-started-manual-location-trusted"><code>--location-trusted</code></a> options to force redirection
|
||
to be followed. In this case, asserts are executed on the last received response. Optionally, the number of
|
||
redirections can be limited with <a href="#getting-started-manual-max-redirs"><code>--max-redirs</code></a>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Running hurl --location google.hurl</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://google.fr</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p>Finally, you can force redirection on a particular request with an [<code>[Options]</code> section]<a href="#file-format-request-options">options</a> and the<a href="#getting-started-manual-location"><code>--location</code></a>
|
||
/ <a href="#getting-started-manual-location-trusted"><code>--location-trusted</code></a> options:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://google.fr</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">location-trusted</span>: <span class="boolean">true</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-entry-retry"><a href="#file-format-entry-retry">Retry</a></h4>
|
||
|
||
<p>Every entry can be retried upon asserts, captures or runtime errors. Retries allow polling scenarios and effective runs
|
||
under flaky conditions. Asserts can be explicit (with an [<code>[Asserts]</code> section]<a href="#file-format-response-asserts">asserts</a>), or implicit (like <a href="#file-format-response-headers">headers</a> or <a href="#file-format-response-version-status">status code</a>).</p>
|
||
|
||
<p>Retries can be set globally for every request (see <a href="#getting-started-manual-retry"><code>--retry</code></a> and <a href="#getting-started-manual-retry-interval"><code>--retry-interval</code></a>),
|
||
or activated on a particular request with an [<code>[Options]</code> section]<a href="#file-format-request-options">options</a>.</p>
|
||
|
||
<p>For example, in this Hurl file, first we create a new job then we poll the new job until it’s completed:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Create a new job</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">http://api.example.org/jobs</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">201</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">job_id</span>: <span class="query-type">jsonpath</span> <span class="string">"$.id"</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.state"</span> <span class="predicate-type">==</span> <span class="string">"RUNNING"</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Pull job status until it is completed</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">http://api.example.org/jobs/{{job_id}}</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">retry</span>: <span class="number">10</span></span> <span class="comment"># maximum number of retry, -1 for unlimited</span>
|
||
<span class="line"><span class="string">retry-interval</span>: <span class="number">300</span><span class="unit">ms</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.state"</span> <span class="predicate-type">==</span> <span class="string">"COMPLETED"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-entry-control-flow"><a href="#file-format-entry-control-flow">Control flow</a></h4>
|
||
|
||
<p>In <code>[Options](#getting-started-manual-options)</code> section, <code>skip</code> and <code>repeat</code> can be used to control flow of execution:</p>
|
||
|
||
<ul>
|
||
<li><code>skip: true/false</code> skip this request and execute the next one unconditionally,</li>
|
||
<li><code>repeat: N</code> loop the request N times. If there are assert or runtime errors, the requests execution is stopped.</li>
|
||
</ul>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># This request will be played exactly 3 times</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/foo</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">repeat</span>: <span class="number">3</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># This request is skipped</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/foo</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">skip</span>: <span class="boolean">true</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p>Additionally, a <code>delay</code> can be inserted between requests, to add a delay before execution of a request.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># A 5 seconds delayed request </span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/foo</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">delay</span>: <span class="number">5</span><span class="unit">s</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p><a href="#getting-started-manual-retry"><code>delay</code></a> and <a href="#getting-started-manual-repeat"><code>repeat</code></a> can also be used globally as command line options:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --delay 500ms --repeat 3 foo.hurl</code></pre>
|
||
|
||
<p>For complete reference, below is a diagram for the executed entries.</p>
|
||
|
||
<div class="picture">
|
||
<img class="u-theme-light u-drop-shadow u-border u-max-width-100" src="https://hurl.dev/assets/img/run-cycle-light.svg" alt="Run cycle explanation" />
|
||
<img class="u-theme-dark u-drop-shadow u-border u-max-width-100" src="https://hurl.dev/assets/img/run-cycle-dark.svg" alt="Run cycle explanation" />
|
||
</div>
|
||
|
||
<hr />
|
||
|
||
<h2 id="file-format-request-request"><a href="#file-format-request-request">Request</a></h2>
|
||
|
||
<h3 id="file-format-request-definition"><a href="#file-format-request-definition">Definition</a></h3>
|
||
|
||
<p>Request describes an HTTP request: a mandatory <a href="#file-format-request-method">method</a> and <a href="#file-format-request-url">URL</a>, followed by optional <a href="#file-format-request-headers">headers</a>.</p>
|
||
|
||
<p>Then, <a href="#file-format-request-options">options</a>, <a href="#file-format-request-query-parameters">query parameters</a>, <a href="#file-format-request-form-parameters">form parameters</a>, <a href="#file-format-request-multipart-form-data">multipart form data</a>, <a href="#file-format-request-cookies">cookies</a>, and <a href="#file-format-request-basic-authentication">basic authentication</a>
|
||
can be used to configure the HTTP request.</p>
|
||
|
||
<p>Finally, an optional <a href="#file-format-request-body">body</a> can be used to configure the HTTP request body.</p>
|
||
|
||
<h3 id="file-format-request-example"><a href="#file-format-request-example">Example</a></h3>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/dogs?id=4567</span></span>
|
||
<span class="line"><span class="string">User-Agent</span>: <span class="string">My User Agent</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">application/json</span></span>
|
||
<span class="line"><span class="section-header">[BasicAuth]</span></span>
|
||
<span class="line"><span class="string">alice</span>: <span class="string">secret</span></span></span></span></code></pre>
|
||
|
||
<h3 id="file-format-request-structure"><a href="#file-format-request-structure">Structure</a></h3>
|
||
|
||
<div class="hurl-structure-schema">
|
||
<div class="hurl-structure">
|
||
<div class="hurl-structure-col-0">
|
||
<div class="hurl-part-0">
|
||
PUT https://sample.net
|
||
</div>
|
||
<div class="hurl-part-1">
|
||
accept: */*<br />x-powered-by: Express<br />user-agent: Test
|
||
</div>
|
||
<div class="hurl-part-2">
|
||
[Options]<br />...
|
||
</div>
|
||
<div class="hurl-part-2">
|
||
[QueryStringParams]<br />...
|
||
</div>
|
||
<div class="hurl-part-2">
|
||
[FormParams]<br />...
|
||
</div>
|
||
<div class="hurl-part-2">
|
||
[BasicAuth]<br />...
|
||
</div>
|
||
<div class="hurl-part-2">
|
||
[Cookies]<br />...
|
||
</div>
|
||
<div class="hurl-part-2">
|
||
...
|
||
</div>
|
||
<div class="hurl-part-2">
|
||
...
|
||
</div>
|
||
<div class="hurl-part-3">
|
||
{<br />
|
||
"type": "FOO",<br />
|
||
"value": 356789,<br />
|
||
"ordered": true,<br />
|
||
"index": 10<br />
|
||
}
|
||
</div>
|
||
</div>
|
||
<div class="hurl-structure-col-1">
|
||
<div class="hurl-request-explanation-part-0">
|
||
<a href="#file-format-request-method">Method</a> and <a href="#file-format-request-url">URL</a> (mandatory)
|
||
</div>
|
||
<div class="hurl-request-explanation-part-1">
|
||
<br /><a href="#file-format-request-headers">HTTP request headers</a> (optional)
|
||
</div>
|
||
<div class="hurl-request-explanation-part-2">
|
||
<br />
|
||
<br />
|
||
<br />
|
||
<br />
|
||
<br />
|
||
</div>
|
||
<div class="hurl-request-explanation-part-2">
|
||
<a href="#file-format-options">Options</a>, <a href="#file-format-request-query-parameters">query strings</a>, <a href="#file-format-request-form-parameters">form params</a>, <a href="#file-format-request-cookies">cookies</a>, <a href="#file-format-request-basic-authentication">authentication</a> ...<br />(optional sections, unordered)
|
||
</div>
|
||
<div class="hurl-request-explanation-part-2">
|
||
<br />
|
||
<br />
|
||
<br />
|
||
<br />
|
||
</div>
|
||
<div class="hurl-request-explanation-part-3">
|
||
<br />
|
||
</div>
|
||
<div class="hurl-request-explanation-part-3">
|
||
<a href="#file-format-request-body">HTTP request body</a> (optional)
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<p><a href="#file-format-request-headers">Headers</a>, if present, follow directly after the <a href="#file-format-request-method">method</a> and <a href="#file-format-request-url">URL</a>. This allows Hurl format to ‘look like’ the real HTTP format.
|
||
Contrary to HTTP headers, other parameters are defined in sections (<code>[Cookies]</code>, <code>[QueryStringParams]</code>, <code>[FormParams]</code> etc...)
|
||
These sections are not ordered and can be mixed in any way:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/dogs</span></span>
|
||
<span class="line"><span class="string">User-Agent</span>: <span class="string">My User Agent</span></span>
|
||
<span class="line"><span class="section-header">[QueryStringParams]</span></span>
|
||
<span class="line"><span class="string">id</span>: <span class="string">4567</span></span>
|
||
<span class="line"><span class="string">order</span>: <span class="string">newest</span></span>
|
||
<span class="line"><span class="section-header">[BasicAuth]</span></span>
|
||
<span class="line"><span class="string">alice</span>: <span class="string">secret</span></span></span></span></code></pre>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/dogs</span></span>
|
||
<span class="line"><span class="string">User-Agent</span>: <span class="string">My User Agent</span></span>
|
||
<span class="line"><span class="section-header">[BasicAuth]</span></span>
|
||
<span class="line"><span class="string">alice</span>: <span class="string">secret</span></span>
|
||
<span class="line"><span class="section-header">[QueryStringParams]</span></span>
|
||
<span class="line"><span class="string">id</span>: <span class="string">4567</span></span>
|
||
<span class="line"><span class="string">order</span>: <span class="string">newest</span></span></span></span></code></pre>
|
||
|
||
<p>The last optional part of a request configuration is the request <a href="#file-format-request-body">body</a>. Request body must be the last parameter of a request
|
||
(after <a href="#file-format-request-headers">headers</a> and request sections). Like headers, body have no explicit marker:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/api/dogs?id=4567</span></span>
|
||
<span class="line"><span class="string">User-Agent</span>: <span class="string">My User Agent</span></span>
|
||
<span class="json"><span class="line">{</span>
|
||
<span class="line"> "name": "Ralphy"</span>
|
||
<span class="line">}</span></span></span></span></code></pre>
|
||
|
||
<h3 id="file-format-request-description"><a href="#file-format-request-description">Description</a></h3>
|
||
|
||
<h4 id="file-format-request-method"><a href="#file-format-request-method">Method</a></h4>
|
||
|
||
<p>Mandatory HTTP request method, usually one of <code>GET</code>, <code>HEAD</code>, <code>POST</code>, <code>PUT</code>, <code>DELETE</code>, <code>CONNECT</code>, <code>OPTIONS</code>,
|
||
<code>TRACE</code> and <code>PATCH</code>.</p>
|
||
|
||
<blockquote>
|
||
<p>Other methods can be used like <code>QUERY</code> with the constraint of using only uppercase chars.</p>
|
||
</blockquote>
|
||
|
||
<h4 id="file-format-request-url"><a href="#file-format-request-url">URL</a></h4>
|
||
|
||
<p>Mandatory HTTP request URL.</p>
|
||
|
||
<p>URL can contain query parameters, even if using a <a href="#file-format-request-query-parameters">query parameters section</a> is preferred.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># A request with URL containing query parameters.</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/forum/questions/?search=Install%20Linux&order=newest</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># A request with query parameters section, equivalent to the first request.</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/forum/questions/</span></span>
|
||
<span class="line"><span class="section-header">[QueryStringParams]</span></span>
|
||
<span class="line"><span class="string">search</span>: <span class="string">Install Linux</span></span>
|
||
<span class="line"><span class="string">order</span>: <span class="string">newest</span></span></span></span></code></pre>
|
||
|
||
<blockquote>
|
||
<p>Query parameters in query parameter section are not URL encoded.</p>
|
||
</blockquote>
|
||
|
||
<p>When query parameters are present in the URL and in a query parameters section, the resulting request will
|
||
have both parameters.</p>
|
||
|
||
<h4 id="file-format-request-headers"><a href="#file-format-request-headers">Headers</a></h4>
|
||
|
||
<p>Optional list of HTTP request headers.</p>
|
||
|
||
<p>A header consists of a name, followed by a <code>:</code> and a value.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/news</span></span>
|
||
<span class="line"><span class="string">User-Agent</span>: <span class="string">Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0</span></span>
|
||
<span class="line"><span class="string">Accept</span>: <span class="string">*/*</span></span>
|
||
<span class="line"><span class="string">Accept-Language</span>: <span class="string">en-US,en;q=0.5</span></span>
|
||
<span class="line"><span class="string">Accept-Encoding</span>: <span class="string">gzip, deflate, br</span></span>
|
||
<span class="line"><span class="string">Connection</span>: <span class="string">keep-alive</span></span></span></span></code></pre>
|
||
|
||
<blockquote>
|
||
<p>Headers directly follow URL, without any section name, contrary to query parameters, form parameters
|
||
or cookies</p>
|
||
</blockquote>
|
||
|
||
<p>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:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">PATCH</span> <span class="url">https://example.org/file.txt</span></span>
|
||
<span class="line"><span class="string">If-Match</span>: <span class="string">"e0023aa4e"</span></span></span></span></code></pre>
|
||
|
||
<p><code>If-Match</code> request header will be sent will the following value <code>"e0023aa4e"</code> (started and ended with double quotes).</p>
|
||
|
||
<p>Headers must follow directly after the <a href="#file-format-request-method">method</a> and <a href="#file-format-request-url">URL</a>.</p>
|
||
|
||
<h4 id="file-format-request-options"><a href="#file-format-request-options">Options</a></h4>
|
||
|
||
<p>Options used to execute this request.</p>
|
||
|
||
<p>Options such as <a href="#getting-started-manual-location"><code>--location</code></a>, <a href="#getting-started-manual-verbose"><code>--verbose</code></a>, <a href="#getting-started-manual-insecure"><code>--insecure</code></a> can be used at the command line and applied to every
|
||
request of an Hurl file. An <code>[Options]</code> section can be used to apply option to only one request (without passing options
|
||
to the command line), while other requests are unaffected.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
<span class="line"></span><span class="comment"># An options section, each option is optional and applied only to this request...</span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">aws-sigv4</span>: <span class="string">aws:amz:sts</span></span> <span class="comment"># generate AWS SigV4 Authorization header</span>
|
||
<span class="line"><span class="string">cacert</span>: <span class="filename">/etc/cert.pem</span></span> <span class="comment"># custom certificate file</span>
|
||
<span class="line"><span class="string">cert</span>: <span class="filename">/etc/client-cert.pem</span></span> <span class="comment"># client authentication certificate</span>
|
||
<span class="line"><span class="string">key</span>: <span class="filename">/etc/client-cert.key</span></span> <span class="comment"># client authentication certificate key</span>
|
||
<span class="line"><span class="string">compressed</span>: <span class="boolean">true</span></span> <span class="comment"># request a compressed response</span>
|
||
<span class="line"><span class="string">connect-timeout</span>: <span class="number">20</span><span class="unit">s</span></span> <span class="comment"># connect timeout</span>
|
||
<span class="line"><span class="string">delay</span>: <span class="number">3</span><span class="unit">s</span></span> <span class="comment"># delay for this request</span>
|
||
<span class="line"><span class="string">http3</span>: <span class="boolean">true</span></span> <span class="comment"># use HTTP/3 protocol version</span>
|
||
<span class="line"><span class="string">insecure</span>: <span class="boolean">true</span></span> <span class="comment"># allow insecure SSL connections and transfers</span>
|
||
<span class="line"><span class="string">ipv6</span>: <span class="boolean">true</span></span> <span class="comment"># use IPv6 addresses</span>
|
||
<span class="line"><span class="string">limit-rate</span>: <span class="number">32000</span></span> <span class="comment"># limit this request to the specidied speed (bytes/s)</span>
|
||
<span class="line"><span class="string">location</span>: <span class="boolean">true</span></span> <span class="comment"># follow redirection for this request</span>
|
||
<span class="line"><span class="string">max-redirs</span>: <span class="number">10</span></span> <span class="comment"># maximum number of redirections</span>
|
||
<span class="line"><span class="string">output</span>: <span class="filename">out.html</span></span> <span class="comment"># dump the response to this file</span>
|
||
<span class="line"><span class="string">path-as-is</span>: <span class="boolean">true</span></span> <span class="comment"># do not handle sequences of /../ or /./ in URL path</span>
|
||
<span class="line"><span class="string">retry</span>: <span class="number">10</span></span> <span class="comment"># number of retry if HTTP/asserts errors</span>
|
||
<span class="line"><span class="string">retry-interval</span>: <span class="number">500</span><span class="unit">ms</span></span> <span class="comment"># interval between retry</span>
|
||
<span class="line"><span class="string">skip</span>: <span class="boolean">false</span></span> <span class="comment"># skip this request</span>
|
||
<span class="line"><span class="string">unix-socket</span>: <span class="string">sock</span></span> <span class="comment"># use Unix socket for transfer</span>
|
||
<span class="line"><span class="string">user</span>: <span class="string">bob:secret</span></span> <span class="comment"># use basic authentication</span>
|
||
<span class="line"><span class="string">proxy</span>: <span class="string">my.proxy:8012</span></span> <span class="comment"># define proxy (host:port where host can be an IP address)</span>
|
||
<span class="line"><span class="string">variable</span>: country=<span class="string">Italy</span></span> <span class="comment"># define variable country</span>
|
||
<span class="line"><span class="string">variable</span>: planet=<span class="string">Earth</span></span> <span class="comment"># define variable planet</span>
|
||
<span class="line"><span class="string">verbose</span>: <span class="boolean">true</span></span> <span class="comment"># allow verbose output</span>
|
||
<span class="line"><span class="string">very-verbose</span>: <span class="boolean">true</span></span> <span class="comment"># allow more verbose output</span></span></span></code></pre>
|
||
|
||
<blockquote>
|
||
<p>Variable defined in an <code>[Options]</code> section are defined also for the next entries. This is
|
||
the exception, all other options are defined only for the current request.</p>
|
||
</blockquote>
|
||
|
||
<h4 id="file-format-request-query-parameters"><a href="#file-format-request-query-parameters">Query parameters</a></h4>
|
||
|
||
<p>Optional list of query parameters.</p>
|
||
|
||
<p>A query parameter consists of a field, followed by a <code>:</code> and a value. The query parameters section starts with
|
||
<code>[QueryStringParams]</code>. Contrary to query parameters in the URL, each value in the query parameters section is not
|
||
URL encoded.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/news</span></span>
|
||
<span class="line"><span class="string">User-Agent</span>: <span class="string">Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0</span></span>
|
||
<span class="line"><span class="section-header">[QueryStringParams]</span></span>
|
||
<span class="line"><span class="string">order</span>: <span class="string">newest</span></span>
|
||
<span class="line"><span class="string">search</span>: <span class="string">{{custom-search}}</span></span>
|
||
<span class="line"><span class="string">count</span>: <span class="string">100</span></span></span></span></code></pre>
|
||
|
||
<p>If there are any parameters in the URL, the resulted request will have both parameters.</p>
|
||
|
||
<h4 id="file-format-request-form-parameters"><a href="#file-format-request-form-parameters">Form parameters</a></h4>
|
||
|
||
<p>A form parameters section can be used to send data, like <a href="https://developer.mozilla.org/en-US/docs/Learn/Forms">HTML form</a>.</p>
|
||
|
||
<p>This section contains an optional list of key values, each key followed by a <code>:</code> and a value. Key values will be
|
||
encoded in key-value tuple separated by ‘&’, with a ‘=’ between the key and the value, and sent in the body request.
|
||
The content type of the request is <code>application/x-www-form-urlencoded</code>. The form parameters section starts
|
||
with <code>[FormParams]</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/contact</span></span>
|
||
<span class="line"><span class="section-header">[FormParams]</span></span>
|
||
<span class="line"><span class="string">default</span>: <span class="string">false</span></span>
|
||
<span class="line"><span class="string">token</span>: <span class="string">{{token}}</span></span>
|
||
<span class="line"><span class="string">email</span>: <span class="string">john.doe@rookie.org</span></span>
|
||
<span class="line"><span class="string">number</span>: <span class="string">33611223344</span></span></span></span></code></pre>
|
||
|
||
<p>Form parameters section can be seen as syntactic sugar over body section (values in form parameters section
|
||
are not URL encoded.). A <a href="#file-format-request-oneline-string-body">oneline string body</a> could be used instead of a forms parameters section.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Run a POST request with form parameters section:</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://example.org/test</span></span>
|
||
<span class="line"><span class="section-header">[FormParams]</span></span>
|
||
<span class="line"><span class="string">name</span>: <span class="string">John Doe</span></span>
|
||
<span class="line"><span class="string">key1</span>: <span class="string">value1</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Run the same POST request with a body section:</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://example.org/test</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">application/x-www-form-urlencoded</span></span>
|
||
<span class="line"><span class="string">`name=John%20Doe&key1=value1`</span></span></span></span></code></pre>
|
||
|
||
<p>When both <a href="#file-format-request-body">body section</a> and form parameters section are present, only the body section is taken into account.</p>
|
||
|
||
<h4 id="file-format-request-multipart-form-data"><a href="#file-format-request-multipart-form-data">Multipart Form Data</a></h4>
|
||
|
||
<p>A multipart form data section can be used to send data, with key / value and file content
|
||
(see <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST">multipart/form-data on MDN</a>).</p>
|
||
|
||
<p>The form parameters section starts with <code>[MultipartFormData]</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/upload</span></span>
|
||
<span class="line"><span class="section-header">[MultipartFormData]</span></span>
|
||
<span class="line"><span class="string">field1</span>: <span class="string">value1</span></span>
|
||
<span class="line"><span class="string">field2</span>: file,<span class="filename">example.txt</span>;</span>
|
||
<span class="line"></span><span class="comment"># One can specify the file content type:</span>
|
||
<span class="line"><span class="string">field3</span>: file,<span class="filename">example.zip</span>; <span class="string">application/zip</span></span></span></span></code></pre>
|
||
|
||
<p>Files are relative to the input Hurl file, and cannot contain implicit parent directory (<code>..</code>). You can use<br />
|
||
<a href="#getting-started-manual-file-root"><code>--file-root</code> option</a> to specify the root directory of all file nodes.</p>
|
||
|
||
<p>Content type can be specified or inferred based on the filename extension:</p>
|
||
|
||
<ul>
|
||
<li><code>.gif</code>: <code>image/gif</code>,</li>
|
||
<li><code>.jpg</code>: <code>image/jpeg</code>,</li>
|
||
<li><code>.jpeg</code>: <code>image/jpeg</code>,</li>
|
||
<li><code>.png</code>: <code>image/png</code>,</li>
|
||
<li><code>.svg</code>: <code>image/svg+xml</code>,</li>
|
||
<li><code>.txt</code>: <code>text/plain</code>,</li>
|
||
<li><code>.htm</code>: <code>text/html</code>,</li>
|
||
<li><code>.html</code>: <code>text/html</code>,</li>
|
||
<li><code>.pdf</code>: <code>application/pdf</code>,</li>
|
||
<li><code>.xml</code>: <code>application/xml</code></li>
|
||
</ul>
|
||
|
||
<p>By default, content type is <code>application/octet-stream</code>.</p>
|
||
|
||
<p>As an alternative to a <code>[MultipartFormData]</code> section, multipart forms can also be sent with a <a href="#file-format-request-multiline-string-body">multiline string body</a>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/upload</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">multipart/form-data; boundary="boundary"</span></span>
|
||
<span class="multiline"><span class="line">```</span>
|
||
<span class="line">--boundary</span>
|
||
<span class="line">Content-Disposition: form-data; name="key1"</span>
|
||
<span class="line"></span>
|
||
<span class="line">value1</span>
|
||
<span class="line">--boundary</span>
|
||
<span class="line">Content-Disposition: form-data; name="upload1"; filename="data.txt"</span>
|
||
<span class="line">Content-Type: text/plain</span>
|
||
<span class="line"></span>
|
||
<span class="line">Hello World!</span>
|
||
<span class="line">--boundary</span>
|
||
<span class="line">Content-Disposition: form-data; name="upload2"; filename="data.html"</span>
|
||
<span class="line">Content-Type: text/html</span>
|
||
<span class="line"></span>
|
||
<span class="line"><div>Hello <b>World</b>!</div></span>
|
||
<span class="line">--boundary--</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<blockquote>
|
||
<p>When using a multiline string body to send a multipart form data, files content must be inlined in the Hurl file.</p>
|
||
</blockquote>
|
||
|
||
<h4 id="file-format-request-cookies"><a href="#file-format-request-cookies">Cookies</a></h4>
|
||
|
||
<p>Optional list of session cookies for this request.</p>
|
||
|
||
<p>A cookie consists of a name, followed by a <code>:</code> and a value. Cookies are sent per request, and are not added to
|
||
the cookie storage session, contrary to a cookie set in a header response. (for instance <code>Set-Cookie: theme=light</code>). The
|
||
cookies section starts with <code>[Cookies]</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/index.html</span></span>
|
||
<span class="line"><span class="section-header">[Cookies]</span></span>
|
||
<span class="line"><span class="string">theme</span>: <span class="string">light</span></span>
|
||
<span class="line"><span class="string">sessionToken</span>: <span class="string">abc123</span></span></span></span></code></pre>
|
||
|
||
<p>Cookies section can be seen as syntactic sugar over corresponding request header.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Run a GET request with cookies section:</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/index.html</span></span>
|
||
<span class="line"><span class="section-header">[Cookies]</span></span>
|
||
<span class="line"><span class="string">theme</span>: <span class="string">light</span></span>
|
||
<span class="line"><span class="string">sessionToken</span>: <span class="string">abc123</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Run the same GET request with a header:</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/index.html</span></span>
|
||
<span class="line"><span class="string">Cookie</span>: <span class="string">theme=light; sessionToken=abc123</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-request-basic-authentication"><a href="#file-format-request-basic-authentication">Basic Authentication</a></h4>
|
||
|
||
<p>A basic authentication section can be used to perform <a href="#file-format-request-basic-authentication">basic authentication</a>.</p>
|
||
|
||
<p>Username is followed by a <code>:</code> and a password. The basic authentication section starts with
|
||
<code>[BasicAuth]</code>. Username and password are <em>not</em> base64 encoded.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Perform basic authentication with login `bob` and password `secret`.</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/protected</span></span>
|
||
<span class="line"><span class="section-header">[BasicAuth]</span></span>
|
||
<span class="line"><span class="string">bob</span>: <span class="string">secret</span></span></span></span></code></pre>
|
||
|
||
<blockquote>
|
||
<p>Spaces surrounded username and password are trimmed. If you
|
||
really want a space in your password (!!), you could use <a href="#file-format-hurl-file-special-characters-in-strings">Hurl unicode literals \u{20}</a>.</p>
|
||
</blockquote>
|
||
|
||
<p>This is equivalent (but simpler) to construct the request with a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization">Authorization</a> header:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Authorization header value can be computed with `echo -n 'bob:secret' | base64`</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/protected</span></span>
|
||
<span class="line"><span class="string">Authorization</span>: <span class="string">Basic Ym9iOnNlY3JldA==</span></span></span></span></code></pre>
|
||
|
||
<p>Basic authentication allows per request authentication.
|
||
If you want to add basic authentication to all the requests of a Hurl file
|
||
you can use <a href="#getting-started-manual-user"><code>-u/--user</code> option</a>.</p>
|
||
|
||
<h4 id="file-format-request-body"><a href="#file-format-request-body">Body</a></h4>
|
||
|
||
<p>Optional HTTP body request.</p>
|
||
|
||
<p>If the body of the request is a <a href="https://www.json.org">JSON</a> string or a <a href="https://en.wikipedia.org/wiki/XML">XML</a> string, the value can be
|
||
directly inserted without any modification. For a text based body that is neither JSON nor XML,
|
||
one can use <a href="#file-format-request-multiline-string-body">multiline string body</a> that starts with <code>```</code> and ends
|
||
with <code>```</code>. Multiline string body support “language hint” and can be used
|
||
to create <a href="#file-format-request-graphql-query">GraphQL queries</a>.</p>
|
||
|
||
<p>For a precise byte control of the request body, <a href="https://en.wikipedia.org/wiki/Base64">Base64</a> encoded string, <a href="#file-format-request-hex-body">hexadecimal string</a>
|
||
or <a href="#file-format-request-file-body">included file</a> can be used to describe exactly the body byte content.</p>
|
||
|
||
<blockquote>
|
||
<p>You can set a body request even with a <code>GET</code> body, even if this is not a common practice.</p>
|
||
</blockquote>
|
||
|
||
<p>The body section must be the last section of the request configuration.</p>
|
||
|
||
<h5 id="file-format-request-json-body"><a href="#file-format-request-json-body">JSON body</a></h5>
|
||
|
||
<p>JSON request body is used to set a literal JSON as the request body.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Create a new doggy thing with JSON body:</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://example.org/api/dogs</span></span>
|
||
<span class="json"><span class="line">{</span>
|
||
<span class="line"> "id": 0,</span>
|
||
<span class="line"> "name": "Frieda",</span>
|
||
<span class="line"> "picture": "images/scottish-terrier.jpeg",</span>
|
||
<span class="line"> "age": 3,</span>
|
||
<span class="line"> "breed": "Scottish Terrier",</span>
|
||
<span class="line"> "location": "Lisco, Alabama"</span>
|
||
<span class="line">}</span></span></span></span></code></pre>
|
||
|
||
<p>JSON request body can be <a href="#file-format-templates-templating-body">templatized with variables</a>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Create a new catty thing with JSON body:</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://example.org/api/cats</span></span>
|
||
<span class="json"><span class="line">{</span>
|
||
<span class="line"> "id": 42,</span>
|
||
<span class="line"> "lives": {{lives_count}},</span>
|
||
<span class="line"> "name": "{{name}}"</span>
|
||
<span class="line">}</span></span></span></span></code></pre>
|
||
|
||
<p>When using JSON request body, the content type <code>application/json</code> is automatically set.</p>
|
||
|
||
<p>JSON request body can be seen as syntactic sugar of <a href="#file-format-request-multiline-string-body">multiline string body</a> with <code>json</code> identifier:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Create a new doggy thing with JSON body:</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://example.org/api/dogs</span></span>
|
||
<span class="multiline"><span class="line">```json</span>
|
||
<span class="line">{</span>
|
||
<span class="line"> "id": 0,</span>
|
||
<span class="line"> "name": "Frieda",</span>
|
||
<span class="line"> "picture": "images/scottish-terrier.jpeg",</span>
|
||
<span class="line"> "age": 3,</span>
|
||
<span class="line"> "breed": "Scottish Terrier",</span>
|
||
<span class="line"> "location": "Lisco, Alabama"</span>
|
||
<span class="line">}</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<h5 id="file-format-request-xml-body"><a href="#file-format-request-xml-body">XML body</a></h5>
|
||
|
||
<p>XML request body is used to set a literal XML as the request body.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Create a new soapy thing XML body:</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://example.org/InStock</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">application/soap+xml; charset=utf-8</span></span>
|
||
<span class="line"><span class="string">Content-Length</span>: <span class="string">299</span></span>
|
||
<span class="line"><span class="string">SOAPAction</span>: <span class="string">"http://www.w3.org/2003/05/soap-envelope"</span></span>
|
||
<span class="xml"><span class="line"><?xml version="1.0" encoding="UTF-8"?></span>
|
||
<span class="line"><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="http://example.net"></span>
|
||
<span class="line"> <soap:Header></soap:Header></span>
|
||
<span class="line"> <soap:Body></span>
|
||
<span class="line"> <m:GetStockPrice></span>
|
||
<span class="line"> <m:StockName>GOOG</m:StockName></span>
|
||
<span class="line"> </m:GetStockPrice></span>
|
||
<span class="line"> </soap:Body></span>
|
||
<span class="line"></soap:Envelope></span></span></span></span></code></pre>
|
||
|
||
<p>XML request body can be seen as syntactic sugar of <a href="#file-format-request-multiline-string-body">multiline string body</a> with <code>xml</code> identifier:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Create a new soapy thing XML body:</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://example.org/InStock</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">application/soap+xml; charset=utf-8</span></span>
|
||
<span class="line"><span class="string">Content-Length</span>: <span class="string">299</span></span>
|
||
<span class="line"><span class="string">SOAPAction</span>: <span class="string">"http://www.w3.org/2003/05/soap-envelope"</span></span>
|
||
<span class="multiline"><span class="line">```xml</span>
|
||
<span class="line"><?xml version="1.0" encoding="UTF-8"?></span>
|
||
<span class="line"><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="http://example.net"></span>
|
||
<span class="line"> <soap:Header></soap:Header></span>
|
||
<span class="line"> <soap:Body></span>
|
||
<span class="line"> <m:GetStockPrice></span>
|
||
<span class="line"> <m:StockName>GOOG</m:StockName></span>
|
||
<span class="line"> </m:GetStockPrice></span>
|
||
<span class="line"> </soap:Body></span>
|
||
<span class="line"></soap:Envelope></span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<blockquote>
|
||
<p>Contrary to JSON body, the succinct syntax of XML body can not use variables. If you need to use variables in your
|
||
XML body, use a simple <a href="#file-format-request-multiline-string-body">multiline string body</a> with variables.</p>
|
||
</blockquote>
|
||
|
||
<h5 id="file-format-request-graphql-query"><a href="#file-format-request-graphql-query">GraphQL query</a></h5>
|
||
|
||
<p>GraphQL query uses <a href="#file-format-request-multiline-string-body">multiline string body</a> with <code>graphql</code> identifier:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/starwars/graphql</span></span>
|
||
<span class="multiline"><span class="line">```graphql</span>
|
||
<span class="line">{</span>
|
||
<span class="line"> human(id: "1000") {</span>
|
||
<span class="line"> name</span>
|
||
<span class="line"> height(unit: FOOT)</span>
|
||
<span class="line"> }</span>
|
||
<span class="line">}</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<p>GraphQL query body can use <a href="https://graphql.org/learn/queries/#variables">GraphQL variables</a>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/starwars/graphql</span></span>
|
||
<span class="multiline"><span class="line">```graphql</span>
|
||
<span class="line">query Hero($episode: Episode, $withFriends: Boolean!) {</span>
|
||
<span class="line"> hero(episode: $episode) {</span>
|
||
<span class="line"> name</span>
|
||
<span class="line"> friends @include(if: $withFriends) {</span>
|
||
<span class="line"> name</span>
|
||
<span class="line"> }</span>
|
||
<span class="line"> }</span>
|
||
<span class="line">}</span>
|
||
<span class="line"></span>
|
||
<span class="line">variables {</span>
|
||
<span class="line"> "episode": "JEDI",</span>
|
||
<span class="line"> "withFriends": false</span>
|
||
<span class="line">}</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<p>GraphQL query, as every multiline string body, can use Hurl variables.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/starwars/graphql</span></span>
|
||
<span class="multiline"><span class="line">```graphql</span>
|
||
<span class="line">{</span>
|
||
<span class="line"> human(id: "{{human_id}}") {</span>
|
||
<span class="line"> name</span>
|
||
<span class="line"> height(unit: FOOT)</span>
|
||
<span class="line"> }</span>
|
||
<span class="line">}</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<blockquote>
|
||
<p>Hurl variables and GraphQL variables can be mixed in the same body.</p>
|
||
</blockquote>
|
||
|
||
<h5 id="file-format-request-multiline-string-body"><a href="#file-format-request-multiline-string-body">Multiline string body</a></h5>
|
||
|
||
<p>For text based body that are neither JSON nor XML, one can use multiline string, started and ending with
|
||
<code>```</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/models</span></span>
|
||
<span class="multiline"><span class="line">```</span>
|
||
<span class="line">Year,Make,Model,Description,Price</span>
|
||
<span class="line">1997,Ford,E350,"ac, abs, moon",3000.00</span>
|
||
<span class="line">1999,Chevy,"Venture ""Extended Edition""","",4900.00</span>
|
||
<span class="line">1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00</span>
|
||
<span class="line">1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<p>The standard usage of a multiline string is:</p>
|
||
|
||
<pre><code>```
|
||
line1
|
||
line2
|
||
line3
|
||
```
|
||
</code></pre>
|
||
|
||
<p>is evaluated as “line1\nline2\nline3\n”.</p>
|
||
|
||
<p>Multiline string body can use language identifier, like <code>json</code>, <code>xml</code> or <code>graphql</code>. 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.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/api/dogs</span></span>
|
||
<span class="multiline"><span class="line">```json</span>
|
||
<span class="line">{</span>
|
||
<span class="line"> "id": 0,</span>
|
||
<span class="line"> "name": "Frieda",</span>
|
||
<span class="line">}</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<h5 id="file-format-request-oneline-string-body"><a href="#file-format-request-oneline-string-body">Oneline string body</a></h5>
|
||
|
||
<p>For text based body that do not contain newlines, one can use oneline string, started and ending with <code>`</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/helloworld</span></span>
|
||
<span class="line"><span class="string">`Hello world!`</span></span></span></span></code></pre>
|
||
|
||
<h5 id="file-format-request-base64-body"><a href="#file-format-request-base64-body">Base64 body</a></h5>
|
||
|
||
<p>Base64 body is used to set binary data as the request body.</p>
|
||
|
||
<p>Base64 body starts with <code>base64,</code> and end with <code>;</code>. MIME’s Base64 encoding is supported (newlines and white spaces may be
|
||
present anywhere but are to be ignored on decoding), and <code>=</code> padding characters might be added.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org</span></span>
|
||
<span class="line"></span><span class="comment"># Some random comments before body</span>
|
||
<span class="line">base64,<span class="base64">TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIG
|
||
FkaXBpc2NpbmcgZWxpdC4gSW4gbWFsZXN1YWRhLCBuaXNsIHZlbCBkaWN0dW0g
|
||
aGVuZHJlcml0LCBlc3QganVzdG8gYmliZW5kdW0gbWV0dXMsIG5lYyBydXRydW
|
||
0gdG9ydG9yIG1hc3NhIGlkIG1ldHVzLiA=</span>;</span></span></span></code></pre>
|
||
|
||
<h5 id="file-format-request-hex-body"><a href="#file-format-request-hex-body">Hex body</a></h5>
|
||
|
||
<p>Hex body is used to set binary data as the request body.</p>
|
||
|
||
<p>Hex body starts with <code>hex,</code> and end with <code>;</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">PUT</span> <span class="url">https://example.org</span></span>
|
||
<span class="line"></span><span class="comment"># Send a café, encoded in UTF-8</span>
|
||
<span class="line">hex,<span class="hex">636166c3a90a</span>;</span></span></span></code></pre>
|
||
|
||
<h5 id="file-format-request-file-body"><a href="#file-format-request-file-body">File body</a></h5>
|
||
|
||
<p>To use the binary content of a local file as the body request, file body can be used. File body starts with
|
||
<code>file,</code> and ends with <code>;</code>`</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org</span></span>
|
||
<span class="line"></span><span class="comment"># Some random comments before body</span>
|
||
<span class="line">file,<span class="filename">data.bin</span>;</span></span></span></code></pre>
|
||
|
||
<p>File are relative to the input Hurl file, and cannot contain implicit parent directory (<code>..</code>). You can use<br />
|
||
<a href="#getting-started-manual-file-root"><code>--file-root</code> option</a> to specify the root directory of all file nodes.</p>
|
||
|
||
<hr />
|
||
|
||
<h2 id="file-format-response-response"><a href="#file-format-response-response">Response</a></h2>
|
||
|
||
<h3 id="file-format-response-definition"><a href="#file-format-response-definition">Definition</a></h3>
|
||
|
||
<p>Responses can be used to capture values to perform subsequent requests, or add asserts to HTTP responses. Response on
|
||
requests are optional, a Hurl file can just consist of a sequence of <a href="#file-format-request">requests</a>.</p>
|
||
|
||
<p>A response describes the expected HTTP response, with mandatory <a href="#file-format-asserting-response-version-status">version and status</a>, followed by optional <a href="#file-format-asserting-response-headers">headers</a>,
|
||
<a href="#file-format-capturing-response-captures">captures</a>, <a href="#file-format-asserting-response-asserts">asserts</a> and <a href="#file-format-asserting-response-body">body</a>. Assertions in the expected HTTP response describe values of the received HTTP response.
|
||
Captures capture values from the received HTTP response and populate a set of named variables that can be used
|
||
in the following entries.</p>
|
||
|
||
<h3 id="file-format-response-example"><a href="#file-format-response-example">Example</a></h3>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="string">Last-Modified</span>: <span class="string">Wed, 21 Oct 2015 07:28:00 GMT</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"normalize-space(//head/title)"</span> <span class="predicate-type">startsWith</span> <span class="string">"Welcome"</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"//li"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">18</span></span></span></span></code></pre>
|
||
|
||
<h3 id="file-format-response-structure"><a href="#file-format-response-structure">Structure</a></h3>
|
||
|
||
<div class="hurl-structure-schema">
|
||
<div class="hurl-structure">
|
||
<div class="hurl-structure-col-0">
|
||
<div class="hurl-part-0">
|
||
HTTP 200
|
||
</div>
|
||
<div class=" hurl-part-1">
|
||
content-length: 206<br />accept-ranges: bytes<br />user-agent: Test
|
||
</div>
|
||
<div class="hurl-part-2">
|
||
[Captures]<br />...
|
||
</div>
|
||
<div class="hurl-part-2">
|
||
[Asserts]<br />...
|
||
</div>
|
||
<div class="hurl-part-3">
|
||
{<br />
|
||
"type": "FOO",<br />
|
||
"value": 356789,<br />
|
||
"ordered": true,<br />
|
||
"index": 10<br />
|
||
}
|
||
</div>
|
||
</div>
|
||
<div class="hurl-structure-col-1">
|
||
<div class="hurl-request-explanation-part-0">
|
||
<a href="#file-format-asserting-response-version-status">Version and status (mandatory if response present)</a>
|
||
</div>
|
||
<div class="hurl-request-explanation-part-1">
|
||
<br /><a href="#file-format-asserting-response-headers">HTTP response headers</a> (optional)
|
||
</div>
|
||
<div class="hurl-request-explanation-part-2">
|
||
<br />
|
||
<br />
|
||
</div>
|
||
<div class="hurl-request-explanation-part-2">
|
||
<a href="#file-format-capturing-response-capturing-response">Captures</a> and <a href="#file-format-asserting-response-asserts">asserts</a> (optional sections, unordered)
|
||
</div>
|
||
<div class="hurl-request-explanation-part-2">
|
||
<br />
|
||
<br />
|
||
<br />
|
||
<br />
|
||
</div>
|
||
<div class="hurl-request-explanation-part-3">
|
||
<a href="#file-format-asserting-response-body">HTTP response body</a> (optional)
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 id="file-format-response-capture-and-assertion"><a href="#file-format-response-capture-and-assertion">Capture and Assertion</a></h3>
|
||
|
||
<p>With the response section, one can optionally <a href="#file-format-capturing-response">capture value from headers, body</a>, or <a href="#file-format-asserting-response">add assert on status code, body or headers</a>.</p>
|
||
|
||
<h4 id="file-format-response-body-compression"><a href="#file-format-response-body-compression">Body compression</a></h4>
|
||
|
||
<p>Hurl outputs the raw HTTP body to stdout by default. If response body is compressed (using <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding">br, gzip, deflate</a>),
|
||
the binary stream is output, without any modification. One can use <a href="#getting-started-manual-compressed"><code>--compressed</code> option</a>
|
||
to request a compressed response and automatically get the decompressed body.</p>
|
||
|
||
<p>Captures and asserts work automatically on the decompressed body, so you can request compressed data (using <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding"><code>Accept-Encoding</code></a>
|
||
header by example) and add assert and captures on the decoded body as if there weren’t any compression.</p>
|
||
|
||
<h3 id="file-format-response-timings"><a href="#file-format-response-timings">Timings</a></h3>
|
||
|
||
<p>HTTP response timings are exposed through Hurl structured output (see <a href="#getting-started-manual-json"><code>--json</code></a>), HTML report (see <a href="#getting-started-manual-report-html"><code>--report-html</code></a>)
|
||
and JSON report (see <a href="#getting-started-manual-report-json"><code>--report-json</code></a>).</p>
|
||
|
||
<p>On each response, libcurl response timings are available:</p>
|
||
|
||
<ul>
|
||
<li><strong>time_namelookup</strong>: the time it took from the start until the name resolving was completed. You can use
|
||
<a href="#getting-started-manual-resolve"><code>--resolve</code></a> to exclude DNS performance from the measure.</li>
|
||
<li><strong>time_connect</strong>: The time it took from the start until the TCP connect to the remote host (or proxy) was completed.</li>
|
||
<li><strong>time_appconnect</strong>: The time it took from the start until the SSL/SSH/etc connect/handshake to the remote host was
|
||
completed. The client is then ready to send its HTTP GET request.</li>
|
||
<li><strong>time_starttransfer</strong>: The time it took from the start until the first byte was just about to be transferred
|
||
(just before Hurl reads the first byte from the network). This includes time_pretransfer and also the time the server
|
||
needed to calculate the result.</li>
|
||
<li><strong>time_total</strong>: The total time that the full operation lasted.</li>
|
||
</ul>
|
||
|
||
<p>All timings are in microsecond.</p>
|
||
|
||
<div class="picture">
|
||
<img class="u-theme-light u-drop-shadow u-border u-max-width-100" src="https://hurl.dev/assets/img/timings-light.svg" alt="Response timings explanation" />
|
||
<img class="u-theme-dark u-drop-shadow u-border u-max-width-100" src="https://hurl.dev/assets/img/timings-dark.svg" alt="Response timings explanation" />
|
||
<a href="https://blog.cloudflare.com/a-question-of-timing/"><small>Courtesy of CloudFlare</small></a>
|
||
</div>
|
||
|
||
<hr />
|
||
|
||
<h2 id="file-format-capturing-response-capturing-response"><a href="#file-format-capturing-response-capturing-response">Capturing Response</a></h2>
|
||
|
||
<h3 id="file-format-capturing-response-captures"><a href="#file-format-capturing-response-captures">Captures</a></h3>
|
||
|
||
<p>Captures are optional values that are <strong>extracted from the HTTP response</strong> and stored in a named variable.
|
||
These captures may be the response status code, part of or the entire the body, and response headers.</p>
|
||
|
||
<p>Captured variables can be accessed through a run session; each new value of a given variable overrides the last value.</p>
|
||
|
||
<p>Captures can be useful for using data from one request in another request, such as when working with <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF tokens</a>.
|
||
Variables in a Hurl file can be created from captures or <a href="#file-format-templates-injecting-variables">injected into the session</a>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># An example to show how to pass a CSRF token</span>
|
||
<span class="line"></span><span class="comment"># from one request to another:</span>
|
||
<span class="line"></span>
|
||
<span class="line"></span><span class="comment"># First GET request to get CSRF token value:</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"></span><span class="comment"># Capture the CSRF token value from html body.</span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">csrf_token</span>: <span class="query-type">xpath</span> <span class="string">"normalize-space(//meta[@name='_csrf_token']/@content)"</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Do the login !</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://acmecorp.net/login?user=toto&password=1234</span></span>
|
||
<span class="line"><span class="string">X-CSRF-TOKEN</span>: <span class="string">{{csrf_token}}</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">302</span></span></span></span></code></pre>
|
||
|
||
<p>Structure of a capture:</p>
|
||
|
||
<div class="schema-container schema-container u-font-size-2 u-font-size-3-sm">
|
||
<div class="schema">
|
||
<span class="schema-token schema-color-1">my_var<span class="schema-label">variable</span></span>
|
||
<span> : </span>
|
||
<span class="schema-token schema-color-2">xpath "string(//h1)"<span class="schema-label">query</span></span>
|
||
</div>
|
||
</div>
|
||
|
||
<p>A capture consists of a variable name, followed by <code>:</code> and a query. Captures
|
||
section starts with <code>[Captures]</code>.</p>
|
||
|
||
<h4 id="file-format-capturing-response-query"><a href="#file-format-capturing-response-query">Query</a></h4>
|
||
|
||
<p>Queries are used to extract data from an HTTP response.</p>
|
||
|
||
<p>A query can be of the following type:</p>
|
||
|
||
<ul>
|
||
<li><a href="#file-format-capturing-response-status-capture"><code>status</code></a></li>
|
||
<li><a href="#file-format-capturing-response-header-capture"><code>header</code></a></li>
|
||
<li><a href="#file-format-capturing-response-url-capture"><code>url</code></a></li>
|
||
<li><a href="#file-format-capturing-response-cookie-capture"><code>cookie</code></a></li>
|
||
<li><a href="#file-format-capturing-response-body-capture"><code>body</code></a></li>
|
||
<li><a href="#file-format-capturing-response-bytes-capture"><code>bytes</code></a></li>
|
||
<li><a href="#file-format-capturing-response-xpath-capture"><code>xpath</code></a></li>
|
||
<li><a href="#file-format-capturing-response-jsonpath-capture"><code>jsonpath</code></a></li>
|
||
<li><a href="#file-format-capturing-response-regex-capture"><code>regex</code></a></li>
|
||
<li><a href="#file-format-capturing-response-variable-capture"><code>variable</code></a></li>
|
||
<li><a href="#file-format-capturing-response-duration-capture"><code>duration</code></a></li>
|
||
<li><a href="#file-format-capturing-response-certificate-capture"><code>certificate</code></a></li>
|
||
</ul>
|
||
|
||
<p>Extracted data can then be further refined using <a href="#file-format-filters">filters</a>.</p>
|
||
|
||
<h4 id="file-format-capturing-response-status-capture"><a href="#file-format-capturing-response-status-capture">Status capture</a></h4>
|
||
|
||
<p>Capture the received HTTP response status code. Status capture consists of a variable name, followed by a <code>:</code>, and the
|
||
keyword <code>status</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">my_status</span>: <span class="query-type">status</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-capturing-response-header-capture"><a href="#file-format-capturing-response-header-capture">Header capture</a></h4>
|
||
|
||
<p>Capture a header from the received HTTP response headers. Header capture consists of a variable name, followed by a <code>:</code>,
|
||
then the keyword <code>header</code> and a header name.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/login</span></span>
|
||
<span class="line"><span class="section-header">[FormParams]</span></span>
|
||
<span class="line"><span class="string">user</span>: <span class="string">toto</span></span>
|
||
<span class="line"><span class="string">password</span>: <span class="string">12345678</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">302</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">next_url</span>: <span class="query-type">header</span> <span class="string">"Location"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-capturing-response-url-capture"><a href="#file-format-capturing-response-url-capture">URL capture</a></h4>
|
||
|
||
<p>Capture the last fetched URL. This is most meaningful if you have told Hurl to follow redirection (see [<code>[Options]</code> section]<a href="#file-format-request-options">options</a> or
|
||
<a href="#getting-started-manual-location"><code>--location</code> option</a>). URL capture consists of a variable name, followed by a <code>:</code>, and the keyword <code>url</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/redirecting</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">location</span>: <span class="boolean">true</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">landing_url</span>: <span class="query-type">url</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-capturing-response-cookie-capture"><a href="#file-format-capturing-response-cookie-capture">Cookie capture</a></h4>
|
||
|
||
<p>Capture a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie"><code>Set-Cookie</code></a> header from the received HTTP response headers. Cookie
|
||
capture consists of a variable name, followed by a <code>:</code>, then the keyword <code>cookie</code>
|
||
and a cookie name.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/cookies/set</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">session-id</span>: <span class="query-type">cookie</span> <span class="string">"LSID"</span></span></span></span></code></pre>
|
||
|
||
<p>Cookie attributes value can also be captured by using the following format:
|
||
<code><cookie-name>[cookie-attribute]</code>. The following attributes are supported:
|
||
<code>Value</code>, <code>Expires</code>, <code>Max-Age</code>, <code>Domain</code>, <code>Path</code>, <code>Secure</code>, <code>HttpOnly</code> and <code>SameSite</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/cookies/set</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">value1</span>: <span class="query-type">cookie</span> <span class="string">"LSID"</span></span>
|
||
<span class="line"><span class="string">value2</span>: <span class="query-type">cookie</span> <span class="string">"LSID[Value]"</span></span> <span class="comment"># Equivalent to the previous capture</span>
|
||
<span class="line"><span class="string">expires</span>: <span class="query-type">cookie</span> <span class="string">"LSID[Expires]"</span></span>
|
||
<span class="line"><span class="string">max-age</span>: <span class="query-type">cookie</span> <span class="string">"LSID[Max-Age]"</span></span>
|
||
<span class="line"><span class="string">domain</span>: <span class="query-type">cookie</span> <span class="string">"LSID[Domain]"</span></span>
|
||
<span class="line"><span class="string">path</span>: <span class="query-type">cookie</span> <span class="string">"LSID[Path]"</span></span>
|
||
<span class="line"><span class="string">secure</span>: <span class="query-type">cookie</span> <span class="string">"LSID[Secure]"</span></span>
|
||
<span class="line"><span class="string">http-only</span>: <span class="query-type">cookie</span> <span class="string">"LSID[HttpOnly]"</span></span>
|
||
<span class="line"><span class="string">same-site</span>: <span class="query-type">cookie</span> <span class="string">"LSID[SameSite]"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-capturing-response-body-capture"><a href="#file-format-capturing-response-body-capture">Body capture</a></h4>
|
||
|
||
<p>Capture the entire body (decoded as text) from the received HTTP response. The encoding used to decode the body
|
||
is based on the <code>charset</code> value in the <code>Content-Type</code> header response.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/home</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">my_body</span>: <span class="query-type">body</span></span></span></span></code></pre>
|
||
|
||
<p>If the <code>Content-Type</code> doesn’t include any encoding hint, a <a href="#file-format-filters-decode"><code>decode</code> filter</a> can be used to explicitly decode the body response
|
||
bytes.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Our HTML response is encoded using GB 2312.</span>
|
||
<span class="line"></span><span class="comment"># But, the 'Content-Type' HTTP response header doesn't precise any charset,</span>
|
||
<span class="line"></span><span class="comment"># so we decode explicitly the bytes.</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/cn</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">my_body</span>: <span class="query-type">bytes</span> <span class="filter-type">decode</span> <span class="string">"gb2312"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-capturing-response-bytes-capture"><a href="#file-format-capturing-response-bytes-capture">Bytes capture</a></h4>
|
||
|
||
<p>Capture the entire body (as a raw bytestream) from the received HTTP response</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/data.bin</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">my_data</span>: <span class="query-type">bytes</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-capturing-response-xpath-capture"><a href="#file-format-capturing-response-xpath-capture">XPath capture</a></h4>
|
||
|
||
<p>Capture a <a href="https://en.wikipedia.org/wiki/XPath">XPath</a> query from the received HTTP body decoded as a string.
|
||
Currently, only XPath 1.0 expression can be used.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/home</span></span>
|
||
</span><span class="response"><span class="line"></span><span class="comment"># Capture the identifier from the dom node <div id="pet0">5646eaf23</div</span>
|
||
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">pet-id</span>: <span class="query-type">xpath</span> <span class="string">"normalize-space(//div[@id='pet0'])"</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Open the captured page.</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/home/pets/{{pet-id}}</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p>XPath captures are not limited to node values (like string, or boolean); any
|
||
valid XPath can be captured and asserted with variable asserts.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Test that the XML endpoint return 200 pets</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/pets</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">pets</span>: <span class="query-type">xpath</span> <span class="string">"//pets"</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">variable</span> <span class="string">"pets"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p>XPath expression can also be evaluated against part of the body with a <a href="#file-format-filters-xpath"><code>xpath</code> filter</a>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/home_cn</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">pet-id</span>: <span class="query-type">bytes</span> <span class="filter-type">decode</span> <span class="string">"gb2312"</span> <span class="filter-type">xpath</span> <span class="string">"normalize-space(//div[@id='pet0'])"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-capturing-response-jsonpath-capture"><a href="#file-format-capturing-response-jsonpath-capture">JSONPath capture</a></h4>
|
||
|
||
<p>Capture a <a href="https://goessner.net/articles/JsonPath/">JSONPath</a> query from the received HTTP body.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/api/contact</span></span>
|
||
<span class="line"><span class="section-header">[FormParams]</span></span>
|
||
<span class="line"><span class="string">token</span>: <span class="string">{{token}}</span></span>
|
||
<span class="line"><span class="string">email</span>: <span class="string">toto@rookie.net</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">contact-id</span>: <span class="query-type">jsonpath</span> <span class="string">"$['id']"</span></span></span></span></code></pre>
|
||
|
||
<blockquote>
|
||
<p>Explain that the value selected by the JSONPath is coerced to a string when only one node is selected.</p>
|
||
</blockquote>
|
||
|
||
<p>As with <a href="#file-format-capturing-response-xpath-capture">XPath captures</a>, JSONPath captures can be anything from string, number, to object and collections.
|
||
For instance, if we have a JSON endpoint that returns the following JSON:</p>
|
||
|
||
<pre><code>{
|
||
"a_null": null,
|
||
"an_object": {
|
||
"id": "123"
|
||
},
|
||
"a_list": [
|
||
1,
|
||
2,
|
||
3
|
||
],
|
||
"an_integer": 1,
|
||
"a float": 1.1,
|
||
"a_bool": true,
|
||
"a_string": "hello"
|
||
}
|
||
</code></pre>
|
||
|
||
<p>We can capture the following paths:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/captures-json</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">an_object</span>: <span class="query-type">jsonpath</span> <span class="string">"$['an_object']"</span></span>
|
||
<span class="line"><span class="string">a_list</span>: <span class="query-type">jsonpath</span> <span class="string">"$['a_list']"</span></span>
|
||
<span class="line"><span class="string">a_null</span>: <span class="query-type">jsonpath</span> <span class="string">"$['a_null']"</span></span>
|
||
<span class="line"><span class="string">an_integer</span>: <span class="query-type">jsonpath</span> <span class="string">"$['an_integer']"</span></span>
|
||
<span class="line"><span class="string">a_float</span>: <span class="query-type">jsonpath</span> <span class="string">"$['a_float']"</span></span>
|
||
<span class="line"><span class="string">a_bool</span>: <span class="query-type">jsonpath</span> <span class="string">"$['a_bool']"</span></span>
|
||
<span class="line"><span class="string">a_string</span>: <span class="query-type">jsonpath</span> <span class="string">"$['a_string']"</span></span>
|
||
<span class="line"><span class="string">all</span>: <span class="query-type">jsonpath</span> <span class="string">"$"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-capturing-response-regex-capture"><a href="#file-format-capturing-response-regex-capture">Regex capture</a></h4>
|
||
|
||
<p>Capture a regex pattern from the HTTP received body, decoded as text.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/helloworld</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">id_a</span>: <span class="query-type">regex</span> <span class="string">"id_a:([0-9]+)"</span></span>
|
||
<span class="line"><span class="string">id_b</span>: <span class="query-type">regex</span> <span class="string">"id_b:(\\d+)"</span></span> <span class="comment"># pattern using double quote </span>
|
||
<span class="line"><span class="string">id_c</span>: <span class="query-type">regex</span> <span class="regex">/id_c:(\d+)/</span></span> <span class="comment"># pattern using forward slash</span>
|
||
<span class="line"><span class="string">name</span>: <span class="query-type">regex</span> <span class="string">"Hello ([a-zA-Z]+)"</span></span></span></span></code></pre>
|
||
|
||
<p>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 <code>\d</code>, <code>\s</code>) must be escaped; literal pattern enclosed by <code>/</code> can also be used to avoid metacharacters escaping.</p>
|
||
|
||
<h4 id="file-format-capturing-response-variable-capture"><a href="#file-format-capturing-response-variable-capture">Variable capture</a></h4>
|
||
|
||
<p>Capture the value of a variable into another.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/helloworld</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">in</span>: <span class="query-type">body</span></span>
|
||
<span class="line"><span class="string">name</span>: <span class="query-type">variable</span> <span class="string">"in"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-capturing-response-duration-capture"><a href="#file-format-capturing-response-duration-capture">Duration capture</a></h4>
|
||
|
||
<p>Capture the response time of the request in ms.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/helloworld</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">duration_in_ms</span>: <span class="query-type">duration</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-capturing-response-ssl-certificate-capture"><a href="#file-format-capturing-response-ssl-certificate-capture">SSL certificate capture</a></h4>
|
||
|
||
<p>Capture the SSL certificate properties. Certificate capture consists of the keyword <code>certificate</code>, followed by the certificate attribute value.</p>
|
||
|
||
<p>The following attributes are supported: <code>Subject</code>, <code>Issuer</code>, <code>Start-Date</code>, <code>Expire-Date</code> and <code>Serial-Number</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">cert_subject</span>: <span class="query-type">certificate</span> <span class="string">"Subject"</span></span>
|
||
<span class="line"><span class="string">cert_issuer</span>: <span class="query-type">certificate</span> <span class="string">"Issuer"</span></span>
|
||
<span class="line"><span class="string">cert_expire_date</span>: <span class="query-type">certificate</span> <span class="string">"Expire-Date"</span></span>
|
||
<span class="line"><span class="string">cert_serial_number</span>: <span class="query-type">certificate</span> <span class="string">"Serial-Number"</span></span></span></span></code></pre>
|
||
|
||
<hr />
|
||
|
||
<h2 id="file-format-asserting-response-asserting-response"><a href="#file-format-asserting-response-asserting-response">Asserting Response</a></h2>
|
||
|
||
<h3 id="file-format-asserting-response-asserts"><a href="#file-format-asserting-response-asserts">Asserts</a></h3>
|
||
|
||
<p>Asserts are used to test various properties of an HTTP response. Asserts can be implicits (such as version, status,
|
||
headers) or explicit within an <code>[Asserts]</code> section. The delimiter of the request / response is <code>HTTP <STATUS-CODE></code>:
|
||
after this delimiter, you’ll find the implicit asserts, then an <code>[Asserts]</code> section with all the explicit checks.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/cats</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">application/json; charset=utf-8</span></span> <span class="comment"># Implicit assert on Content-Type Header</span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span> <span class="comment"># Explicit asserts section </span>
|
||
<span class="line"><span class="query-type">bytes</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">120</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Content-Type"</span> <span class="predicate-type">contains</span> <span class="string">"utf-8"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.cats"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">49</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.cats[0].name"</span> <span class="predicate-type">==</span> <span class="string">"Felix"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.cats[0].lives"</span> <span class="predicate-type">==</span> <span class="number">9</span></span></span></span></code></pre>
|
||
|
||
<h3 id="file-format-asserting-response-implicit-asserts"><a href="#file-format-asserting-response-implicit-asserts">Implicit asserts</a></h3>
|
||
|
||
<h4 id="file-format-asserting-response-version-status"><a href="#file-format-asserting-response-version-status">Version - Status</a></h4>
|
||
|
||
<p>Expected protocol version and status code of the HTTP response.</p>
|
||
|
||
<p>Protocol version is one of <code>HTTP/1.0</code>, <code>HTTP/1.1</code>, <code>HTTP/2</code>, <code>HTTP/3</code> or
|
||
<code>HTTP</code>; <code>HTTP</code> describes any version. Note that there are no status text following the status code.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/404.html</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">404</span></span></span></span></code></pre>
|
||
|
||
<p>Wildcard keywords <code>HTTP</code> and <code>*</code> can be used to disable tests on protocol version and status:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/pets</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">*</span></span>
|
||
<span class="line"></span><span class="comment"># Check that response status code is > 400 and <= 500</span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">status</span> <span class="predicate-type">></span> <span class="number">400</span></span>
|
||
<span class="line"><span class="query-type">status</span> <span class="predicate-type"><=</span> <span class="number">500</span></span></span></span></code></pre>
|
||
|
||
<p>While <code>HTTP/1.0</code>, <code>HTTP/1.1</code>, <code>HTTP/2</code> and <code>HTTP/3</code> explicitly check HTTP version:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Check that our server responds with HTTP/2</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/pets</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP/2</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-headers"><a href="#file-format-asserting-response-headers">Headers</a></h4>
|
||
|
||
<p>Optional list of the expected HTTP response headers that must be in the received response.</p>
|
||
|
||
<p>A header consists of a name, followed by a <code>:</code> and a value.</p>
|
||
|
||
<p>For each expected header, the received response headers are checked. If the received header is not equal to the
|
||
expected, or not present, an error is raised. The comparison is case-insensitive for the name: expecting a
|
||
<code>Content-Type</code> header is equivalent to a <code>content-type</code> one. Note that the expected headers list is not fully
|
||
descriptive: headers present in the response and not in the expected list doesn’t raise error.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Check that user toto is redirected to home after login.</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://example.org/login</span></span>
|
||
<span class="line"><span class="section-header">[FormParams]</span></span>
|
||
<span class="line"><span class="string">user</span>: <span class="string">toto</span></span>
|
||
<span class="line"><span class="string">password</span>: <span class="string">12345678</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">302</span></span>
|
||
<span class="line"><span class="string">Location</span>: <span class="string">https://example.org/home</span></span></span></span></code></pre>
|
||
|
||
<blockquote>
|
||
<p>Quotes in the header value are part of the value itself.</p>
|
||
|
||
<p>This is used by the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag">ETag</a> Header
|
||
<code>
|
||
ETag: W/"<etag_value>"
|
||
ETag: "<etag_value>"
|
||
</code></p>
|
||
</blockquote>
|
||
|
||
<p>Testing duplicated headers is also possible.</p>
|
||
|
||
<p>For example with the <code>Set-Cookie</code> header:</p>
|
||
|
||
<pre><code>Set-Cookie: theme=light
|
||
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
|
||
</code></pre>
|
||
|
||
<p>You can either test the two header values:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/index.html</span></span>
|
||
<span class="line"><span class="string">Host</span>: <span class="string">example.net</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="string">Set-Cookie</span>: <span class="string">theme=light</span></span>
|
||
<span class="line"><span class="string">Set-Cookie</span>: <span class="string">sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT</span></span></span></span></code></pre>
|
||
|
||
<p>Or only one:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/index.html</span></span>
|
||
<span class="line"><span class="string">Host</span>: <span class="string">example.net</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="string">Set-Cookie</span>: <span class="string">theme=light</span></span></span></span></code></pre>
|
||
|
||
<p>If you want to test specifically the number of headers returned for a given header name, or
|
||
if you want to test header value with <a href="#file-format-asserting-response-predicates">predicates</a> (like <code>startsWith</code>, <code>contains</code>, <code>exists</code>)
|
||
you can use the explicit <a href="#file-format-asserting-response-header-assert">header assert</a>.</p>
|
||
|
||
<h3 id="file-format-asserting-response-explicit-asserts"><a href="#file-format-asserting-response-explicit-asserts">Explicit asserts</a></h3>
|
||
|
||
<p>Optional list of assertions on the HTTP response within an <code>[Asserts]</code> section. Assertions can describe checks
|
||
on status code, on the received body (or part of it) and on response headers.</p>
|
||
|
||
<p>Structure of an assert:</p>
|
||
|
||
<div class="schema-container schema-container u-font-size-1 u-font-size-2-sm u-font-size-3-md">
|
||
<div class="schema">
|
||
<span class="schema-token schema-color-2">jsonpath "$.book"<span class="schema-label">query</span></span>
|
||
<span class="schema-token schema-color-1">contains<span class="schema-label">predicate type</span></span>
|
||
<span class="schema-token schema-color-3">"Dune"<span class="schema-label">predicate value</span></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="schema-container schema-container u-font-size-1 u-font-size-2-sm u-font-size-3-md">
|
||
<div class="schema">
|
||
<span class="schema-token schema-color-2">body<span class="schema-label">query</span></span>
|
||
<span class="schema-token schema-color-1">matches<span class="schema-label">predicate type</span></span>
|
||
<span class="schema-token schema-color-3">/\d{4}-\d{2}-\d{2}/<span class="schema-label">predicate value</span></span>
|
||
</div>
|
||
</div>
|
||
|
||
<p>An assert consists of a query followed by a predicate. The format of the query
|
||
is shared with <a href="#file-format-capturing-response-query">captures</a>, and can be one of :</p>
|
||
|
||
<ul>
|
||
<li><a href="#file-format-asserting-response-status-assert"><code>status</code></a></li>
|
||
<li><a href="#file-format-asserting-response-header-assert"><code>header</code></a></li>
|
||
<li><a href="#file-format-asserting-response-url-assert"><code>url</code></a></li>
|
||
<li><a href="#file-format-asserting-response-cookie-assert"><code>cookie</code></a></li>
|
||
<li><a href="#file-format-asserting-response-body-assert"><code>body</code></a></li>
|
||
<li><a href="#file-format-asserting-response-bytes-assert"><code>bytes</code></a></li>
|
||
<li><a href="#file-format-asserting-response-xpath-assert"><code>xpath</code></a></li>
|
||
<li><a href="#file-format-asserting-response-jsonpath-assert"><code>jsonpath</code></a></li>
|
||
<li><a href="#file-format-asserting-response-regex-assert"><code>regex</code></a></li>
|
||
<li><a href="#file-format-asserting-response-sha-256-assert"><code>sha256</code></a></li>
|
||
<li><a href="#file-format-asserting-response-md5-assert"><code>md5</code></a></li>
|
||
<li><a href="#file-format-asserting-response-variable-assert"><code>variable</code></a></li>
|
||
<li><a href="#file-format-asserting-response-duration-assert"><code>duration</code></a></li>
|
||
<li><a href="#file-format-asserting-response-ssl-certificate-assert"><code>certificate</code></a></li>
|
||
</ul>
|
||
|
||
<p>Queries are used to extract data from the HTTP response. Queries, in asserts and in captures, can be refined with <a href="#file-format-filters">filters</a>, like
|
||
[<code>count</code>]<a href="#file-format-filters-count">count</a> to add tests on collections sizes.</p>
|
||
|
||
<h4 id="file-format-asserting-response-predicates"><a href="#file-format-asserting-response-predicates">Predicates</a></h4>
|
||
|
||
<p>Predicates consist of a predicate function and a predicate value. Predicate functions are:</p>
|
||
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Predicate</th>
|
||
<th>Description</th>
|
||
<th>Example</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><strong><code>==</code></strong></td>
|
||
<td>Query and predicate value are equal</td>
|
||
<td><code>jsonpath "$.book" == "Dune"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>!=</code></strong></td>
|
||
<td>Query and predicate value are different</td>
|
||
<td><code>jsonpath "$.color" != "red"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>></code></strong></td>
|
||
<td>Query number is greater than predicate value</td>
|
||
<td><code>jsonpath "$.year" > 1978</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>>=</code></strong></td>
|
||
<td>Query number is greater than or equal to the predicate value</td>
|
||
<td><code>jsonpath "$.year" >= 1978</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code><</code></strong></td>
|
||
<td>Query number is less than that predicate value</td>
|
||
<td><code>jsonpath "$.year" < 1978</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code><=</code></strong></td>
|
||
<td>Query number is less than or equal to the predicate value</td>
|
||
<td><code>jsonpath "$.year" <= 1978</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>startsWith</code></strong></td>
|
||
<td>Query starts with the predicate value<br />Value is string or a binary content</td>
|
||
<td><code>jsonpath "$.movie" startsWith "The"</code><br /><br /><code>bytes startsWith hex,efbbbf;</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>endsWith</code></strong></td>
|
||
<td>Query ends with the predicate value<br />Value is string or a binary content</td>
|
||
<td><code>jsonpath "$.movie" endsWith "Back"</code><br /><br /><code>bytes endsWith hex,ab23456;</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>contains</code></strong></td>
|
||
<td>Query contains the predicate value<br />Value is string or a binary content</td>
|
||
<td><code>jsonpath "$.movie" contains "Empire"</code><br /><br /><code>bytes contains hex,beef;</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>includes</code></strong></td>
|
||
<td>Query collections includes the predicate value</td>
|
||
<td><code>jsonpath "$.nooks" includes "Dune"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>matches</code></strong></td>
|
||
<td>Part of the query string matches the regex pattern described by the predicate value</td>
|
||
<td><code>jsonpath "$.release" matches "\\d{4}"</code><br /><br /><code>jsonpath "$.release" matches /\d{4}/</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>exists</code></strong></td>
|
||
<td>Query returns a value</td>
|
||
<td><code>jsonpath "$.book" exists</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>isBoolean</code></strong></td>
|
||
<td>Query returns a boolean</td>
|
||
<td><code>jsonpath "$.succeeded" isBoolean</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>isCollection</code></strong></td>
|
||
<td>Query returns a collection</td>
|
||
<td><code>jsonpath "$.books" isCollection</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>isEmpty</code></strong></td>
|
||
<td>Query returns an empty collection</td>
|
||
<td><code>jsonpath "$.movies" isEmpty</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>isFloat</code></strong></td>
|
||
<td>Query returns a float</td>
|
||
<td><code>jsonpath "$.height" isFloat</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>isInteger</code></strong></td>
|
||
<td>Query returns an integer</td>
|
||
<td><code>jsonpath "$.count" isInteger</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>isIsoDate</code></strong></td>
|
||
<td>Query string returns a <a href="https://www.rfc-editor.org/rfc/rfc3339">RFC 3339</a> date (<code>YYYY-MM-DDTHH:mm:ss.sssZ</code>)</td>
|
||
<td><code>jsonpath "$.publication_date" isIsoDate</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>isNumber</code></strong></td>
|
||
<td>Query returns an integer or a float</td>
|
||
<td><code>jsonpath "$.count" isNumber</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong><code>isString</code></strong></td>
|
||
<td>Query returns a string</td>
|
||
<td><code>jsonpath "$.name" isString</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p>Each predicate can be negated by prefixing it with <code>not</code> (for instance, <code>not contains</code> or <code>not exists</code>)</p>
|
||
|
||
<div class="schema-container schema-container u-font-size-1 u-font-size-2-sm u-font-size-3-md">
|
||
<div class="schema">
|
||
<span class="schema-token schema-color-2">jsonpath "$.book"<span class="schema-label">query</span></span>
|
||
<span class="schema-token schema-color-1">not contains<span class="schema-label">predicate type</span></span>
|
||
<span class="schema-token schema-color-3">"Dune"<span class="schema-label">predicate value</span></span>
|
||
</div>
|
||
</div>
|
||
|
||
<p>A predicate value is typed, and can be a string, a boolean, a number, a bytestream, <code>null</code> or a collection. Note that
|
||
<code>"true"</code> is a string, whereas <code>true</code> is a boolean.</p>
|
||
|
||
<p>For instance, to test the presence of a h1 node in an HTML response, the following assert can be used:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/home</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"boolean(count(//h1))"</span> <span class="predicate-type">==</span> <span class="boolean">true</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"//h1"</span> <span class="predicate-type">exists</span></span> <span class="comment"># Equivalent but simpler</span></span></span></code></pre>
|
||
|
||
<p>As the XPath query <code>boolean(count(//h1))</code> returns a boolean, the predicate value in the assert must be either
|
||
<code>true</code> or <code>false</code> without double quotes. On the other side, say you have an article node and you want to check the value of some
|
||
<a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes">data attributes</a>:</p>
|
||
|
||
<pre><code class="language-xml"><article
|
||
id="electric-cars"
|
||
data-visible="true"
|
||
...
|
||
</article>
|
||
</code></pre>
|
||
|
||
<p>The following assert will check the value of the <code>data-visible</code> attribute:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/home</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"string(//article/@data-visible)"</span> <span class="predicate-type">==</span> <span class="string">"true"</span></span></span></span></code></pre>
|
||
|
||
<p>In this case, the XPath query <code>string(//article/@data-visible)</code> returns a string, so the predicate value must be a
|
||
string.</p>
|
||
|
||
<p>The predicate function <code>==</code> can be used with string, numbers or booleans; <code>startWith</code> and <code>contains</code> can only
|
||
be used with strings and bytes, while <code>matches</code> only works on string. If a query returns a number, using a <code>matches</code> predicate will cause a runner error.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># A really well tested web page...</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/home</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Content-Type"</span> <span class="predicate-type">contains</span> <span class="string">"text/html"</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Last-Modified"</span> <span class="predicate-type">==</span> <span class="string">"Wed, 21 Oct 2015 07:28:00 GMT"</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"//h1"</span> <span class="predicate-type">exists</span></span> <span class="comment"># Check we've at least one h1</span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"normalize-space(//h1)"</span> <span class="predicate-type">contains</span> <span class="string">"Welcome"</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"//h2"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">13</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"string(//article/@data-id)"</span> <span class="predicate-type">startsWith</span> <span class="string">"electric"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-status-assert"><a href="#file-format-asserting-response-status-assert">Status assert</a></h4>
|
||
|
||
<p>Check the received HTTP response status code. Status assert consists of the keyword <code>status</code> followed by a predicate
|
||
function and value.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">*</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">status</span> <span class="predicate-type"><</span> <span class="number">300</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-header-assert"><a href="#file-format-asserting-response-header-assert">Header assert</a></h4>
|
||
|
||
<p>Check the value of a received HTTP response header. Header assert consists of the keyword <code>header</code> followed by the value
|
||
of the header, a predicate function and a predicate value. Like <a href="#file-format-asserting-response-headers">headers implicit asserts</a>, the check is
|
||
case-insensitive for the name: comparing a <code>Content-Type</code> header is equivalent to a <code>content-type</code> one.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">302</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Location"</span> <span class="predicate-type">contains</span> <span class="string">"www.example.net"</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Last-Modified"</span> <span class="predicate-type">matches</span> <span class="regex">/\d{2} [a-z-A-Z]{3} \d{4}/</span></span></span></span></code></pre>
|
||
|
||
<p>If there are multiple headers with the same name, the header assert returns a collection, so <code>count</code>, <code>includes</code> can be
|
||
used in this case to test the header list.</p>
|
||
|
||
<p>Let’s say we have this request and response:</p>
|
||
|
||
<pre><code>> GET /hello HTTP/1.1
|
||
> Host: example.org
|
||
> Accept: */*
|
||
> User-Agent: hurl/2.0.0-SNAPSHOT
|
||
>
|
||
* Response: (received 12 bytes in 11 ms)
|
||
*
|
||
< HTTP/1.0 200 OK
|
||
< Vary: Content-Type
|
||
< Vary: User-Agent
|
||
< Content-Type: text/html; charset=utf-8
|
||
< Content-Length: 12
|
||
< Server: Flask Server
|
||
< Date: Fri, 07 Oct 2022 20:53:35 GMT
|
||
</code></pre>
|
||
|
||
<p>One can use explicit header asserts:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/hello</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Vary"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">2</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Vary"</span> <span class="predicate-type">includes</span> <span class="string">"User-Agent"</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Vary"</span> <span class="predicate-type">includes</span> <span class="string">"Content-Type"</span></span></span></span></code></pre>
|
||
|
||
<p>Or implicit header asserts:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/hello</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="string">Vary</span>: <span class="string">User-Agent</span></span>
|
||
<span class="line"><span class="string">Vary</span>: <span class="string">Content-Type</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-url-assert"><a href="#file-format-asserting-response-url-assert">URL assert</a></h4>
|
||
|
||
<p>Check the last fetched URL. This is most meaningful if you have told Hurl to follow redirection (see [<code>[Options]</code>section]<a href="#file-format-request-options">options</a> or
|
||
<a href="#getting-started-manual-location"><code>--location</code> option</a>). URL assert consists of the keyword <code>url</code> followed by a predicate function and value.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/redirecting</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">location</span>: <span class="boolean">true</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">url</span> <span class="predicate-type">==</span> <span class="string">"https://example.org/redirected"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-cookie-assert"><a href="#file-format-asserting-response-cookie-assert">Cookie assert</a></h4>
|
||
|
||
<p>Check value or attributes of a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie"><code>Set-Cookie</code></a> response header. Cookie assert
|
||
consists of the keyword <code>cookie</code>, followed by the cookie name (and optionally a
|
||
cookie attribute), a predicate function and value.</p>
|
||
|
||
<p>Cookie attributes value can be checked by using the following format:
|
||
<code><cookie-name>[cookie-attribute]</code>. The following attributes are supported: <code>Value</code>,
|
||
<code>Expires</code>, <code>Max-Age</code>, <code>Domain</code>, <code>Path</code>, <code>Secure</code>, <code>HttpOnly</code> and <code>SameSite</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/cookies/set</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Explicit check of Set-Cookie header value. If the attributes are</span>
|
||
<span class="line"></span><span class="comment"># not in this exact order, this assert will fail. </span>
|
||
<span class="line"><span class="string">Set-Cookie</span>: <span class="string">LSID=DQAAAKEaem_vYg; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly; Path=/accounts; SameSite=Lax;</span></span>
|
||
<span class="line"><span class="string">Set-Cookie</span>: <span class="string">HSID=AYQEVnDKrdst; Domain=localhost; Expires=Wed, 13 Jan 2021 22:23:01 GMT; HttpOnly; Path=/</span></span>
|
||
<span class="line"><span class="string">Set-Cookie</span>: <span class="string">SSID=Ap4PGTEq; Domain=localhost; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly; Path=/</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Using cookie assert, one can check cookie value and various attributes.</span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"LSID"</span> <span class="predicate-type">==</span> <span class="string">"DQAAAKEaem_vYg"</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"LSID[Value]"</span> <span class="predicate-type">==</span> <span class="string">"DQAAAKEaem_vYg"</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"LSID[Expires]"</span> <span class="predicate-type">exists</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"LSID[Expires]"</span> <span class="predicate-type">contains</span> <span class="string">"Wed, 13 Jan 2021"</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"LSID[Max-Age]"</span> <span class="not">not</span> <span class="predicate-type">exists</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"LSID[Domain]"</span> <span class="not">not</span> <span class="predicate-type">exists</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"LSID[Path]"</span> <span class="predicate-type">==</span> <span class="string">"/accounts"</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"LSID[Secure]"</span> <span class="predicate-type">exists</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"LSID[HttpOnly]"</span> <span class="predicate-type">exists</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"LSID[SameSite]"</span> <span class="predicate-type">==</span> <span class="string">"Lax"</span></span></span></span></code></pre>
|
||
|
||
<blockquote>
|
||
<p><code>Secure</code> and <code>HttpOnly</code> attributes can only be tested with <code>exists</code> or <code>not exists</code> predicates
|
||
to reflect the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie header</a> semantics (in other words, queries <code><cookie-name>[HttpOnly]</code>
|
||
and <code><cookie-name>[Secure]</code> don’t return boolean).</p>
|
||
</blockquote>
|
||
|
||
<h4 id="file-format-asserting-response-body-assert"><a href="#file-format-asserting-response-body-assert">Body assert</a></h4>
|
||
|
||
<p>Check the value of the received HTTP response body when decoded as a string.
|
||
Body assert consists of the keyword <code>body</code> followed by a predicate function and
|
||
value. The encoding used to decode the body is based on the <code>charset</code> value in the
|
||
<code>Content-Type</code> header response.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">body</span> <span class="predicate-type">contains</span> <span class="string">"<h1>Welcome!</h1>"</span></span></span></span></code></pre>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Our HTML response is encoded with GB 2312 (see https://en.wikipedia.org/wiki/GB_2312)</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/cn</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Content-Type"</span> <span class="predicate-type">==</span> <span class="string">"text/html; charset=gb2312"</span></span>
|
||
<span class="line"><span class="query-type">bytes</span> <span class="predicate-type">contains</span> hex,<span class="hex">c4e3bac3cac0bde7</span>;</span> <span class="comment"># 你好世界 encoded in GB 2312</span>
|
||
<span class="line"><span class="query-type">body</span> <span class="predicate-type">contains</span> <span class="string">"你好世界"</span></span></span></span></code></pre>
|
||
|
||
<p>If the <code>Content-Type</code> doesn’t include any encoding hint, a <a href="#file-format-filters-decode"><code>decode</code> filter</a> can be used to explicitly decode the body response
|
||
bytes.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Our HTML response is encoded using GB 2312.</span>
|
||
<span class="line"></span><span class="comment"># But, the 'Content-Type' HTTP response header doesn't precise any charset,</span>
|
||
<span class="line"></span><span class="comment"># so we decode explicitly the bytes.</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/cn</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Content-Type"</span> <span class="predicate-type">==</span> <span class="string">"text/html"</span></span>
|
||
<span class="line"><span class="query-type">bytes</span> <span class="predicate-type">contains</span> hex,<span class="hex">c4e3bac3cac0bde7</span>;</span> <span class="comment"># 你好世界 encoded in GB2312</span>
|
||
<span class="line"><span class="query-type">bytes</span> <span class="filter-type">decode</span> <span class="string">"gb2312"</span> <span class="predicate-type">contains</span> <span class="string">"你好世界"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-bytes-assert"><a href="#file-format-asserting-response-bytes-assert">Bytes assert</a></h4>
|
||
|
||
<p>Check the value of the received HTTP response body as a bytestream. Body assert
|
||
consists of the keyword <code>bytes</code> followed by a predicate function and value.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/data.bin</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">bytes</span> <span class="predicate-type">startsWith</span> hex,<span class="hex">efbbbf</span>;</span>
|
||
<span class="line"><span class="query-type">bytes</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">12424</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Content-Length"</span> <span class="predicate-type">==</span> <span class="string">"12424"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-xpath-assert"><a href="#file-format-asserting-response-xpath-assert">XPath assert</a></h4>
|
||
|
||
<p>Check the value of a <a href="https://en.wikipedia.org/wiki/XPath">XPath</a> query on the received HTTP body decoded as a string (using the <code>charset</code> value in the
|
||
<code>Content-Type</code> header response). Currently, only XPath 1.0 expression can be used. Body assert consists of the
|
||
keyword <code>xpath</code> followed by a predicate function and value. Values can be string,
|
||
boolean or number depending on the XPath query.</p>
|
||
|
||
<p>Let’s say we want to check this HTML response:</p>
|
||
|
||
<pre><code class="language-plain">$ curl -v https://example.org
|
||
|
||
< HTTP/1.1 200 OK
|
||
< Content-Type: text/html; charset=UTF-8
|
||
...
|
||
<!doctype html>
|
||
<html>
|
||
<head>
|
||
<title>Example Domain</title>
|
||
...
|
||
</head>
|
||
|
||
<body>
|
||
<div>
|
||
<h1>Example</h1>
|
||
<p>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</p>
|
||
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
</code></pre>
|
||
|
||
<p>With Hurl, we can write multiple XPath asserts describing the DOM content:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">text/html; charset=UTF-8</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"string(/html/head/title)"</span> <span class="predicate-type">contains</span> <span class="string">"Example"</span></span> <span class="comment"># Check title</span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"count(//p)"</span> <span class="predicate-type">==</span> <span class="number">2</span></span> <span class="comment"># Check the number of <p></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"//p"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">2</span></span> <span class="comment"># Similar assert for <p></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"boolean(count(//h2))"</span> <span class="predicate-type">==</span> <span class="boolean">false</span></span> <span class="comment"># Check there is no <h2> </span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"//h2"</span> <span class="not">not</span> <span class="predicate-type">exists</span></span> <span class="comment"># Similar assert for <h2></span></span></span></code></pre>
|
||
|
||
<p>XML Namespaces are also supported. Let’s say you want to check this XML response:</p>
|
||
|
||
<pre><code class="language-xml"><?xml version="1.0"?>
|
||
<!-- both namespace prefixes are available throughout -->
|
||
<bk:book xmlns:bk='urn:loc.gov:books'
|
||
xmlns:isbn='urn:ISBN:0-395-36341-6'>
|
||
<bk:title>Cheaper by the Dozen</bk:title>
|
||
<isbn:number>1568491379</isbn:number>
|
||
</bk:book>
|
||
</code></pre>
|
||
|
||
<p>This XML response can be tested with the following Hurl file:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/assert-xpath</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"string(//bk:book/bk:title)"</span> <span class="predicate-type">==</span> <span class="string">"Cheaper by the Dozen"</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"string(//*[name()='bk:book']/*[name()='bk:title'])"</span> <span class="predicate-type">==</span> <span class="string">"Cheaper by the Dozen"</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"string(//*[local-name()='book']/*[local-name()='title'])"</span> <span class="predicate-type">==</span> <span class="string">"Cheaper by the Dozen"</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"string(//bk:book/isbn:number)"</span> <span class="predicate-type">==</span> <span class="string">"1568491379"</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"string(//*[name()='bk:book']/*[name()='isbn:number'])"</span> <span class="predicate-type">==</span> <span class="string">"1568491379"</span></span>
|
||
<span class="line"><span class="query-type">xpath</span> <span class="string">"string(//*[local-name()='book']/*[local-name()='number'])"</span> <span class="predicate-type">==</span> <span class="string">"1568491379"</span></span></span></span></code></pre>
|
||
|
||
<p>The XPath expressions <code>string(//bk:book/bk:title)</code> and <code>string(//bk:book/isbn:number)</code> are written with <code>bk</code> and <code>isbn</code>
|
||
namespaces.</p>
|
||
|
||
<blockquote>
|
||
<p>For convenience, the first default namespace can be used with <code>_</code></p>
|
||
</blockquote>
|
||
|
||
<h4 id="file-format-asserting-response-jsonpath-assert"><a href="#file-format-asserting-response-jsonpath-assert">JSONPath assert</a></h4>
|
||
|
||
<p>Check the value of a <a href="https://goessner.net/articles/JsonPath/">JSONPath</a> query on the received HTTP body decoded as a JSON
|
||
document. JSONPath assert consists of the keyword <code>jsonpath</code> followed by a predicate
|
||
function and value.</p>
|
||
|
||
<p>Let’s say we want to check this JSON response:</p>
|
||
|
||
<pre><code class="language-plain">curl -v http://httpbin.org/json
|
||
|
||
< HTTP/1.1 200 OK
|
||
< Content-Type: application/json
|
||
...
|
||
|
||
{
|
||
"slideshow": {
|
||
"author": "Yours Truly",
|
||
"date": "date of publication",
|
||
"slides": [
|
||
{
|
||
"title": "Wake up to WonderWidgets!",
|
||
"type": "all"
|
||
},
|
||
...
|
||
],
|
||
"title": "Sample Slide Show"
|
||
}
|
||
}
|
||
</code></pre>
|
||
|
||
<p>With Hurl, we can write multiple JSONPath asserts describing the DOM content:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://httpbin.org/json</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.slideshow.author"</span> <span class="predicate-type">==</span> <span class="string">"Yours Truly"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.slideshow.slides[0].title"</span> <span class="predicate-type">contains</span> <span class="string">"Wonder"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.slideshow.slides"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">2</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.slideshow.date"</span> <span class="predicate-type">!=</span> <span class="null">null</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.slideshow.slides[*].title"</span> <span class="predicate-type">includes</span> <span class="string">"Mind Blowing!"</span></span></span></span></code></pre>
|
||
|
||
<blockquote>
|
||
<p>Explain that the value selected by the JSONPath is coerced to a string when only
|
||
one node is selected.</p>
|
||
</blockquote>
|
||
|
||
<p>In <code>matches</code> predicates, metacharacters beginning with a backslash (like <code>\d</code>, <code>\s</code>) must be escaped.
|
||
Alternatively, <code>matches</code> predicate support <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">JavaScript-like Regular expression syntax</a> to enhance
|
||
the readability:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/hello</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Predicate value with matches predicate:</span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.date"</span> <span class="predicate-type">matches</span> <span class="string">"^\\d{4}-\\d{2}-\\d{2}$"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.name"</span> <span class="predicate-type">matches</span> <span class="string">"Hello [a-zA-Z]+!"</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Equivalent syntax:</span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.date"</span> <span class="predicate-type">matches</span> <span class="regex">/^\d{4}-\d{2}-\d{2}$/</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.name"</span> <span class="predicate-type">matches</span> <span class="regex">/Hello [a-zA-Z]+!/</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-regex-assert"><a href="#file-format-asserting-response-regex-assert">Regex assert</a></h4>
|
||
|
||
<p>Check that the HTTP received body, decoded as text, matches a regex pattern.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/hello</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">regex</span> <span class="string">"^(\\d{4}-\\d{2}-\\d{2})$"</span> <span class="predicate-type">==</span> <span class="string">"2018-12-31"</span></span>
|
||
<span class="line"></span><span class="comment"># Same assert as previous using regex literals</span>
|
||
<span class="line"><span class="query-type">regex</span> <span class="regex">/^(\d{4}-\d{2}-\d{2})$/</span> <span class="predicate-type">==</span> <span class="string">"2018-12-31"</span></span></span></span></code></pre>
|
||
|
||
<p>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 <code>\d</code>, <code>\s</code>) must be escaped; literal pattern enclosed by
|
||
<code>/</code> can also be used to avoid metacharacters escaping.</p>
|
||
|
||
<h4 id="file-format-asserting-response-sha-256-assert"><a href="#file-format-asserting-response-sha-256-assert">SHA-256 assert</a></h4>
|
||
|
||
<p>Check response body <a href="https://en.wikipedia.org/wiki/SHA-2">SHA-256</a> hash.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/data.tar.gz</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">sha256</span> <span class="predicate-type">==</span> hex,<span class="hex">039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81</span>;</span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-md5-assert"><a href="#file-format-asserting-response-md5-assert">MD5 assert</a></h4>
|
||
|
||
<p>Check response body <a href="https://en.wikipedia.org/wiki/MD5">MD5</a> hash.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/data.tar.gz</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">md5</span> <span class="predicate-type">==</span> hex,<span class="hex">ed076287532e86365e841e92bfc50d8c</span>;</span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-variable-assert"><a href="#file-format-asserting-response-variable-assert">Variable assert</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Test that the XML endpoint return 200 pets </span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/pets</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">pets</span>: <span class="query-type">xpath</span> <span class="string">"//pets"</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">variable</span> <span class="string">"pets"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-duration-assert"><a href="#file-format-asserting-response-duration-assert">Duration assert</a></h4>
|
||
|
||
<p>Check the total duration (sending plus receiving time) of the HTTP transaction.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/helloworld</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">duration</span> <span class="predicate-type"><</span> <span class="number">1000</span></span> <span class="comment"># Check that response time is less than one second</span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-ssl-certificate-assert"><a href="#file-format-asserting-response-ssl-certificate-assert">SSL certificate assert</a></h4>
|
||
|
||
<p>Check the SSL certificate properties. Certificate assert consists of the keyword <code>certificate</code>, followed by the certificate attribute value.</p>
|
||
|
||
<p>The following attributes are supported: <code>Subject</code>, <code>Issuer</code>, <code>Start-Date</code>, <code>Expire-Date</code> and <code>Serial-Number</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">certificate</span> <span class="string">"Subject"</span> <span class="predicate-type">==</span> <span class="string">"CN=example.org"</span></span>
|
||
<span class="line"><span class="query-type">certificate</span> <span class="string">"Issuer"</span> <span class="predicate-type">==</span> <span class="string">"C=US, O=Let's Encrypt, CN=R3"</span></span>
|
||
<span class="line"><span class="query-type">certificate</span> <span class="string">"Expire-Date"</span> <span class="filter-type">daysAfterNow</span> <span class="predicate-type">></span> <span class="number">15</span></span>
|
||
<span class="line"><span class="query-type">certificate</span> <span class="string">"Serial-Number"</span> <span class="predicate-type">matches</span> <span class="string">"[0-9af]+"</span></span></span></span></code></pre>
|
||
|
||
<h3 id="file-format-asserting-response-body"><a href="#file-format-asserting-response-body">Body</a></h3>
|
||
|
||
<p>Optional assertion on the received HTTP response body. Body section can be seen
|
||
as syntactic sugar over <a href="#file-format-asserting-response-body-assert">body asserts</a> (with <code>==</code> predicate). If the
|
||
body of the response is a <a href="https://www.json.org">JSON</a> string or a <a href="https://en.wikipedia.org/wiki/XML">XML</a> string, the body assertion can
|
||
be directly inserted without any modification. For a text based body that is neither JSON nor XML,
|
||
one can use multiline string that starts with <code>```</code> and ends
|
||
with <code>```</code>. For a precise byte control of the response body,
|
||
a <a href="https://en.wikipedia.org/wiki/Base64">Base64</a> encoded string or an input file can be used to describe exactly
|
||
the body byte content to check.</p>
|
||
|
||
<h4 id="file-format-asserting-response-json-body"><a href="#file-format-asserting-response-json-body">JSON body</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Get a doggy thing:</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/dogs/{{dog-id}}</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="json"><span class="line">{</span>
|
||
<span class="line"> "id": 0,</span>
|
||
<span class="line"> "name": "Frieda",</span>
|
||
<span class="line"> "picture": "images/scottish-terrier.jpeg",</span>
|
||
<span class="line"> "age": 3,</span>
|
||
<span class="line"> "breed": "Scottish Terrier",</span>
|
||
<span class="line"> "location": "Lisco, Alabama"</span>
|
||
<span class="line">}</span></span></span></span></code></pre>
|
||
|
||
<p>JSON response body can be seen as syntactic sugar of <a href="#file-format-asserting-response-multiline-string-body">multiline string body</a> with <code>json</code> identifier:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># Get a doggy thing:</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/dogs/{{dog-id}}</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="multiline"><span class="line">```json</span>
|
||
<span class="line">{</span>
|
||
<span class="line"> "id": 0,</span>
|
||
<span class="line"> "name": "Frieda",</span>
|
||
<span class="line"> "picture": "images/scottish-terrier.jpeg",</span>
|
||
<span class="line"> "age": 3,</span>
|
||
<span class="line"> "breed": "Scottish Terrier",</span>
|
||
<span class="line"> "location": "Lisco, Alabama"</span>
|
||
<span class="line">}</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-xml-body"><a href="#file-format-asserting-response-xml-body">XML body</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/catalog</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="xml"><span class="line"><?xml version="1.0" encoding="UTF-8"?></span>
|
||
<span class="line"><catalog></span>
|
||
<span class="line"> <book id="bk101"></span>
|
||
<span class="line"> <author>Gambardella, Matthew</author></span>
|
||
<span class="line"> <title>XML Developer's Guide</title></span>
|
||
<span class="line"> <genre>Computer</genre></span>
|
||
<span class="line"> <price>44.95</price></span>
|
||
<span class="line"> <publish_date>2000-10-01</publish_date></span>
|
||
<span class="line"> <description>An in-depth look at creating applications with XML.</description></span>
|
||
<span class="line"> </book></span>
|
||
<span class="line"></catalog></span></span></span></span></code></pre>
|
||
|
||
<p>XML response body can be seen as syntactic sugar of <a href="#file-format-asserting-response-multiline-string-body">multiline string body</a> with <code>xml</code> identifier:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/catalog</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="multiline"><span class="line">```xml</span>
|
||
<span class="line"><?xml version="1.0" encoding="UTF-8"?></span>
|
||
<span class="line"><catalog></span>
|
||
<span class="line"> <book id="bk101"></span>
|
||
<span class="line"> <author>Gambardella, Matthew</author></span>
|
||
<span class="line"> <title>XML Developer's Guide</title></span>
|
||
<span class="line"> <genre>Computer</genre></span>
|
||
<span class="line"> <price>44.95</price></span>
|
||
<span class="line"> <publish_date>2000-10-01</publish_date></span>
|
||
<span class="line"> <description>An in-depth look at creating applications with XML.</description></span>
|
||
<span class="line"> </book></span>
|
||
<span class="line"></catalog></span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-multiline-string-body"><a href="#file-format-asserting-response-multiline-string-body">Multiline string body</a></h4>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/models</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="multiline"><span class="line">```</span>
|
||
<span class="line">Year,Make,Model,Description,Price</span>
|
||
<span class="line">1997,Ford,E350,"ac, abs, moon",3000.00</span>
|
||
<span class="line">1999,Chevy,"Venture ""Extended Edition""","",4900.00</span>
|
||
<span class="line">1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00</span>
|
||
<span class="line">1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<p>The standard usage of a multiline string is :</p>
|
||
|
||
<pre><code>```
|
||
line1
|
||
line2
|
||
line3
|
||
```
|
||
</code></pre>
|
||
|
||
<h5 id="file-format-asserting-response-oneline-string-body"><a href="#file-format-asserting-response-oneline-string-body">Oneline string body</a></h5>
|
||
|
||
<p>For text based response body that do not contain newlines, one can use oneline string, started and ending with <code>`</code>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/helloworld</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="string">`Hello world!`</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-base64-body"><a href="#file-format-asserting-response-base64-body">Base64 body</a></h4>
|
||
|
||
<p>Base64 response body assert starts with <code>base64,</code> and end with <code>;</code>. MIME’s Base64 encoding
|
||
is supported (newlines and white spaces may be present anywhere but are to be
|
||
ignored on decoding), and <code>=</code> padding characters might be added.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line">base64,<span class="base64">TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIG
|
||
FkaXBpc2NpbmcgZWxpdC4gSW4gbWFsZXN1YWRhLCBuaXNsIHZlbCBkaWN0dW0g
|
||
aGVuZHJlcml0LCBlc3QganVzdG8gYmliZW5kdW0gbWV0dXMsIG5lYyBydXRydW
|
||
0gdG9ydG9yIG1hc3NhIGlkIG1ldHVzLiA=</span>;</span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-asserting-response-file-body"><a href="#file-format-asserting-response-file-body">File body</a></h4>
|
||
|
||
<p>To use the binary content of a local file as the body response assert, file body
|
||
can be used. File body starts with <code>file,</code> and ends with <code>;</code>`</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line">file,<span class="filename">data.bin</span>;</span></span></span></code></pre>
|
||
|
||
<p>File are relative to the input Hurl file, and cannot contain implicit parent
|
||
directory (<code>..</code>). You can use <a href="#getting-started-manual-file-root"><code>--file-root</code> option</a> to specify the root directory
|
||
of all file nodes.</p>
|
||
|
||
<hr />
|
||
|
||
<h2 id="file-format-filters-filters"><a href="#file-format-filters-filters">Filters</a></h2>
|
||
|
||
<h3 id="file-format-filters-definition"><a href="#file-format-filters-definition">Definition</a></h3>
|
||
|
||
<p><a href="#file-format-capturing-response">Captures</a> and <a href="#file-format-asserting-response">asserts</a> share a common structure: query. A query is used to extract data from an HTTP response; this data
|
||
can come from the HTTP response body, the HTTP response headers or from the HTTP meta-information (like <code>duration</code> for instance)...</p>
|
||
|
||
<p>In this example, the query <strong><code>jsonpath "$.books[0].name"</code></strong> is used in a capture to save data and in an assert to test
|
||
the HTTP response body.</p>
|
||
|
||
<p><strong>Capture</strong>:</p>
|
||
|
||
<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>
|
||
|
||
<p><strong>Assert</strong>:</p>
|
||
|
||
<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>
|
||
|
||
<p>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 <strong>filters</strong>.</p>
|
||
|
||
<p>Filters are used to transform value extracted by a query and can be used in asserts and captures to refine data. Filters
|
||
<strong>can be chained</strong>, allowing for fine-grained data extraction.</p>
|
||
|
||
<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>
|
||
|
||
<h3 id="file-format-filters-example"><a href="#file-format-filters-example">Example</a></h3>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">name</span>: <span class="query-type">jsonpath</span> <span class="string">"$user.id"</span> <span class="filter-type">replace</span> <span class="regex">/\d/</span> <span class="string">"x"</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"x-servers"</span> <span class="filter-type">split</span> <span class="string">","</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">2</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"x-servers"</span> <span class="filter-type">split</span> <span class="string">","</span> <span class="filter-type">nth</span> <span class="number">0</span> <span class="predicate-type">==</span> <span class="string">"rec1"</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"x-servers"</span> <span class="filter-type">split</span> <span class="string">","</span> <span class="filter-type">nth</span> <span class="number">1</span> <span class="predicate-type">==</span> <span class="string">"rec3"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.books"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">12</span></span></span></span></code></pre>
|
||
|
||
<h3 id="file-format-filters-description"><a href="#file-format-filters-description">Description</a></h3>
|
||
|
||
<h4 id="file-format-filters-count"><a href="#file-format-filters-count">count</a></h4>
|
||
|
||
<p>Counts the number of items in a collection.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.books"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">12</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-daysafternow"><a href="#file-format-filters-daysafternow">daysAfterNow</a></h4>
|
||
|
||
<p>Returns the number of days between now and a date in the future.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">certificate</span> <span class="string">"Expire-Date"</span> <span class="filter-type">daysAfterNow</span> <span class="predicate-type">></span> <span class="number">15</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-daysbeforenow"><a href="#file-format-filters-daysbeforenow">daysBeforeNow</a></h4>
|
||
|
||
<p>Returns the number of days between now and a date in the past.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">certificate</span> <span class="string">"Start-Date"</span> <span class="filter-type">daysBeforeNow</span> <span class="predicate-type"><</span> <span class="number">100</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-decode"><a href="#file-format-filters-decode">decode</a></h4>
|
||
|
||
<p>Decode bytes to string using encoding.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"></span><span class="comment"># The 'Content-Type' HTTP response header does not precise the charset 'gb2312'</span>
|
||
<span class="line"></span><span class="comment"># so body must be decoded explicitly by Hurl before processing any text based assert</span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/hello_china</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Content-Type"</span> <span class="predicate-type">==</span> <span class="string">"text/html"</span></span>
|
||
<span class="line"></span><span class="comment"># Content-Type has no encoding clue, we must decode ourselves the body response.</span>
|
||
<span class="line"><span class="query-type">bytes</span> <span class="filter-type">decode</span> <span class="string">"gb2312"</span> <span class="filter-type">xpath</span> <span class="string">"string(//body)"</span> <span class="predicate-type">==</span> <span class="string">"你好世界"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-format"><a href="#file-format-filters-format">format</a></h4>
|
||
|
||
<p>Formats a date to a string given <a href="https://docs.rs/chrono/latest/chrono/format/strftime/index.html">a specification format</a>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">cookie</span> <span class="string">"LSID[Expires]"</span> <span class="filter-type">format</span> <span class="string">"%a, %d %b %Y %H:%M:%S"</span> <span class="predicate-type">==</span> <span class="string">"Wed, 13 Jan 2021 22:23:01"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-htmlescape"><a href="#file-format-filters-htmlescape">htmlEscape</a></h4>
|
||
|
||
<p>Converts the characters <code>&</code>, <code><</code> and <code>></code> to HTML-safe sequence.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.text"</span> <span class="filter-type">htmlEscape</span> <span class="predicate-type">==</span> <span class="string">"a &gt; b"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-htmlunescape"><a href="#file-format-filters-htmlunescape">htmlUnescape</a></h4>
|
||
|
||
<p>Converts all named and numeric character references (e.g. <code>&gt;</code>, <code>&#62;</code>, <code>&#x3e;</code>) to the corresponding Unicode characters.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.escaped_html[1]"</span> <span class="filter-type">htmlUnescape</span> <span class="predicate-type">==</span> <span class="string">"Foo © bar 𝌆"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-jsonpath"><a href="#file-format-filters-jsonpath">jsonpath</a></h4>
|
||
|
||
<p>Evaluates a <a href="https://goessner.net/articles/JsonPath/">JSONPath</a> expression.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">books</span>: <span class="query-type">xpath</span> <span class="string">"string(//body/@data-books)"</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">variable</span> <span class="string">"books"</span> <span class="filter-type">jsonpath</span> <span class="string">"$[0].name"</span> <span class="predicate-type">==</span> <span class="string">"Dune"</span></span>
|
||
<span class="line"><span class="query-type">variable</span> <span class="string">"books"</span> <span class="filter-type">jsonpath</span> <span class="string">"$[0].author"</span> <span class="predicate-type">==</span> <span class="string">"Franck Herbert"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-nth"><a href="#file-format-filters-nth">nth</a></h4>
|
||
|
||
<p>Returns the element from a collection at a zero-based index.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.books"</span> <span class="filter-type">nth</span> <span class="number">2</span> <span class="predicate-type">==</span> <span class="string">"Children of Dune"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-regex"><a href="#file-format-filters-regex">regex</a></h4>
|
||
|
||
<p>Extracts regex capture group. Pattern must have at least one capture group.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/foo</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">param1</span>: <span class="query-type">header</span> <span class="string">"header1"</span></span>
|
||
<span class="line"><span class="string">param2</span>: <span class="query-type">header</span> <span class="string">"header2"</span> <span class="filter-type">regex</span> <span class="string">"Hello (.*)!"</span></span>
|
||
<span class="line"><span class="string">param3</span>: <span class="query-type">header</span> <span class="string">"header2"</span> <span class="filter-type">regex</span> <span class="regex">/Hello (.*)!/</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-replace"><a href="#file-format-filters-replace">replace</a></h4>
|
||
|
||
<p>Replaces all occurrences of old string with new string.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/foo</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">url</span>: <span class="query-type">jsonpath</span> <span class="string">"$.url"</span> <span class="filter-type">replace</span> <span class="string">"http://"</span> <span class="string">"https://"</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.ips"</span> <span class="filter-type">replace</span> <span class="string">", "</span> <span class="string">"|"</span> <span class="predicate-type">==</span> <span class="string">"192.168.2.1|10.0.0.20|10.0.0.10"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-split"><a href="#file-format-filters-split">split</a></h4>
|
||
|
||
<p>Splits to a list of strings around occurrences of the specified delimiter.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/foo</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.ips"</span> <span class="filter-type">split</span> <span class="string">", "</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">3</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-todate"><a href="#file-format-filters-todate">toDate</a></h4>
|
||
|
||
<p>Converts a string to a date given <a href="https://docs.rs/chrono/latest/chrono/format/strftime/index.html">a specification format</a>.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https:///example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">header</span> <span class="string">"Expires"</span> <span class="filter-type">toDate</span> <span class="string">"%a, %d %b %Y %H:%M:%S GMT"</span> <span class="filter-type">daysBeforeNow</span> <span class="predicate-type">></span> <span class="number">1000</span></span></span></span></code></pre>
|
||
|
||
<p>ISO 8601 / RFC 3339 date and time format have shorthand format <code>%+</code>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/books</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.published"</span> <span class="predicate-type">==</span> <span class="string">"2023-01-23T18:25:43.511Z"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.published"</span> <span class="filter-type">toDate</span> <span class="string">"%Y-%m-%dT%H:%M:%S%.fZ"</span> <span class="filter-type">format</span> <span class="string">"%A"</span> <span class="predicate-type">==</span> <span class="string">"Monday"</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.published"</span> <span class="filter-type">toDate</span> <span class="string">"%+"</span> <span class="filter-type">format</span> <span class="string">"%A"</span> <span class="predicate-type">==</span> <span class="string">"Monday"</span></span> <span class="comment"># %+ can be used to parse ISO 8601 / RFC 3339</span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-tofloat"><a href="#file-format-filters-tofloat">toFloat</a></h4>
|
||
|
||
<p>Converts to float number.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/foo</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.pi"</span> <span class="filter-type">toFloat</span> <span class="predicate-type">==</span> <span class="number">3.14</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-toint"><a href="#file-format-filters-toint">toInt</a></h4>
|
||
|
||
<p>Converts to integer number.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/foo</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.id"</span> <span class="filter-type">toInt</span> <span class="predicate-type">==</span> <span class="number">123</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-urldecode"><a href="#file-format-filters-urldecode">urlDecode</a></h4>
|
||
|
||
<p>Replaces %xx escapes with their single-character equivalent.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/foo</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.encoded_url"</span> <span class="filter-type">urlDecode</span> <span class="predicate-type">==</span> <span class="string">"https://mozilla.org/?x=шеллы"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-urlencode"><a href="#file-format-filters-urlencode">urlEncode</a></h4>
|
||
|
||
<p>Percent-encodes all the characters which are not included in unreserved chars (see <a href="https://www.rfc-editor.org/rfc/rfc3986">RFC3986</a>) with the exception of forward slash (/).</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/foo</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.url"</span> <span class="filter-type">urlEncode</span> <span class="predicate-type">==</span> <span class="string">"https%3A//mozilla.org/%3Fx%3D%D1%88%D0%B5%D0%BB%D0%BB%D1%8B"</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-filters-xpath"><a href="#file-format-filters-xpath">xpath</a></h4>
|
||
|
||
<p>Evaluates a <a href="https://en.wikipedia.org/wiki/XPath">XPath</a> expression.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/hello_gb2312</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">bytes</span> <span class="filter-type">decode</span> <span class="string">"gb2312"</span> <span class="filter-type">xpath</span> <span class="string">"string(//body)"</span> <span class="predicate-type">==</span> <span class="string">"你好世界"</span></span></span></span></code></pre>
|
||
|
||
<hr />
|
||
|
||
<h2 id="file-format-templates-templates"><a href="#file-format-templates-templates">Templates</a></h2>
|
||
|
||
<h3 id="file-format-templates-variables"><a href="#file-format-templates-variables">Variables</a></h3>
|
||
|
||
<p>In Hurl file, you can generate value using two curly braces, i.e <code>{{my_variable}}</code>. For instance, if you want to reuse a
|
||
value from an HTTP response in the next entries, you can capture this value in a variable and reuse it in a placeholder.</p>
|
||
|
||
<p>In this example, we capture the value of a <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF token</a> from the body of the first response, and inject it
|
||
as a header in the next POST request:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">csrf_token</span>: <span class="query-type">xpath</span> <span class="string">"string(//meta[@name='_csrf_token']/@content)"</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"></span><span class="comment"># Do the login !</span>
|
||
<span class="line"><span class="method">POST</span> <span class="url">https://acmecorp.net/login?user=toto&password=1234</span></span>
|
||
<span class="line"><span class="string">X-CSRF-TOKEN</span>: <span class="string">{{csrf_token}}</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">302</span></span></span></span></code></pre>
|
||
|
||
<p>In this second example, we capture the body in a variable <code>index</code>, and reuse this value in the query
|
||
<code>jsonpath "$.errors[{{index}}].id"</code>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/index</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">index</span>: <span class="query-type">body</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/status</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.errors[{{index}}].id"</span> <span class="predicate-type">==</span> <span class="string">"error"</span></span></span></span></code></pre>
|
||
|
||
<h3 id="file-format-templates-functions"><a href="#file-format-templates-functions">Functions</a></h3>
|
||
|
||
<p>Besides variables, functions can be used to generate dynamic values. Current functions are:</p>
|
||
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Function</th>
|
||
<th>Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>newUuid</code></td>
|
||
<td>Generates an <a href="https://en.wikipedia.org/wiki/Universally_unique_identifier">UUID v4 random string</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>newDate</code></td>
|
||
<td>Generates a <a href="https://www.rfc-editor.org/rfc/rfc3339">RFC 3339</a> UTC date string, at the current time</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p>In the following example, we use <code>newDate</code> to generate a dynamic query parameter:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://example.org/api/foo</span></span>
|
||
<span class="line"><span class="section-header">[QueryStringParams]</span></span>
|
||
<span class="line"><span class="string">date</span>: <span class="string">{{newDate}}</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<p>We run a <code>GET</code> request to <code>https://example.org/api/foo?date=2024%2D12%2D02T10%3A35%3A44%2E461731Z</code> where the <code>date</code>
|
||
query parameter value is <code>2024-12-02T10:35:44.461731Z</code> URL encoded.</p>
|
||
|
||
<p>In this second example, we use <code>newUuid</code> function to generate an email dynamically:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">POST</span> <span class="url">https://example.org/api/foo</span></span>
|
||
<span class="json"><span class="line">{</span>
|
||
<span class="line"> "name": "foo",</span>
|
||
<span class="line"> "email": "{{newUuid}}@test.com"</span>
|
||
<span class="line">}</span></span></span></span></code></pre>
|
||
|
||
<p>When run, the request body will be:</p>
|
||
|
||
<pre><code>{
|
||
"name": "foo",
|
||
"email": "0531f78f-7f87-44be-a7f2-969a1c4e6d97@test.com"
|
||
}
|
||
</code></pre>
|
||
|
||
<h3 id="file-format-templates-types"><a href="#file-format-templates-types">Types</a></h3>
|
||
|
||
<p>Values generated from function and variables are typed, and can be either string, bool, number, <code>null</code> or collections. Depending on the value type,
|
||
templates can be rendered differently. Let’s say we have captured an integer value into a variable named
|
||
<code>count</code>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://sample/counter</span></span>
|
||
</span><span class="response"><span class="line"></span>
|
||
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Captures]</span></span>
|
||
<span class="line"><span class="string">count</span>: <span class="query-type">jsonpath</span> <span class="string">"$.results[0]"</span></span></span></span></code></pre>
|
||
|
||
<p>The following entry:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://sample/counter/{{count}}</span></span>
|
||
</span><span class="response"><span class="line"></span>
|
||
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.id"</span> <span class="predicate-type">==</span> <span class="string">"{{count}}"</span></span></span></span></code></pre>
|
||
|
||
<p>will be rendered at runtime to:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://sample/counter/458</span></span>
|
||
</span><span class="response"><span class="line"></span>
|
||
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.id"</span> <span class="predicate-type">==</span> <span class="string">"458"</span></span></span></span></code></pre>
|
||
|
||
<p>resulting in a comparison between the <a href="#file-format-asserting-response-jsonpath-assert">JSONPath</a> expression and a string value.</p>
|
||
|
||
<p>On the other hand, the following assert:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://sample/counter/{{count}}</span></span>
|
||
</span><span class="response"><span class="line"></span>
|
||
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.index"</span> <span class="predicate-type">==</span> <span class="expr">{{count}}</span></span></span></span></code></pre>
|
||
|
||
<p>will be rendered at runtime to:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://sample/counter/458</span></span>
|
||
</span><span class="response"><span class="line"></span>
|
||
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||
<span class="line"><span class="section-header">[Asserts]</span></span>
|
||
<span class="line"><span class="query-type">jsonpath</span> <span class="string">"$.index"</span> <span class="predicate-type">==</span> <span class="number">458</span></span></span></span></code></pre>
|
||
|
||
<p>resulting in a comparison between the <a href="#file-format-asserting-response-jsonpath-assert">JSONPath</a> expression and an integer value.</p>
|
||
|
||
<p>So if you want to use typed values (in asserts for instances), you can use <code>{{my_var}}</code>.
|
||
If you’re interested in the string representation of a variable, you can surround the variable with double quotes
|
||
, as in <code>"{{my_var}}"</code>.</p>
|
||
|
||
<blockquote>
|
||
<p>When there is no possible ambiguities, like using a variable in an URL, or
|
||
in a header, you can omit the double quotes. The value will always be rendered
|
||
as a string.</p>
|
||
</blockquote>
|
||
|
||
<h3 id="file-format-templates-injecting-variables"><a href="#file-format-templates-injecting-variables">Injecting Variables</a></h3>
|
||
|
||
<p>Variables can be injected in a Hurl file:</p>
|
||
|
||
<ul>
|
||
<li>by using <a href="#getting-started-manual-variable"><code>--variable</code> option</a></li>
|
||
<li>by using <a href="#getting-started-manual-variables-file"><code>--variables-file</code> option</a></li>
|
||
<li>by defining environment variables, for instance <code>HURL_foo=bar</code></li>
|
||
<li>by defining variables in an [<code>[Options]</code> section]<a href="#file-format-request-options">options</a></li>
|
||
</ul>
|
||
|
||
<p>Lets’ see how to inject variables, given this <code>test.hurl</code>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://{{host}}/{{id}}/status</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">304</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://{{host}}/health</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<h4 id="file-format-templates-variable-option"><a href="#file-format-templates-variable-option"><code>variable</code> option</a></h4>
|
||
|
||
<p>Variable can be defined with command line option:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --variable host=example.net --variable id=1234 test.hurl</code></pre>
|
||
|
||
<h4 id="file-format-templates-variables-file-option"><a href="#file-format-templates-variables-file-option"><code>variables-file</code> option</a></h4>
|
||
|
||
<p>We can also define all injected variables in a file:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --variables-file vars.env test.hurl</code></pre>
|
||
|
||
<p>where <code>vars.env</code> is</p>
|
||
|
||
<pre><code>host=example.net
|
||
id=1234
|
||
</code></pre>
|
||
|
||
<h4 id="file-format-templates-environment-variable"><a href="#file-format-templates-environment-variable">Environment variable</a></h4>
|
||
|
||
<p>We can use environment variables in the form of <code>HURL_name=value</code>:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>export HURL_host=example.net
|
||
<span class="prompt">$ </span>export HURL_id=1234
|
||
<span class="prompt">$ </span>hurl test.hurl</code></pre>
|
||
|
||
<h4 id="file-format-templates-options-sections"><a href="#file-format-templates-options-sections">Options sections</a></h4>
|
||
|
||
<p>We can define variables in <code>[Options]</code> section. Variables defined in a section are available for the next requests.</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">https://{{host}}/{{id}}/status</span></span>
|
||
<span class="line"><span class="section-header">[Options]</span></span>
|
||
<span class="line"><span class="string">variable</span>: host=<span class="string">example.net</span></span>
|
||
<span class="line"><span class="string">variable</span>: id=<span class="number">1234</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">304</span></span>
|
||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||
<span class="line"><span class="method">GET</span> <span class="url">https://{{host}}/health</span></span>
|
||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span></span></span></code></pre>
|
||
|
||
<h3 id="file-format-templates-templating-body"><a href="#file-format-templates-templating-body">Templating Body</a></h3>
|
||
|
||
<p>Variables and functions can be used in <a href="#file-format-request-json-body">JSON body</a>:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">PUT</span> <span class="url">https://example.org/api/hits</span></span>
|
||
<span class="json"><span class="line">{</span>
|
||
<span class="line"> "key0": "{{a_string}}",</span>
|
||
<span class="line"> "key1": {{a_bool}},</span>
|
||
<span class="line"> "key2": {{a_null}},</span>
|
||
<span class="line"> "key3": {{a_number}},</span>
|
||
<span class="line"> "key4": "{{newDate}}"</span>
|
||
<span class="line">}</span></span></span></span></code></pre>
|
||
|
||
<p>Note that we’re writing a kind of JSON body directly without any delimitation marker. For the moment, <a href="#file-format-request-xml-body">XML body</a> can’t
|
||
use variables directly. In order to templatize a XML body, you can use <a href="#file-format-request-multiline-string-body">multiline string body</a> with variables and
|
||
functions. The multiline string body allows to templatize any text based body (JSON, XML, CSV etc...):</p>
|
||
|
||
<p>Multiline string body delimited by <code></code><code> </code>`:</p>
|
||
|
||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">PUT</span> <span class="url">https://example.org/api/hits</span></span>
|
||
<span class="line"><span class="string">Content-Type</span>: <span class="string">application/json</span></span>
|
||
<span class="multiline"><span class="line">```</span>
|
||
<span class="line">{</span>
|
||
<span class="line"> "key0": "{{a_string}}",</span>
|
||
<span class="line"> "key1": {{a_bool}},</span>
|
||
<span class="line"> "key2": {{a_null}},</span>
|
||
<span class="line"> "key3": {{a_number}},</span>
|
||
<span class="line"> "key4: "{{newDate}}"</span>
|
||
<span class="line">}</span>
|
||
<span class="line">```</span></span></span></span></code></pre>
|
||
|
||
<p>Variables can be initialized via command line:</p>
|
||
|
||
<pre><code class="language-shell"><span class="prompt">$ </span>hurl --variable a_string=apple --variable a_bool=true --variable a_null=null --variable a_number=42 test.hurl</code></pre>
|
||
|
||
<p>Resulting in a PUT request with the following JSON body:</p>
|
||
|
||
<pre><code>{
|
||
"key0": "apple",
|
||
"key1": true,
|
||
"key2": null,
|
||
"key3": 42,
|
||
"key4": "2024-12-02T13:39:45.936643Z"
|
||
}
|
||
</code></pre>
|
||
|
||
<hr />
|
||
|
||
<h2 id="file-format-grammar-grammar"><a href="#file-format-grammar-grammar">Grammar</a></h2>
|
||
|
||
<h3 id="file-format-grammar-definitions"><a href="#file-format-grammar-definitions">Definitions</a></h3>
|
||
|
||
<p>Short description:</p>
|
||
|
||
<ul>
|
||
<li>operator | denotes alternative,</li>
|
||
<li>operator * denotes iteration (zero or more),</li>
|
||
<li>operator + denotes iteration (one or more),</li>
|
||
</ul>
|
||
|
||
<h3 id="file-format-grammar-syntax-grammar"><a href="#file-format-grammar-syntax-grammar">Syntax Grammar</a></h3>
|
||
|
||
<div class="grammar-ruleset"><h3 id="general"><a href="#general">General</a></h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="hurl-file">hurl-file</span></div><div class="grammar-rule-expression"><a href="#entry">entry</a><span class="grammar-symbol">*</span><br />
|
||
<a href="#lt">lt</a><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="entry">entry</span><span class="grammar-usedby">(used by <a href="#hurl-file">hurl-file</a>)</span></div><div class="grammar-rule-expression"><a href="#request">request</a><br />
|
||
<a href="#response">response</a><span class="grammar-symbol">?</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="request">request</span><span class="grammar-usedby">(used by <a href="#entry">entry</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<a href="#method">method</a> <a href="#sp">sp</a> <a href="#value-string">value-string</a> <a href="#lt">lt</a><br />
|
||
<a href="#header">header</a><span class="grammar-symbol">*</span><br />
|
||
<a href="#request-section">request-section</a><span class="grammar-symbol">*</span><br />
|
||
<a href="#body">body</a><span class="grammar-symbol">?</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="response">response</span><span class="grammar-usedby">(used by <a href="#entry">entry</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<a href="#version">version</a> <a href="#sp">sp</a> <a href="#status">status</a> <a href="#lt">lt</a><br />
|
||
<a href="#header">header</a><span class="grammar-symbol">*</span><br />
|
||
<a href="#response-section">response-section</a><span class="grammar-symbol">*</span><br />
|
||
<a href="#body">body</a><span class="grammar-symbol">?</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="method">method</span><span class="grammar-usedby">(used by <a href="#request">request</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[A-Z]+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="version">version</span><span class="grammar-usedby">(used by <a href="#response">response</a>)</span></div><div class="grammar-rule-expression"> <span class="grammar-literal">HTTP/1.0</span><br />
|
||
<span class="grammar-symbol">|</span><span class="grammar-literal">HTTP/1.1</span><br />
|
||
<span class="grammar-symbol">|</span><span class="grammar-literal">HTTP/2</span><br />
|
||
<span class="grammar-symbol">|</span><span class="grammar-literal">HTTP</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="status">status</span><span class="grammar-usedby">(used by <a href="#response">response</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[0-9]+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="header">header</span><span class="grammar-usedby">(used by <a href="#request">request</a>, <a href="#response">response</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<a href="#key-value">key-value</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="body">body</span><span class="grammar-usedby">(used by <a href="#request">request</a>, <a href="#response">response</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<a href="#bytes">bytes</a> <a href="#lt">lt</a></div></div>
|
||
</div>
|
||
<div class="grammar-ruleset"><h3 id="sections"><a href="#sections">Sections</a></h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="request-section">request-section</span><span class="grammar-usedby">(used by <a href="#request">request</a>)</span></div><div class="grammar-rule-expression"> <a href="#basic-auth-section">basic-auth-section</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#query-string-params-section">query-string-params-section</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#form-params-section">form-params-section</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#multipart-form-data-section">multipart-form-data-section</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#cookies-section">cookies-section</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#options-section">options-section</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="response-section">response-section</span><span class="grammar-usedby">(used by <a href="#response">response</a>)</span></div><div class="grammar-rule-expression"> <a href="#captures-section">captures-section</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#asserts-section">asserts-section</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="query-string-params-section">query-string-params-section</span><span class="grammar-usedby">(used by <a href="#request-section">request-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<span class="grammar-symbol">(</span><span class="grammar-literal">[QueryStringParams]</span><span class="grammar-symbol">|</span><span class="grammar-literal">[Query]</span><span class="grammar-symbol">)</span> <a href="#lt">lt</a><br />
|
||
<a href="#key-value">key-value</a><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="form-params-section">form-params-section</span><span class="grammar-usedby">(used by <a href="#request-section">request-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<span class="grammar-symbol">(</span><span class="grammar-literal">[FormParams]</span><span class="grammar-symbol">|</span><span class="grammar-literal">[Form]</span><span class="grammar-symbol">)</span> <a href="#lt">lt</a><br />
|
||
<a href="#key-value">key-value</a><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multipart-form-data-section">multipart-form-data-section</span><span class="grammar-usedby">(used by <a href="#request-section">request-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<span class="grammar-symbol">(</span><span class="grammar-literal">[MultipartFormData]</span><span class="grammar-symbol">|</span><span class="grammar-literal">[Multipart]</span><span class="grammar-symbol">)</span> <a href="#lt">lt</a><br />
|
||
<a href="#multipart-form-data-param">multipart-form-data-param</a><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="cookies-section">cookies-section</span><span class="grammar-usedby">(used by <a href="#request-section">request-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<span class="grammar-literal">[Cookies]</span> <a href="#lt">lt</a><br />
|
||
<a href="#key-value">key-value</a><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="captures-section">captures-section</span><span class="grammar-usedby">(used by <a href="#response-section">response-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<span class="grammar-literal">[Captures]</span> <a href="#lt">lt</a><br />
|
||
<a href="#capture">capture</a><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="asserts-section">asserts-section</span><span class="grammar-usedby">(used by <a href="#response-section">response-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<span class="grammar-literal">[Asserts]</span> <a href="#lt">lt</a><br />
|
||
<a href="#assert">assert</a><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="basic-auth-section">basic-auth-section</span><span class="grammar-usedby">(used by <a href="#request-section">request-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<span class="grammar-literal">[BasicAuth]</span> <a href="#lt">lt</a><br />
|
||
<a href="#key-value">key-value</a><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="options-section">options-section</span><span class="grammar-usedby">(used by <a href="#request-section">request-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<span class="grammar-literal">[Options]</span> <a href="#lt">lt</a><br />
|
||
<a href="#option">option</a><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="key-value">key-value</span><span class="grammar-usedby">(used by <a href="#header">header</a>, <a href="#query-string-params-section">query-string-params-section</a>, <a href="#form-params-section">form-params-section</a>, <a href="#cookies-section">cookies-section</a>, <a href="#basic-auth-section">basic-auth-section</a>, <a href="#multipart-form-data-param">multipart-form-data-param</a>)</span></div><div class="grammar-rule-expression"><a href="#key-string">key-string</a> <span class="grammar-literal">:</span> <a href="#value-string">value-string</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multipart-form-data-param">multipart-form-data-param</span><span class="grammar-usedby">(used by <a href="#multipart-form-data-section">multipart-form-data-section</a>)</span></div><div class="grammar-rule-expression"><a href="#file-param">file-param</a><span class="grammar-symbol">|</span><a href="#key-value">key-value</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="file-param">file-param</span><span class="grammar-usedby">(used by <a href="#multipart-form-data-param">multipart-form-data-param</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<a href="#key-string">key-string</a> <span class="grammar-literal">:</span> <a href="#file-value">file-value</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="file-value">file-value</span><span class="grammar-usedby">(used by <a href="#file-param">file-param</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">file,</span> <a href="#filename">filename</a> <span class="grammar-literal">;</span> <span class="grammar-symbol">(</span><a href="#file-contenttype">file-contenttype</a><span class="grammar-symbol">)</span><span class="grammar-symbol">?</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="file-contenttype">file-contenttype</span><span class="grammar-usedby">(used by <a href="#file-value">file-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[a-zA-Z0-9/+-]+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="capture">capture</span><span class="grammar-usedby">(used by <a href="#captures-section">captures-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<a href="#key-string">key-string</a> <span class="grammar-literal">:</span> <a href="#query">query</a> <span class="grammar-symbol">(</span><a href="#sp">sp</a> <a href="#filter">filter</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="assert">assert</span><span class="grammar-usedby">(used by <a href="#asserts-section">asserts-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<a href="#query">query</a> <span class="grammar-symbol">(</span><a href="#sp">sp</a> <a href="#filter">filter</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span> <a href="#sp">sp</a> <a href="#predicate">predicate</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="option">option</span><span class="grammar-usedby">(used by <a href="#options-section">options-section</a>)</span></div><div class="grammar-rule-expression"><a href="#lt">lt</a><span class="grammar-symbol">*</span><br />
|
||
<span class="grammar-symbol">(</span><a href="#aws-sigv4-option">aws-sigv4-option</a><span class="grammar-symbol">|</span><a href="#ca-certificate-option">ca-certificate-option</a><span class="grammar-symbol">|</span><a href="#client-certificate-option">client-certificate-option</a><span class="grammar-symbol">|</span><a href="#client-key-option">client-key-option</a><span class="grammar-symbol">|</span><a href="#compressed-option">compressed-option</a><span class="grammar-symbol">|</span><a href="#connect-to-option">connect-to-option</a><span class="grammar-symbol">|</span><a href="#connect-timeout-option">connect-timeout-option</a><span class="grammar-symbol">|</span><a href="#delay-option">delay-option</a><span class="grammar-symbol">|</span><a href="#follow-redirect-option">follow-redirect-option</a><span class="grammar-symbol">|</span><a href="#follow-redirect-trusted-option">follow-redirect-trusted-option</a><span class="grammar-symbol">|</span><a href="#http10-option">http10-option</a><span class="grammar-symbol">|</span><a href="#http11-option">http11-option</a><span class="grammar-symbol">|</span><a href="#http2-option">http2-option</a><span class="grammar-symbol">|</span><a href="#http3-option">http3-option</a><span class="grammar-symbol">|</span><a href="#insecure-option">insecure-option</a><span class="grammar-symbol">|</span><a href="#ipv4-option">ipv4-option</a><span class="grammar-symbol">|</span><a href="#ipv6-option">ipv6-option</a><span class="grammar-symbol">|</span><a href="#limit-rate-option">limit-rate-option</a><span class="grammar-symbol">|</span><a href="#max-redirs-option">max-redirs-option</a><span class="grammar-symbol">|</span><a href="#netrc-option">netrc-option</a><span class="grammar-symbol">|</span><a href="#netrc-file-option">netrc-file-option</a><span class="grammar-symbol">|</span><a href="#netrc-optional-option">netrc-optional-option</a><span class="grammar-symbol">|</span><a href="#output-option">output-option</a><span class="grammar-symbol">|</span><a href="#path-as-is-option">path-as-is-option</a><span class="grammar-symbol">|</span><a href="#proxy-option">proxy-option</a><span class="grammar-symbol">|</span><a href="#repeat-option">repeat-option</a><span class="grammar-symbol">|</span><a href="#resolve-option">resolve-option</a><span class="grammar-symbol">|</span><a href="#retry-option">retry-option</a><span class="grammar-symbol">|</span><a href="#retry-interval-option">retry-interval-option</a><span class="grammar-symbol">|</span><a href="#skip-option">skip-option</a><span class="grammar-symbol">|</span><a href="#unix-socket-option">unix-socket-option</a><span class="grammar-symbol">|</span><a href="#user-option">user-option</a><span class="grammar-symbol">|</span><a href="#variable-option">variable-option</a><span class="grammar-symbol">|</span><a href="#verbose-option">verbose-option</a><span class="grammar-symbol">|</span><a href="#very-verbose-option">very-verbose-option</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="aws-sigv4-option">aws-sigv4-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">aws-sigv4</span> <span class="grammar-literal">:</span> <a href="#value-string">value-string</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="ca-certificate-option">ca-certificate-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">cacert</span> <span class="grammar-literal">:</span> <a href="#filename">filename</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="client-certificate-option">client-certificate-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">cert</span> <span class="grammar-literal">:</span> <a href="#filename-password">filename-password</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="client-key-option">client-key-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">key</span> <span class="grammar-literal">:</span> <a href="#value-string">value-string</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="compressed-option">compressed-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">compressed</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="connect-to-option">connect-to-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">connect-to</span> <span class="grammar-literal">:</span> <a href="#value-string">value-string</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="connect-timeout-option">connect-timeout-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">connect-timeout</span> <span class="grammar-literal">:</span> <a href="#duration-option">duration-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="delay-option">delay-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">delay</span> <span class="grammar-literal">:</span> <a href="#duration-option">duration-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="follow-redirect-option">follow-redirect-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">location</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="follow-redirect-trusted-option">follow-redirect-trusted-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">location-trusted</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="http10-option">http10-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">http1.0</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="http11-option">http11-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">http1.1</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="http2-option">http2-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">http2</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="http3-option">http3-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">http3</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="insecure-option">insecure-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">insecure</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="ipv4-option">ipv4-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">ipv4</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="ipv6-option">ipv6-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">ipv6</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="limit-rate-option">limit-rate-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">limit-rate</span> <span class="grammar-literal">:</span> <a href="#integer-option">integer-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="max-redirs-option">max-redirs-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">max-redirs</span> <span class="grammar-literal">:</span> <a href="#integer-option">integer-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="netrc-option">netrc-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">netrc</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="netrc-file-option">netrc-file-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">netrc-file</span> <span class="grammar-literal">:</span> <a href="#value-string">value-string</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="netrc-optional-option">netrc-optional-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">netrc-optional</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="output-option">output-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">output</span> <span class="grammar-literal">:</span> <a href="#value-string">value-string</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="path-as-is-option">path-as-is-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">path-as-is</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="proxy-option">proxy-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">proxy</span> <span class="grammar-literal">:</span> <a href="#value-string">value-string</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="resolve-option">resolve-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">resolve</span> <span class="grammar-literal">:</span> <a href="#value-string">value-string</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="repeat-option">repeat-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">repeat</span> <span class="grammar-literal">:</span> <a href="#integer-option">integer-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="retry-option">retry-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">retry</span> <span class="grammar-literal">:</span> <a href="#integer-option">integer-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="retry-interval-option">retry-interval-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">retry-interval</span> <span class="grammar-literal">:</span> <a href="#duration-option">duration-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="skip-option">skip-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">skip</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="unix-socket-option">unix-socket-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">unix-socket</span> <span class="grammar-literal">:</span> <a href="#value-string">value-string</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="user-option">user-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">user</span> <span class="grammar-literal">:</span> <a href="#value-string">value-string</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="variable-option">variable-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">variable</span> <span class="grammar-literal">:</span> <a href="#variable-definition">variable-definition</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="verbose-option">verbose-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">verbose</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="very-verbose-option">very-verbose-option</span><span class="grammar-usedby">(used by <a href="#option">option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">very-verbose</span> <span class="grammar-literal">:</span> <a href="#boolean-option">boolean-option</a> <a href="#lt">lt</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="variable-definition">variable-definition</span><span class="grammar-usedby">(used by <a href="#variable-option">variable-option</a>)</span></div><div class="grammar-rule-expression"><a href="#variable-name">variable-name</a> <span class="grammar-literal">=</span> <a href="#variable-value">variable-value</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="boolean-option">boolean-option</span><span class="grammar-usedby">(used by <a href="#compressed-option">compressed-option</a>, <a href="#follow-redirect-option">follow-redirect-option</a>, <a href="#follow-redirect-trusted-option">follow-redirect-trusted-option</a>, <a href="#http10-option">http10-option</a>, <a href="#http11-option">http11-option</a>, <a href="#http2-option">http2-option</a>, <a href="#http3-option">http3-option</a>, <a href="#insecure-option">insecure-option</a>, <a href="#ipv4-option">ipv4-option</a>, <a href="#ipv6-option">ipv6-option</a>, <a href="#netrc-option">netrc-option</a>, <a href="#netrc-optional-option">netrc-optional-option</a>, <a href="#path-as-is-option">path-as-is-option</a>, <a href="#skip-option">skip-option</a>, <a href="#verbose-option">verbose-option</a>, <a href="#very-verbose-option">very-verbose-option</a>)</span></div><div class="grammar-rule-expression"><a href="#boolean">boolean</a><span class="grammar-symbol">|</span><a href="#template">template</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="integer-option">integer-option</span><span class="grammar-usedby">(used by <a href="#limit-rate-option">limit-rate-option</a>, <a href="#max-redirs-option">max-redirs-option</a>, <a href="#repeat-option">repeat-option</a>, <a href="#retry-option">retry-option</a>)</span></div><div class="grammar-rule-expression"><a href="#integer">integer</a><span class="grammar-symbol">|</span><a href="#template">template</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="duration-option">duration-option</span><span class="grammar-usedby">(used by <a href="#connect-timeout-option">connect-timeout-option</a>, <a href="#delay-option">delay-option</a>, <a href="#retry-interval-option">retry-interval-option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#integer">integer</a> <a href="#duration-unit">duration-unit</a><span class="grammar-symbol">?</span><span class="grammar-symbol">)</span><span class="grammar-symbol">|</span><a href="#template">template</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="duration-unit">duration-unit</span><span class="grammar-usedby">(used by <a href="#duration-option">duration-option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">ms</span><span class="grammar-symbol">|</span><span class="grammar-literal">s</span><span class="grammar-symbol">|</span><span class="grammar-literal">m</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="variable-value">variable-value</span><span class="grammar-usedby">(used by <a href="#variable-definition">variable-definition</a>)</span></div><div class="grammar-rule-expression"> <a href="#null">null</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#boolean">boolean</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#integer">integer</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#float">float</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#key-string">key-string</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#quoted-string">quoted-string</a></div></div>
|
||
</div>
|
||
<div class="grammar-ruleset"><h3 id="query"><a href="#query">Query</a></h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="query">query</span><span class="grammar-usedby">(used by <a href="#capture">capture</a>, <a href="#assert">assert</a>)</span></div><div class="grammar-rule-expression"> <a href="#status-query">status-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#url-query">url-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#header-query">header-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#certificate-query">certificate-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#cookie-query">cookie-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#body-query">body-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#xpath-query">xpath-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#jsonpath-query">jsonpath-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#regex-query">regex-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#variable-query">variable-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#duration-query">duration-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#bytes-query">bytes-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#sha256-query">sha256-query</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#md5-query">md5-query</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="status-query">status-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">status</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="url-query">url-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">url</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="header-query">header-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">header</span> <a href="#sp">sp</a> <a href="#quoted-string">quoted-string</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="certificate-query">certificate-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">certificate</span> <a href="#sp">sp</a> <span class="grammar-symbol">(</span><span class="grammar-literal">Subject</span><span class="grammar-symbol">|</span><span class="grammar-literal">Issuer</span><span class="grammar-symbol">|</span><span class="grammar-literal">Start-Date</span><span class="grammar-symbol">|</span><span class="grammar-literal">Expire-Date</span><span class="grammar-symbol">|</span><span class="grammar-literal">Serial-Number</span><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="cookie-query">cookie-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">cookie</span> <a href="#sp">sp</a> <a href="#quoted-string">quoted-string</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="body-query">body-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">body</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="xpath-query">xpath-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">xpath</span> <a href="#sp">sp</a> <a href="#quoted-string">quoted-string</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="jsonpath-query">jsonpath-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">jsonpath</span> <a href="#sp">sp</a> <a href="#quoted-string">quoted-string</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="regex-query">regex-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">regex</span> <a href="#sp">sp</a> <span class="grammar-symbol">(</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#regex">regex</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="variable-query">variable-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">variable</span> <a href="#sp">sp</a> <a href="#quoted-string">quoted-string</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="duration-query">duration-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">duration</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="sha256-query">sha256-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">sha256</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="md5-query">md5-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">md5</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="bytes-query">bytes-query</span><span class="grammar-usedby">(used by <a href="#query">query</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">bytes</span></div></div>
|
||
</div>
|
||
<div class="grammar-ruleset"><h3 id="predicates"><a href="#predicates">Predicates</a></h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="predicate">predicate</span><span class="grammar-usedby">(used by <a href="#assert">assert</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><span class="grammar-literal">not</span> <a href="#sp">sp</a><span class="grammar-symbol">)</span><span class="grammar-symbol">?</span> <a href="#predicate-func">predicate-func</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="predicate-func">predicate-func</span><span class="grammar-usedby">(used by <a href="#predicate">predicate</a>)</span></div><div class="grammar-rule-expression"> <a href="#equal-predicate">equal-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#not-equal-predicate">not-equal-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#greater-predicate">greater-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#greater-or-equal-predicate">greater-or-equal-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#less-predicate">less-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#less-or-equal-predicate">less-or-equal-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#start-with-predicate">start-with-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#end-with-predicate">end-with-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#contain-predicate">contain-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#match-predicate">match-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#exist-predicate">exist-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#is-empty-predicate">is-empty-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#include-predicate">include-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#integer-predicate">integer-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#float-predicate">float-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#boolean-predicate">boolean-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#string-predicate">string-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#collection-predicate">collection-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#date-predicate">date-predicate</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#iso-date-predicate">iso-date-predicate</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="equal-predicate">equal-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">==</span> <a href="#sp">sp</a> <a href="#predicate-value">predicate-value</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="not-equal-predicate">not-equal-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">!=</span> <a href="#sp">sp</a> <a href="#predicate-value">predicate-value</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="greater-predicate">greater-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">></span> <a href="#sp">sp</a> <span class="grammar-symbol">(</span><a href="#number">number</a><span class="grammar-symbol">|</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="greater-or-equal-predicate">greater-or-equal-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">>=</span> <a href="#sp">sp</a> <a href="#sp">sp</a><span class="grammar-symbol">*</span> <span class="grammar-symbol">(</span><a href="#number">number</a><span class="grammar-symbol">|</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="less-predicate">less-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal"><</span> <a href="#sp">sp</a> <span class="grammar-symbol">(</span><a href="#number">number</a><span class="grammar-symbol">|</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="less-or-equal-predicate">less-or-equal-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal"><=</span> <a href="#sp">sp</a> <span class="grammar-symbol">(</span><a href="#number">number</a><span class="grammar-symbol">|</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="start-with-predicate">start-with-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">startsWith</span> <a href="#sp">sp</a> <span class="grammar-symbol">(</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#oneline-hex">oneline-hex</a><span class="grammar-symbol">|</span><a href="#oneline-base64">oneline-base64</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="end-with-predicate">end-with-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">endsWith</span> <a href="#sp">sp</a> <span class="grammar-symbol">(</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#oneline-hex">oneline-hex</a><span class="grammar-symbol">|</span><a href="#oneline-base64">oneline-base64</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="contain-predicate">contain-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">contains</span> <a href="#sp">sp</a> <a href="#quoted-string">quoted-string</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="match-predicate">match-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">matches</span> <a href="#sp">sp</a> <span class="grammar-symbol">(</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#regex">regex</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="exist-predicate">exist-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">exists</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="is-empty-predicate">is-empty-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isEmpty</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="include-predicate">include-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">includes</span> <a href="#sp">sp</a> <a href="#predicate-value">predicate-value</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="integer-predicate">integer-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isInteger</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="float-predicate">float-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isFloat</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="boolean-predicate">boolean-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isBoolean</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="string-predicate">string-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isString</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="collection-predicate">collection-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isCollection</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="date-predicate">date-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isDate</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="iso-date-predicate">iso-date-predicate</span><span class="grammar-usedby">(used by <a href="#predicate-func">predicate-func</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">isIsoDate</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="predicate-value">predicate-value</span><span class="grammar-usedby">(used by <a href="#equal-predicate">equal-predicate</a>, <a href="#not-equal-predicate">not-equal-predicate</a>, <a href="#include-predicate">include-predicate</a>)</span></div><div class="grammar-rule-expression"> <a href="#boolean">boolean</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#multiline-string">multiline-string</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#null">null</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#number">number</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#oneline-string">oneline-string</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#oneline-base64">oneline-base64</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#oneline-file">oneline-file</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#oneline-hex">oneline-hex</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#quoted-string">quoted-string</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#template">template</a></div></div>
|
||
</div>
|
||
<div class="grammar-ruleset"><h3 id="bytes"><a href="#bytes">Bytes</a></h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="bytes">bytes</span><span class="grammar-usedby">(used by <a href="#body">body</a>)</span></div><div class="grammar-rule-expression"> <a href="#json-value">json-value</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#xml">xml</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#multiline-string">multiline-string</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#oneline-string">oneline-string</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#oneline-base64">oneline-base64</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#oneline-file">oneline-file</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#oneline-hex">oneline-hex</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="xml">xml</span><span class="grammar-usedby">(used by <a href="#bytes">bytes</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal"><</span> <span class="grammar-literal">To Be Defined</span> <span class="grammar-literal">></span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-base64">oneline-base64</span><span class="grammar-usedby">(used by <a href="#start-with-predicate">start-with-predicate</a>, <a href="#end-with-predicate">end-with-predicate</a>, <a href="#predicate-value">predicate-value</a>, <a href="#bytes">bytes</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">base64,</span> <span class="grammar-regex">[A-Z0-9+-= \n]+</span> <span class="grammar-literal">;</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-file">oneline-file</span><span class="grammar-usedby">(used by <a href="#predicate-value">predicate-value</a>, <a href="#bytes">bytes</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">file,</span> <a href="#filename">filename</a> <span class="grammar-literal">;</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-hex">oneline-hex</span><span class="grammar-usedby">(used by <a href="#start-with-predicate">start-with-predicate</a>, <a href="#end-with-predicate">end-with-predicate</a>, <a href="#predicate-value">predicate-value</a>, <a href="#bytes">bytes</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">hex,</span> <a href="#hexdigit">hexdigit</a><span class="grammar-symbol">*</span> <span class="grammar-literal">;</span></div></div>
|
||
</div>
|
||
<div class="grammar-ruleset"><h3 id="strings"><a href="#strings">Strings</a></h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="quoted-string">quoted-string</span><span class="grammar-usedby">(used by <a href="#variable-value">variable-value</a>, <a href="#header-query">header-query</a>, <a href="#cookie-query">cookie-query</a>, <a href="#xpath-query">xpath-query</a>, <a href="#jsonpath-query">jsonpath-query</a>, <a href="#regex-query">regex-query</a>, <a href="#variable-query">variable-query</a>, <a href="#greater-predicate">greater-predicate</a>, <a href="#greater-or-equal-predicate">greater-or-equal-predicate</a>, <a href="#less-predicate">less-predicate</a>, <a href="#less-or-equal-predicate">less-or-equal-predicate</a>, <a href="#start-with-predicate">start-with-predicate</a>, <a href="#end-with-predicate">end-with-predicate</a>, <a href="#contain-predicate">contain-predicate</a>, <a href="#match-predicate">match-predicate</a>, <a href="#predicate-value">predicate-value</a>, <a href="#jsonpath-filter">jsonpath-filter</a>, <a href="#regex-filter">regex-filter</a>, <a href="#replace-filter">replace-filter</a>, <a href="#split-filter">split-filter</a>, <a href="#xpath-filter">xpath-filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">"</span> <span class="grammar-symbol">(</span><a href="#quoted-string-content">quoted-string-content</a><span class="grammar-symbol">|</span><a href="#template">template</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span> <span class="grammar-literal">"</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="quoted-string-content">quoted-string-content</span><span class="grammar-usedby">(used by <a href="#quoted-string">quoted-string</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#quoted-string-text">quoted-string-text</a><span class="grammar-symbol">|</span><a href="#quoted-string-escaped-char">quoted-string-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="quoted-string-text">quoted-string-text</span><span class="grammar-usedby">(used by <a href="#quoted-string-content">quoted-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~["\\]+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="quoted-string-escaped-char">quoted-string-escaped-char</span><span class="grammar-usedby">(used by <a href="#quoted-string-content">quoted-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span> <span class="grammar-symbol">(</span><span class="grammar-literal">"</span><span class="grammar-symbol">|</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">\b</span><span class="grammar-symbol">|</span><span class="grammar-literal">\f</span><span class="grammar-symbol">|</span><span class="grammar-literal">\n</span><span class="grammar-symbol">|</span><span class="grammar-literal">\r</span><span class="grammar-symbol">|</span><span class="grammar-literal">\t</span><span class="grammar-symbol">|</span><span class="grammar-literal">\u</span> <a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="key-string">key-string</span><span class="grammar-usedby">(used by <a href="#key-value">key-value</a>, <a href="#file-param">file-param</a>, <a href="#capture">capture</a>, <a href="#variable-value">variable-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#key-string-content">key-string-content</a><span class="grammar-symbol">|</span><a href="#template">template</a><span class="grammar-symbol">)</span><span class="grammar-symbol">+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="key-string-content">key-string-content</span><span class="grammar-usedby">(used by <a href="#key-string">key-string</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#key-string-text">key-string-text</a><span class="grammar-symbol">|</span><a href="#key-string-escaped-char">key-string-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="key-string-text">key-string-text</span><span class="grammar-usedby">(used by <a href="#key-string-content">key-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#alphanum">alphanum</a><span class="grammar-symbol">|</span><span class="grammar-literal">_</span><span class="grammar-symbol">|</span><span class="grammar-literal">-</span><span class="grammar-symbol">|</span><span class="grammar-literal">.</span><span class="grammar-symbol">|</span><span class="grammar-literal">[</span><span class="grammar-symbol">|</span><span class="grammar-literal">]</span><span class="grammar-symbol">|</span><span class="grammar-literal">@</span><span class="grammar-symbol">|</span><span class="grammar-literal">$</span><span class="grammar-symbol">)</span><span class="grammar-symbol">+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="key-string-escaped-char">key-string-escaped-char</span><span class="grammar-usedby">(used by <a href="#key-string-content">key-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span> <span class="grammar-symbol">(</span><span class="grammar-literal">#</span><span class="grammar-symbol">|</span><span class="grammar-literal">:</span><span class="grammar-symbol">|</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">\b</span><span class="grammar-symbol">|</span><span class="grammar-literal">\f</span><span class="grammar-symbol">|</span><span class="grammar-literal">\n</span><span class="grammar-symbol">|</span><span class="grammar-literal">\r</span><span class="grammar-symbol">|</span><span class="grammar-literal">\t</span><span class="grammar-symbol">|</span><span class="grammar-literal">\u</span> <a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="value-string">value-string</span><span class="grammar-usedby">(used by <a href="#request">request</a>, <a href="#key-value">key-value</a>, <a href="#aws-sigv4-option">aws-sigv4-option</a>, <a href="#client-key-option">client-key-option</a>, <a href="#connect-to-option">connect-to-option</a>, <a href="#netrc-file-option">netrc-file-option</a>, <a href="#output-option">output-option</a>, <a href="#proxy-option">proxy-option</a>, <a href="#resolve-option">resolve-option</a>, <a href="#unix-socket-option">unix-socket-option</a>, <a href="#user-option">user-option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#value-string-content">value-string-content</a><span class="grammar-symbol">|</span><a href="#template">template</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="value-string-content">value-string-content</span><span class="grammar-usedby">(used by <a href="#value-string">value-string</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#value-string-text">value-string-text</a><span class="grammar-symbol">|</span><a href="#value-string-escaped-char">value-string-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="value-string-text">value-string-text</span><span class="grammar-usedby">(used by <a href="#value-string-content">value-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[#\n\\]+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="value-string-escaped-char">value-string-escaped-char</span><span class="grammar-usedby">(used by <a href="#value-string-content">value-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span> <span class="grammar-symbol">(</span><span class="grammar-literal">#</span><span class="grammar-symbol">|</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">\b</span><span class="grammar-symbol">|</span><span class="grammar-literal">\f</span><span class="grammar-symbol">|</span><span class="grammar-literal">\n</span><span class="grammar-symbol">|</span><span class="grammar-literal">\r</span><span class="grammar-symbol">|</span><span class="grammar-literal">\t</span><span class="grammar-symbol">|</span><span class="grammar-literal">\u</span> <a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-string">oneline-string</span><span class="grammar-usedby">(used by <a href="#predicate-value">predicate-value</a>, <a href="#bytes">bytes</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">`</span> <span class="grammar-symbol">(</span><a href="#oneline-string-content">oneline-string-content</a><span class="grammar-symbol">|</span><a href="#template">template</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span> <span class="grammar-literal">`</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-string-content">oneline-string-content</span><span class="grammar-usedby">(used by <a href="#oneline-string">oneline-string</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#oneline-string-text">oneline-string-text</a><span class="grammar-symbol">|</span><a href="#oneline-string-escaped-char">oneline-string-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-string-text">oneline-string-text</span><span class="grammar-usedby">(used by <a href="#oneline-string-content">oneline-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[#\n\\]</span> <span class="grammar-symbol">~</span><span class="grammar-literal">`</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="oneline-string-escaped-char">oneline-string-escaped-char</span><span class="grammar-usedby">(used by <a href="#oneline-string-content">oneline-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span> <span class="grammar-symbol">(</span><span class="grammar-literal">`</span><span class="grammar-symbol">|</span><span class="grammar-literal">#</span><span class="grammar-symbol">|</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">b</span><span class="grammar-symbol">|</span><span class="grammar-literal">f</span><span class="grammar-symbol">|</span><span class="grammar-literal">u</span> <a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multiline-string">multiline-string</span><span class="grammar-usedby">(used by <a href="#predicate-value">predicate-value</a>, <a href="#bytes">bytes</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">```</span> <a href="#multiline-string-type">multiline-string-type</a><span class="grammar-symbol">?</span> <span class="grammar-symbol">(</span><span class="grammar-literal">,</span> <a href="#multiline-string-attribute">multiline-string-attribute</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span> <a href="#lt">lt</a><br />
|
||
<span class="grammar-symbol">(</span><a href="#multiline-string-content">multiline-string-content</a><span class="grammar-symbol">|</span><a href="#template">template</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span> <a href="#lt">lt</a><br />
|
||
<span class="grammar-literal">```</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multiline-string-type">multiline-string-type</span><span class="grammar-usedby">(used by <a href="#multiline-string">multiline-string</a>)</span></div><div class="grammar-rule-expression"> <span class="grammar-literal">base64</span><br />
|
||
<span class="grammar-symbol">|</span><span class="grammar-literal">hex</span><br />
|
||
<span class="grammar-symbol">|</span><span class="grammar-literal">json</span><br />
|
||
<span class="grammar-symbol">|</span><span class="grammar-literal">xml</span><br />
|
||
<span class="grammar-symbol">|</span><span class="grammar-literal">graphql</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multiline-string-attribute">multiline-string-attribute</span><span class="grammar-usedby">(used by <a href="#multiline-string">multiline-string</a>)</span></div><div class="grammar-rule-expression"> <span class="grammar-literal">escape</span><br />
|
||
<span class="grammar-symbol">|</span><span class="grammar-literal">novariable</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multiline-string-content">multiline-string-content</span><span class="grammar-usedby">(used by <a href="#multiline-string">multiline-string</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#multiline-string-text">multiline-string-text</a><span class="grammar-symbol">|</span><a href="#multiline-string-escaped-char">multiline-string-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multiline-string-text">multiline-string-text</span><span class="grammar-usedby">(used by <a href="#multiline-string-content">multiline-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[\\]+</span> <span class="grammar-symbol">~</span><span class="grammar-literal">```</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="multiline-string-escaped-char">multiline-string-escaped-char</span><span class="grammar-usedby">(used by <a href="#multiline-string-content">multiline-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span> <span class="grammar-symbol">(</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">b</span><span class="grammar-symbol">|</span><span class="grammar-literal">f</span><span class="grammar-symbol">|</span><span class="grammar-literal">n</span><span class="grammar-symbol">|</span><span class="grammar-literal">r</span><span class="grammar-symbol">|</span><span class="grammar-literal">t</span><span class="grammar-symbol">|</span><span class="grammar-literal">`</span><span class="grammar-symbol">|</span><span class="grammar-literal">u</span> <a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename">filename</span><span class="grammar-usedby">(used by <a href="#file-value">file-value</a>, <a href="#ca-certificate-option">ca-certificate-option</a>, <a href="#oneline-file">oneline-file</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#filename-content">filename-content</a><span class="grammar-symbol">|</span><a href="#template">template</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-content">filename-content</span><span class="grammar-usedby">(used by <a href="#filename">filename</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#filename-text">filename-text</a><span class="grammar-symbol">|</span><a href="#filename-escaped-char">filename-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-text">filename-text</span><span class="grammar-usedby">(used by <a href="#filename-content">filename-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[#;{} \n\\]+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-escaped-char">filename-escaped-char</span><span class="grammar-usedby">(used by <a href="#filename-content">filename-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span> <span class="grammar-symbol">(</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">b</span><span class="grammar-symbol">|</span><span class="grammar-literal">f</span><span class="grammar-symbol">|</span><span class="grammar-literal">n</span><span class="grammar-symbol">|</span><span class="grammar-literal">r</span><span class="grammar-symbol">|</span><span class="grammar-literal">t</span><span class="grammar-symbol">|</span><span class="grammar-literal">#</span><span class="grammar-symbol">|</span><span class="grammar-literal">;</span><span class="grammar-symbol">|</span><span class="grammar-literal"> </span><span class="grammar-symbol">|</span><span class="grammar-literal">{</span><span class="grammar-symbol">|</span><span class="grammar-literal">}</span><span class="grammar-symbol">|</span><span class="grammar-literal">u</span> <a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password">filename-password</span><span class="grammar-usedby">(used by <a href="#client-certificate-option">client-certificate-option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#filename-password-content">filename-password-content</a><span class="grammar-symbol">|</span><a href="#template">template</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password-content">filename-password-content</span><span class="grammar-usedby">(used by <a href="#filename-password">filename-password</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#filename-password-text">filename-password-text</a><span class="grammar-symbol">|</span><a href="#filename-password-escaped-char">filename-password-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password-text">filename-password-text</span><span class="grammar-usedby">(used by <a href="#filename-password-content">filename-password-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[#;{} \n\\]+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password-escaped-char">filename-password-escaped-char</span><span class="grammar-usedby">(used by <a href="#filename-password-content">filename-password-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span> <span class="grammar-symbol">(</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">b</span><span class="grammar-symbol">|</span><span class="grammar-literal">f</span><span class="grammar-symbol">|</span><span class="grammar-literal">n</span><span class="grammar-symbol">|</span><span class="grammar-literal">r</span><span class="grammar-symbol">|</span><span class="grammar-literal">t</span><span class="grammar-symbol">|</span><span class="grammar-literal">#</span><span class="grammar-symbol">|</span><span class="grammar-literal">;</span><span class="grammar-symbol">|</span><span class="grammar-literal"> </span><span class="grammar-symbol">|</span><span class="grammar-literal">{</span><span class="grammar-symbol">|</span><span class="grammar-literal">}</span><span class="grammar-symbol">|</span><span class="grammar-literal">:</span><span class="grammar-symbol">|</span><span class="grammar-literal">u</span> <a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="unicode-char">unicode-char</span><span class="grammar-usedby">(used by <a href="#quoted-string-escaped-char">quoted-string-escaped-char</a>, <a href="#key-string-escaped-char">key-string-escaped-char</a>, <a href="#value-string-escaped-char">value-string-escaped-char</a>, <a href="#oneline-string-escaped-char">oneline-string-escaped-char</a>, <a href="#multiline-string-escaped-char">multiline-string-escaped-char</a>, <a href="#filename-escaped-char">filename-escaped-char</a>, <a href="#filename-password-escaped-char">filename-password-escaped-char</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">{</span> <a href="#hexdigit">hexdigit</a><span class="grammar-symbol">+</span> <span class="grammar-literal">}</span></div></div>
|
||
</div>
|
||
<div class="grammar-ruleset"><h3 id="json"><a href="#json">JSON</a></h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-value">json-value</span><span class="grammar-usedby">(used by <a href="#bytes">bytes</a>, <a href="#json-key-value">json-key-value</a>, <a href="#json-array">json-array</a>)</span></div><div class="grammar-rule-expression"> <a href="#template">template</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#json-object">json-object</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#json-array">json-array</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#json-string">json-string</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#json-number">json-number</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#boolean">boolean</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#null">null</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-object">json-object</span><span class="grammar-usedby">(used by <a href="#json-value">json-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">{</span> <a href="#json-key-value">json-key-value</a> <span class="grammar-symbol">(</span><span class="grammar-literal">,</span> <a href="#json-key-value">json-key-value</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span> <span class="grammar-literal">}</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-key-value">json-key-value</span><span class="grammar-usedby">(used by <a href="#json-object">json-object</a>)</span></div><div class="grammar-rule-expression"><a href="#json-string">json-string</a> <span class="grammar-literal">:</span> <a href="#json-value">json-value</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-array">json-array</span><span class="grammar-usedby">(used by <a href="#json-value">json-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">[</span> <a href="#json-value">json-value</a> <span class="grammar-symbol">(</span><span class="grammar-literal">,</span> <a href="#json-value">json-value</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span> <span class="grammar-literal">]</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-string">json-string</span><span class="grammar-usedby">(used by <a href="#json-value">json-value</a>, <a href="#json-key-value">json-key-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">"</span> <span class="grammar-symbol">(</span><a href="#json-string-content">json-string-content</a><span class="grammar-symbol">|</span><a href="#template">template</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span> <span class="grammar-literal">"</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-string-content">json-string-content</span><span class="grammar-usedby">(used by <a href="#json-string">json-string</a>)</span></div><div class="grammar-rule-expression"><a href="#json-string-text">json-string-text</a><span class="grammar-symbol">|</span><a href="#json-string-escaped-char">json-string-escaped-char</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-string-text">json-string-text</span><span class="grammar-usedby">(used by <a href="#json-string-content">json-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~["\\]</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-string-escaped-char">json-string-escaped-char</span><span class="grammar-usedby">(used by <a href="#json-string-content">json-string-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span> <span class="grammar-symbol">(</span><span class="grammar-literal">"</span><span class="grammar-symbol">|</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">b</span><span class="grammar-symbol">|</span><span class="grammar-literal">f</span><span class="grammar-symbol">|</span><span class="grammar-literal">n</span><span class="grammar-symbol">|</span><span class="grammar-literal">r</span><span class="grammar-symbol">|</span><span class="grammar-literal">t</span><span class="grammar-symbol">|</span><span class="grammar-literal">u</span> <a href="#hexdigit">hexdigit</a> <a href="#hexdigit">hexdigit</a> <a href="#hexdigit">hexdigit</a> <a href="#hexdigit">hexdigit</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-number">json-number</span><span class="grammar-usedby">(used by <a href="#json-value">json-value</a>)</span></div><div class="grammar-rule-expression"><a href="#integer">integer</a> <a href="#fraction">fraction</a><span class="grammar-symbol">?</span> <a href="#exponent">exponent</a><span class="grammar-symbol">?</span></div></div>
|
||
</div>
|
||
<div class="grammar-ruleset"><h3 id="template-expression"><a href="#template-expression">Template / Expression</a></h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="template">template</span><span class="grammar-usedby">(used by <a href="#boolean-option">boolean-option</a>, <a href="#integer-option">integer-option</a>, <a href="#duration-option">duration-option</a>, <a href="#predicate-value">predicate-value</a>, <a href="#quoted-string">quoted-string</a>, <a href="#key-string">key-string</a>, <a href="#value-string">value-string</a>, <a href="#oneline-string">oneline-string</a>, <a href="#multiline-string">multiline-string</a>, <a href="#filename">filename</a>, <a href="#filename-password">filename-password</a>, <a href="#json-value">json-value</a>, <a href="#json-string">json-string</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">{{</span> <a href="#expr">expr</a> <span class="grammar-literal">}}</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="expr">expr</span><span class="grammar-usedby">(used by <a href="#template">template</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#variable-name">variable-name</a><span class="grammar-symbol">|</span><a href="#function">function</a><span class="grammar-symbol">)</span> <span class="grammar-symbol">(</span><a href="#sp">sp</a> <a href="#filter">filter</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="variable-name">variable-name</span><span class="grammar-usedby">(used by <a href="#variable-definition">variable-definition</a>, <a href="#expr">expr</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[A-Za-z]</span> <span class="grammar-regex">[A-Za-z_-0-9]*</span></div></div>
|
||
</div>
|
||
<div class="grammar-ruleset"><h3 id="function"><a href="#function">Function</a></h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="function">function</span><span class="grammar-usedby">(used by <a href="#expr">expr</a>)</span></div><div class="grammar-rule-expression"> <a href="#env-function">env-function</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#now-function">now-function</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#uuid-function">uuid-function</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="env-function">env-function</span><span class="grammar-usedby">(used by <a href="#function">function</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">getEnv</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="now-function">now-function</span><span class="grammar-usedby">(used by <a href="#function">function</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">newDate</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="uuid-function">uuid-function</span><span class="grammar-usedby">(used by <a href="#function">function</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">newUuid</span></div></div>
|
||
</div>
|
||
<div class="grammar-ruleset"><h3 id="filter"><a href="#filter">Filter</a></h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filter">filter</span><span class="grammar-usedby">(used by <a href="#capture">capture</a>, <a href="#assert">assert</a>, <a href="#expr">expr</a>)</span></div><div class="grammar-rule-expression"> <a href="#count-filter">count-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#days-after-now-filter">days-after-now-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#days-before-now-filter">days-before-now-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#decode-filter">decode-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#format-filter">format-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#html-escape-filter">html-escape-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#html-unescape-filter">html-unescape-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#jsonpath-filter">jsonpath-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#nth-filter">nth-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#regex-filter">regex-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#replace-filter">replace-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#split-filter">split-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#to-date-filter">to-date-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#to-float-filter">to-float-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#to-int-filter">to-int-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#url-decode-filter">url-decode-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#url-encode-filter">url-encode-filter</a><br />
|
||
<span class="grammar-symbol">|</span><a href="#xpath-filter">xpath-filter</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="count-filter">count-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">count</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="days-after-now-filter">days-after-now-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">daysAfterNow</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="days-before-now-filter">days-before-now-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">daysBeforeNow</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="decode-filter">decode-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">decode</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="format-filter">format-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">format</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="html-escape-filter">html-escape-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">htmlEscape</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="html-unescape-filter">html-unescape-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">htmlUnescape</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="jsonpath-filter">jsonpath-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">jsonpath</span> <a href="#sp">sp</a> <a href="#quoted-string">quoted-string</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="nth-filter">nth-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">nth</span> <a href="#sp">sp</a> <a href="#integer">integer</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="regex-filter">regex-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">regex</span> <a href="#sp">sp</a> <span class="grammar-symbol">(</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#regex">regex</a><span class="grammar-symbol">)</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="replace-filter">replace-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">replace</span> <a href="#sp">sp</a> <span class="grammar-symbol">(</span><a href="#quoted-string">quoted-string</a><span class="grammar-symbol">|</span><a href="#regex">regex</a><span class="grammar-symbol">)</span> <a href="#sp">sp</a> <a href="#quoted-string">quoted-string</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="split-filter">split-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">split</span> <a href="#sp">sp</a> <a href="#quoted-string">quoted-string</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="to-date-filter">to-date-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">toDate</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="to-float-filter">to-float-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">toFloat</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="to-int-filter">to-int-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">toInt</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="url-decode-filter">url-decode-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">urlDecode</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="url-encode-filter">url-encode-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">urlEncode</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="xpath-filter">xpath-filter</span><span class="grammar-usedby">(used by <a href="#filter">filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">xpath</span> <a href="#sp">sp</a> <a href="#quoted-string">quoted-string</a></div></div>
|
||
</div>
|
||
<div class="grammar-ruleset"><h3 id="lexical-grammar"><a href="#lexical-grammar">Lexical Grammar</a></h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="boolean">boolean</span><span class="grammar-usedby">(used by <a href="#boolean-option">boolean-option</a>, <a href="#variable-value">variable-value</a>, <a href="#predicate-value">predicate-value</a>, <a href="#json-value">json-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">true</span><span class="grammar-symbol">|</span><span class="grammar-literal">false</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="null">null</span><span class="grammar-usedby">(used by <a href="#variable-value">variable-value</a>, <a href="#predicate-value">predicate-value</a>, <a href="#json-value">json-value</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">null</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="alphanum">alphanum</span><span class="grammar-usedby">(used by <a href="#key-string-text">key-string-text</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[A-Za-z0-9]</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="integer">integer</span><span class="grammar-usedby">(used by <a href="#integer-option">integer-option</a>, <a href="#duration-option">duration-option</a>, <a href="#variable-value">variable-value</a>, <a href="#json-number">json-number</a>, <a href="#nth-filter">nth-filter</a>, <a href="#float">float</a>, <a href="#number">number</a>)</span></div><div class="grammar-rule-expression"><a href="#digit">digit</a><span class="grammar-symbol">+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="float">float</span><span class="grammar-usedby">(used by <a href="#variable-value">variable-value</a>, <a href="#number">number</a>)</span></div><div class="grammar-rule-expression"><a href="#integer">integer</a> <a href="#fraction">fraction</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="number">number</span><span class="grammar-usedby">(used by <a href="#greater-predicate">greater-predicate</a>, <a href="#greater-or-equal-predicate">greater-or-equal-predicate</a>, <a href="#less-predicate">less-predicate</a>, <a href="#less-or-equal-predicate">less-or-equal-predicate</a>, <a href="#predicate-value">predicate-value</a>)</span></div><div class="grammar-rule-expression"><a href="#integer">integer</a><span class="grammar-symbol">|</span><a href="#float">float</a></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="digit">digit</span><span class="grammar-usedby">(used by <a href="#integer">integer</a>, <a href="#fraction">fraction</a>, <a href="#exponent">exponent</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[0-9]</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="hexdigit">hexdigit</span><span class="grammar-usedby">(used by <a href="#oneline-hex">oneline-hex</a>, <a href="#unicode-char">unicode-char</a>, <a href="#json-string-escaped-char">json-string-escaped-char</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[0-9A-Fa-f]</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="fraction">fraction</span><span class="grammar-usedby">(used by <a href="#json-number">json-number</a>, <a href="#float">float</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">.</span> <a href="#digit">digit</a><span class="grammar-symbol">+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="exponent">exponent</span><span class="grammar-usedby">(used by <a href="#json-number">json-number</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><span class="grammar-literal">e</span><span class="grammar-symbol">|</span><span class="grammar-literal">E</span><span class="grammar-symbol">)</span> <span class="grammar-symbol">(</span><span class="grammar-literal">+</span><span class="grammar-symbol">|</span><span class="grammar-literal">-</span><span class="grammar-symbol">)</span><span class="grammar-symbol">?</span> <a href="#digit">digit</a><span class="grammar-symbol">+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="sp">sp</span><span class="grammar-usedby">(used by <a href="#request">request</a>, <a href="#response">response</a>, <a href="#capture">capture</a>, <a href="#assert">assert</a>, <a href="#header-query">header-query</a>, <a href="#certificate-query">certificate-query</a>, <a href="#cookie-query">cookie-query</a>, <a href="#xpath-query">xpath-query</a>, <a href="#jsonpath-query">jsonpath-query</a>, <a href="#regex-query">regex-query</a>, <a href="#variable-query">variable-query</a>, <a href="#predicate">predicate</a>, <a href="#equal-predicate">equal-predicate</a>, <a href="#not-equal-predicate">not-equal-predicate</a>, <a href="#greater-predicate">greater-predicate</a>, <a href="#greater-or-equal-predicate">greater-or-equal-predicate</a>, <a href="#less-predicate">less-predicate</a>, <a href="#less-or-equal-predicate">less-or-equal-predicate</a>, <a href="#start-with-predicate">start-with-predicate</a>, <a href="#end-with-predicate">end-with-predicate</a>, <a href="#contain-predicate">contain-predicate</a>, <a href="#match-predicate">match-predicate</a>, <a href="#include-predicate">include-predicate</a>, <a href="#expr">expr</a>, <a href="#jsonpath-filter">jsonpath-filter</a>, <a href="#nth-filter">nth-filter</a>, <a href="#regex-filter">regex-filter</a>, <a href="#replace-filter">replace-filter</a>, <a href="#split-filter">split-filter</a>, <a href="#xpath-filter">xpath-filter</a>, <a href="#lt">lt</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">[ \t]</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="lt">lt</span><span class="grammar-usedby">(used by <a href="#hurl-file">hurl-file</a>, <a href="#request">request</a>, <a href="#response">response</a>, <a href="#header">header</a>, <a href="#body">body</a>, <a href="#query-string-params-section">query-string-params-section</a>, <a href="#form-params-section">form-params-section</a>, <a href="#multipart-form-data-section">multipart-form-data-section</a>, <a href="#cookies-section">cookies-section</a>, <a href="#captures-section">captures-section</a>, <a href="#asserts-section">asserts-section</a>, <a href="#basic-auth-section">basic-auth-section</a>, <a href="#options-section">options-section</a>, <a href="#file-param">file-param</a>, <a href="#capture">capture</a>, <a href="#assert">assert</a>, <a href="#option">option</a>, <a href="#aws-sigv4-option">aws-sigv4-option</a>, <a href="#ca-certificate-option">ca-certificate-option</a>, <a href="#client-certificate-option">client-certificate-option</a>, <a href="#client-key-option">client-key-option</a>, <a href="#compressed-option">compressed-option</a>, <a href="#connect-to-option">connect-to-option</a>, <a href="#connect-timeout-option">connect-timeout-option</a>, <a href="#delay-option">delay-option</a>, <a href="#follow-redirect-option">follow-redirect-option</a>, <a href="#follow-redirect-trusted-option">follow-redirect-trusted-option</a>, <a href="#http10-option">http10-option</a>, <a href="#http11-option">http11-option</a>, <a href="#http2-option">http2-option</a>, <a href="#http3-option">http3-option</a>, <a href="#insecure-option">insecure-option</a>, <a href="#ipv4-option">ipv4-option</a>, <a href="#ipv6-option">ipv6-option</a>, <a href="#limit-rate-option">limit-rate-option</a>, <a href="#max-redirs-option">max-redirs-option</a>, <a href="#netrc-option">netrc-option</a>, <a href="#netrc-file-option">netrc-file-option</a>, <a href="#netrc-optional-option">netrc-optional-option</a>, <a href="#output-option">output-option</a>, <a href="#path-as-is-option">path-as-is-option</a>, <a href="#proxy-option">proxy-option</a>, <a href="#resolve-option">resolve-option</a>, <a href="#repeat-option">repeat-option</a>, <a href="#retry-option">retry-option</a>, <a href="#retry-interval-option">retry-interval-option</a>, <a href="#skip-option">skip-option</a>, <a href="#unix-socket-option">unix-socket-option</a>, <a href="#user-option">user-option</a>, <a href="#variable-option">variable-option</a>, <a href="#verbose-option">verbose-option</a>, <a href="#very-verbose-option">very-verbose-option</a>, <a href="#multiline-string">multiline-string</a>)</span></div><div class="grammar-rule-expression"><a href="#sp">sp</a><span class="grammar-symbol">*</span> <a href="#comment">comment</a><span class="grammar-symbol">?</span> <span class="grammar-regex">[\n]?</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="comment">comment</span><span class="grammar-usedby">(used by <a href="#lt">lt</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">#</span> <span class="grammar-regex">~[\n]*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="regex">regex</span><span class="grammar-usedby">(used by <a href="#regex-query">regex-query</a>, <a href="#match-predicate">match-predicate</a>, <a href="#regex-filter">regex-filter</a>, <a href="#replace-filter">replace-filter</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">/</span> <a href="#regex-content">regex-content</a> <span class="grammar-literal">/</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="regex-content">regex-content</span><span class="grammar-usedby">(used by <a href="#regex">regex</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#regex-text">regex-text</a><span class="grammar-symbol">|</span><a href="#regex-escaped-char">regex-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="regex-text">regex-text</span><span class="grammar-usedby">(used by <a href="#regex-content">regex-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[\n\/]+</span></div></div>
|
||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="regex-escaped-char">regex-escaped-char</span><span class="grammar-usedby">(used by <a href="#regex-content">regex-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span> <span class="grammar-regex">~[\n]</span></div></div>
|
||
</div>
|
||
|
||
<hr />
|
||
|
||
<h1 id="resources"><a href="#resources">Resources</a></h1>
|
||
|
||
<h2 id="resources-license-license"><a href="#resources-license-license">License</a></h2>
|
||
|
||
<pre><code>
|
||
Apache License
|
||
Version 2.0, January 2004
|
||
http://www.apache.org/licenses/
|
||
|
||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||
|
||
1. Definitions.
|
||
|
||
"License" shall mean the terms and conditions for use, reproduction,
|
||
and distribution as defined by Sections 1 through 9 of this document.
|
||
|
||
"Licensor" shall mean the copyright owner or entity authorized by
|
||
the copyright owner that is granting the License.
|
||
|
||
"Legal Entity" shall mean the union of the acting entity and all
|
||
other entities that control, are controlled by, or are under common
|
||
control with that entity. For the purposes of this definition,
|
||
"control" means (i) the power, direct or indirect, to cause the
|
||
direction or management of such entity, whether by contract or
|
||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||
|
||
"You" (or "Your") shall mean an individual or Legal Entity
|
||
exercising permissions granted by this License.
|
||
|
||
"Source" form shall mean the preferred form for making modifications,
|
||
including but not limited to software source code, documentation
|
||
source, and configuration files.
|
||
|
||
"Object" form shall mean any form resulting from mechanical
|
||
transformation or translation of a Source form, including but
|
||
not limited to compiled object code, generated documentation,
|
||
and conversions to other media types.
|
||
|
||
"Work" shall mean the work of authorship, whether in Source or
|
||
Object form, made available under the License, as indicated by a
|
||
copyright notice that is included in or attached to the work
|
||
(an example is provided in the Appendix below).
|
||
|
||
"Derivative Works" shall mean any work, whether in Source or Object
|
||
form, that is based on (or derived from) the Work and for which the
|
||
editorial revisions, annotations, elaborations, or other modifications
|
||
represent, as a whole, an original work of authorship. For the purposes
|
||
of this License, Derivative Works shall not include works that remain
|
||
separable from, or merely link (or bind by name) to the interfaces of,
|
||
the Work and Derivative Works thereof.
|
||
|
||
"Contribution" shall mean any work of authorship, including
|
||
the original version of the Work and any modifications or additions
|
||
to that Work or Derivative Works thereof, that is intentionally
|
||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||
or by an individual or Legal Entity authorized to submit on behalf of
|
||
the copyright owner. For the purposes of this definition, "submitted"
|
||
means any form of electronic, verbal, or written communication sent
|
||
to the Licensor or its representatives, including but not limited to
|
||
communication on electronic mailing lists, source code control systems,
|
||
and issue tracking systems that are managed by, or on behalf of, the
|
||
Licensor for the purpose of discussing and improving the Work, but
|
||
excluding communication that is conspicuously marked or otherwise
|
||
designated in writing by the copyright owner as "Not a Contribution."
|
||
|
||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||
on behalf of whom a Contribution has been received by Licensor and
|
||
subsequently incorporated within the Work.
|
||
|
||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||
this License, each Contributor hereby grants to You a perpetual,
|
||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||
copyright license to reproduce, prepare Derivative Works of,
|
||
publicly display, publicly perform, sublicense, and distribute the
|
||
Work and such Derivative Works in Source or Object form.
|
||
|
||
3. Grant of Patent License. Subject to the terms and conditions of
|
||
this License, each Contributor hereby grants to You a perpetual,
|
||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||
(except as stated in this section) patent license to make, have made,
|
||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||
where such license applies only to those patent claims licensable
|
||
by such Contributor that are necessarily infringed by their
|
||
Contribution(s) alone or by combination of their Contribution(s)
|
||
with the Work to which such Contribution(s) was submitted. If You
|
||
institute patent litigation against any entity (including a
|
||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||
or a Contribution incorporated within the Work constitutes direct
|
||
or contributory patent infringement, then any patent licenses
|
||
granted to You under this License for that Work shall terminate
|
||
as of the date such litigation is filed.
|
||
|
||
4. Redistribution. You may reproduce and distribute copies of the
|
||
Work or Derivative Works thereof in any medium, with or without
|
||
modifications, and in Source or Object form, provided that You
|
||
meet the following conditions:
|
||
|
||
(a) You must give any other recipients of the Work or
|
||
Derivative Works a copy of this License; and
|
||
|
||
(b) You must cause any modified files to carry prominent notices
|
||
stating that You changed the files; and
|
||
|
||
(c) You must retain, in the Source form of any Derivative Works
|
||
that You distribute, all copyright, patent, trademark, and
|
||
attribution notices from the Source form of the Work,
|
||
excluding those notices that do not pertain to any part of
|
||
the Derivative Works; and
|
||
|
||
(d) If the Work includes a "NOTICE" text file as part of its
|
||
distribution, then any Derivative Works that You distribute must
|
||
include a readable copy of the attribution notices contained
|
||
within such NOTICE file, excluding those notices that do not
|
||
pertain to any part of the Derivative Works, in at least one
|
||
of the following places: within a NOTICE text file distributed
|
||
as part of the Derivative Works; within the Source form or
|
||
documentation, if provided along with the Derivative Works; or,
|
||
within a display generated by the Derivative Works, if and
|
||
wherever such third-party notices normally appear. The contents
|
||
of the NOTICE file are for informational purposes only and
|
||
do not modify the License. You may add Your own attribution
|
||
notices within Derivative Works that You distribute, alongside
|
||
or as an addendum to the NOTICE text from the Work, provided
|
||
that such additional attribution notices cannot be construed
|
||
as modifying the License.
|
||
|
||
You may add Your own copyright statement to Your modifications and
|
||
may provide additional or different license terms and conditions
|
||
for use, reproduction, or distribution of Your modifications, or
|
||
for any such Derivative Works as a whole, provided Your use,
|
||
reproduction, and distribution of the Work otherwise complies with
|
||
the conditions stated in this License.
|
||
|
||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||
any Contribution intentionally submitted for inclusion in the Work
|
||
by You to the Licensor shall be under the terms and conditions of
|
||
this License, without any additional terms or conditions.
|
||
Notwithstanding the above, nothing herein shall supersede or modify
|
||
the terms of any separate license agreement you may have executed
|
||
with Licensor regarding such Contributions.
|
||
|
||
6. Trademarks. This License does not grant permission to use the trade
|
||
names, trademarks, service marks, or product names of the Licensor,
|
||
except as required for reasonable and customary use in describing the
|
||
origin of the Work and reproducing the content of the NOTICE file.
|
||
|
||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||
agreed to in writing, Licensor provides the Work (and each
|
||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||
implied, including, without limitation, any warranties or conditions
|
||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||
appropriateness of using or redistributing the Work and assume any
|
||
risks associated with Your exercise of permissions under this License.
|
||
|
||
8. Limitation of Liability. In no event and under no legal theory,
|
||
whether in tort (including negligence), contract, or otherwise,
|
||
unless required by applicable law (such as deliberate and grossly
|
||
negligent acts) or agreed to in writing, shall any Contributor be
|
||
liable to You for damages, including any direct, indirect, special,
|
||
incidental, or consequential damages of any character arising as a
|
||
result of this License or out of the use or inability to use the
|
||
Work (including but not limited to damages for loss of goodwill,
|
||
work stoppage, computer failure or malfunction, or any and all
|
||
other commercial damages or losses), even if such Contributor
|
||
has been advised of the possibility of such damages.
|
||
|
||
9. Accepting Warranty or Additional Liability. While redistributing
|
||
the Work or Derivative Works thereof, You may choose to offer,
|
||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||
or other liability obligations and/or rights consistent with this
|
||
License. However, in accepting such obligations, You may act only
|
||
on Your own behalf and on Your sole responsibility, not on behalf
|
||
of any other Contributor, and only if You agree to indemnify,
|
||
defend, and hold each Contributor harmless for any liability
|
||
incurred by, or claims asserted against, such Contributor by reason
|
||
of your accepting any such warranty or additional liability.
|
||
|
||
END OF TERMS AND CONDITIONS
|
||
|
||
APPENDIX: How to apply the Apache License to your work.
|
||
|
||
To apply the Apache License to your work, attach the following
|
||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||
replaced with your own identifying information. (Don't include
|
||
the brackets!) The text should be enclosed in the appropriate
|
||
comment syntax for the file format. We also recommend that a
|
||
file or class name and description of purpose be included on the
|
||
same "printed page" as the copyright notice for easier
|
||
identification within third-party archives.
|
||
|
||
Copyright 2021 Hurl
|
||
|
||
Licensed under the Apache License, Version 2.0 (the "License");
|
||
you may not use this file except in compliance with the License.
|
||
You may obtain a copy of the License at
|
||
|
||
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
||
Unless required by applicable law or agreed to in writing, software
|
||
distributed under the License is distributed on an "AS IS" BASIS,
|
||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
See the License for the specific language governing permissions and
|
||
limitations under the License.
|
||
</code></pre>
|
||
|
||
<hr />
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html> |