Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1490,7 +1490,7 @@ to configure Hurl, there are three sources from the lowest priority (most easily
| <a href="#path-as-is" id="path-as-is"><code>--path-as-is</code></a> | Tell Hurl to not handle sequences of /../ or /./ in the given URL path. Normally Hurl will squash or merge them according to standards but with this option set you tell it not to do that.<br> |
| <a href="#pinnedpubkey" id="pinnedpubkey"><code>--pinnedpubkey &lt;HASHES&gt;</code></a> | When negotiating a TLS or SSL connection, the server sends a certificate indicating its identity. A public key is extracted from this certificate and if it does not exactly match the public key provided to this option, Hurl aborts the connection before sending or receiving any data.<br> |
| <a href="#proxy" id="proxy"><code>-x, --proxy &lt;[PROTOCOL://]HOST[:PORT]&gt;</code></a> | Use the specified proxy.<br><br>Environment variables: http_proxy https_proxy all_proxy<br> |
| <a href="#proxy-header" id="proxy-header"><code>--proxy-header &lt;HEADER&gt;</code></a> | Extra header to include in the request when sending to a proxy. These headers are only applied when a proxy is involved; if Hurl connects directly to the target server, they are ignored.<br><br>This is a cli-only option.<br> |
| <a href="#proxy-header" id="proxy-header"><code>--proxy-header &lt;HEADER&gt;</code></a> | Extra header to include in the request when sending to a proxy. These headers are only applied when a proxy is involved; if Hurl connects directly to the target server, they are ignored.<br><br>Environment variables: HURL_PROXY_HEADER='name1:value1&#124;name2:value2' (headers are separated by &#124;)<br><br>This is a cli-only option.<br> |
| <a href="#resolve" id="resolve"><code>--resolve &lt;HOST:PORT:ADDR&gt;</code></a> | Provide a custom address for a specific host and port pair. Using this, you can make the Hurl requests(s) use a specified address and prevent the otherwise normally resolved address to be used. Consider it a sort of /etc/hosts alternative provided on the command line.<br> |
| <a href="#ssl-no-revoke" id="ssl-no-revoke"><code>--ssl-no-revoke</code></a> | (Windows) This option tells Hurl to disable certificate revocation checks. WARNING: this option loosens the SSL security, and by using this flag you ask for exactly that.<br><br>This is a cli-only option.<br> |
| <a href="#unix-socket" id="unix-socket"><code>--unix-socket &lt;PATH&gt;</code></a> | (HTTP) Connect through this Unix domain socket, instead of using the network.<br> |
Expand Down
2 changes: 1 addition & 1 deletion docs/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ to configure Hurl, there are three sources from the lowest priority (most easily
| <a href="#path-as-is" id="path-as-is"><code>--path-as-is</code></a> | Tell Hurl to not handle sequences of /../ or /./ in the given URL path. Normally Hurl will squash or merge them according to standards but with this option set you tell it not to do that.<br> |
| <a href="#pinnedpubkey" id="pinnedpubkey"><code>--pinnedpubkey &lt;HASHES&gt;</code></a> | When negotiating a TLS or SSL connection, the server sends a certificate indicating its identity. A public key is extracted from this certificate and if it does not exactly match the public key provided to this option, Hurl aborts the connection before sending or receiving any data.<br> |
| <a href="#proxy" id="proxy"><code>-x, --proxy &lt;[PROTOCOL://]HOST[:PORT]&gt;</code></a> | Use the specified proxy.<br><br>Environment variables: http_proxy https_proxy all_proxy<br> |
| <a href="#proxy-header" id="proxy-header"><code>--proxy-header &lt;HEADER&gt;</code></a> | Extra header to include in the request when sending to a proxy. These headers are only applied when a proxy is involved; if Hurl connects directly to the target server, they are ignored.<br><br>This is a cli-only option.<br> |
| <a href="#proxy-header" id="proxy-header"><code>--proxy-header &lt;HEADER&gt;</code></a> | Extra header to include in the request when sending to a proxy. These headers are only applied when a proxy is involved; if Hurl connects directly to the target server, they are ignored.<br><br>Environment variables: HURL_PROXY_HEADER='name1:value1&#124;name2:value2' (headers are separated by &#124;)<br><br>This is a cli-only option.<br> |
| <a href="#resolve" id="resolve"><code>--resolve &lt;HOST:PORT:ADDR&gt;</code></a> | Provide a custom address for a specific host and port pair. Using this, you can make the Hurl requests(s) use a specified address and prevent the otherwise normally resolved address to be used. Consider it a sort of /etc/hosts alternative provided on the command line.<br> |
| <a href="#ssl-no-revoke" id="ssl-no-revoke"><code>--ssl-no-revoke</code></a> | (Windows) This option tells Hurl to disable certificate revocation checks. WARNING: this option loosens the SSL security, and by using this flag you ask for exactly that.<br><br>This is a cli-only option.<br> |
| <a href="#unix-socket" id="unix-socket"><code>--unix-socket &lt;PATH&gt;</code></a> | (HTTP) Connect through this Unix domain socket, instead of using the network.<br> |
Expand Down
4 changes: 3 additions & 1 deletion docs/manual/hurl.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH hurl 1 "20 Jun 2026" "hurl 8.1.0" " Hurl Manual"
.TH hurl 1 "21 Jun 2026" "hurl 8.1.0" " Hurl Manual"
.SH NAME

hurl - run and test HTTP requests.
Expand Down Expand Up @@ -334,6 +334,8 @@ Environment variables: http_proxy https_proxy all_proxy

Extra header to include in the request when sending to a proxy. These headers are only applied when a proxy is involved; if Hurl connects directly to the target server, they are ignored.

Environment variables: HURL_PROXY_HEADER='name1:value1|name2:value2' (headers are separated by |)

This is a cli-only option.

.IP "--resolve <HOST:PORT:ADDR> "
Expand Down
2 changes: 2 additions & 0 deletions docs/manual/hurl.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ Environment variables: http_proxy https_proxy all_proxy

Extra header to include in the request when sending to a proxy. These headers are only applied when a proxy is involved; if Hurl connects directly to the target server, they are ignored.

Environment variables: HURL_PROXY_HEADER='name1:value1|name2:value2' (headers are separated by |)

This is a cli-only option.

#### --resolve <HOST:PORT:ADDR> {#resolve}
Expand Down
1 change: 1 addition & 0 deletions docs/spec/options/hurl/proxy_header.option
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ help: Extra header to include in the request when sending to a proxy
help_heading: HTTP options
multi: append
cli_only: true
env_var: HURL_PROXY_HEADER='name1:value1|name2:value2' (headers are separated by |)
---
Extra header to include in the request when sending to a proxy. These headers are only applied when a proxy is involved; if Hurl connects directly to the target server, they are ignored.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
> CONNECT 127.0.0.1:8002 HTTP/1.1
> Host: 127.0.0.1:8002
> Proxy-Connection: Keep-Alive
> X-TO-PROXY-1: to-proxy-1
> X-TO-PROXY-2: to-proxy-2
>
< HTTP/1.1 200 Connection established
<
> GET /hello HTTP/1.1
> Host: 127.0.0.1:8002
> Accept: */*
> X-TO-SERVER: to-server
> User-Agent: hurl/<<<.*>>>
>
< HTTP/1.1 200 OK
< Server: Werkzeug/<<<.*?>>> Python/<<<.*>>>
< Date: <<<.*>>>
< Content-Type: text/html; charset=utf-8
< Content-Length: 12
< Connection: close
<
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello World!
11 changes: 11 additions & 0 deletions integration/hurl/tests_ssl/cacert_with_proxy_header_env_var.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Set-StrictMode -Version latest
$ErrorActionPreference = 'Stop'

# Does not work without --ssl-no-revoke
# $env:HURL_PROXY_HEADER = 'X-TO-PROXY-1: to-proxy-1|X-TO-PROXY-2: to-proxy-2'
# hurl --verbosity brief `
# --proxy http://127.0.0.1:3128 `
# --header X-TO-SERVER:to-server `
# --cacert tests_ssl/certs/server/cert.pem `
# tests_ssl/cacert_with_proxy.hurl
exit 255
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash
set -Eeuo pipefail

export HURL_PROXY_HEADER="X-TO-PROXY-1: to-proxy-1|X-TO-PROXY-2: to-proxy-2"
hurl --verbosity brief \
--proxy http://127.0.0.1:3128 \
--header X-TO-SERVER:to-server \
--cacert tests_ssl/certs/server/cert.pem \
tests_ssl/cacert_with_proxy.hurl
2 changes: 1 addition & 1 deletion packages/hurl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1490,7 +1490,7 @@ to configure Hurl, there are three sources from the lowest priority (most easily
| <a href="#path-as-is" id="path-as-is"><code>--path-as-is</code></a> | Tell Hurl to not handle sequences of /../ or /./ in the given URL path. Normally Hurl will squash or merge them according to standards but with this option set you tell it not to do that.<br> |
| <a href="#pinnedpubkey" id="pinnedpubkey"><code>--pinnedpubkey &lt;HASHES&gt;</code></a> | When negotiating a TLS or SSL connection, the server sends a certificate indicating its identity. A public key is extracted from this certificate and if it does not exactly match the public key provided to this option, Hurl aborts the connection before sending or receiving any data.<br> |
| <a href="#proxy" id="proxy"><code>-x, --proxy &lt;[PROTOCOL://]HOST[:PORT]&gt;</code></a> | Use the specified proxy.<br><br>Environment variables: http_proxy https_proxy all_proxy<br> |
| <a href="#proxy-header" id="proxy-header"><code>--proxy-header &lt;HEADER&gt;</code></a> | Extra header to include in the request when sending to a proxy. These headers are only applied when a proxy is involved; if Hurl connects directly to the target server, they are ignored.<br><br>This is a cli-only option.<br> |
| <a href="#proxy-header" id="proxy-header"><code>--proxy-header &lt;HEADER&gt;</code></a> | Extra header to include in the request when sending to a proxy. These headers are only applied when a proxy is involved; if Hurl connects directly to the target server, they are ignored.<br><br>Environment variables: HURL_PROXY_HEADER='name1:value1&#124;name2:value2' (headers are separated by &#124;)<br><br>This is a cli-only option.<br> |
| <a href="#resolve" id="resolve"><code>--resolve &lt;HOST:PORT:ADDR&gt;</code></a> | Provide a custom address for a specific host and port pair. Using this, you can make the Hurl requests(s) use a specified address and prevent the otherwise normally resolved address to be used. Consider it a sort of /etc/hosts alternative provided on the command line.<br> |
| <a href="#ssl-no-revoke" id="ssl-no-revoke"><code>--ssl-no-revoke</code></a> | (Windows) This option tells Hurl to disable certificate revocation checks. WARNING: this option loosens the SSL security, and by using this flag you ask for exactly that.<br><br>This is a cli-only option.<br> |
| <a href="#unix-socket" id="unix-socket"><code>--unix-socket &lt;PATH&gt;</code></a> | (HTTP) Connect through this Unix domain socket, instead of using the network.<br> |
Expand Down
8 changes: 8 additions & 0 deletions packages/hurl/src/cli/options/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub const HURL_NO_JSONPATH_COERCION: &str = "HURL_NO_JSONPATH_COERCION";
pub const HURL_NO_OUTPUT: &str = "HURL_NO_OUTPUT";
pub const HURL_NO_PRETTY: &str = "HURL_NO_PRETTY";
pub const HURL_PRETTY: &str = "HURL_PRETTY";
pub const HURL_PROXY_HEADER: &str = "HURL_PROXY_HEADER";
pub const HURL_RETRY: &str = "HURL_RETRY";
pub const HURL_RETRY_INTERVAL: &str = "HURL_RETRY_INTERVAL";
pub const HURL_SECRET_PREFIX: &str = "HURL_SECRET_";
Expand Down Expand Up @@ -295,6 +296,13 @@ impl RunContext {
self.get_env_var_bool(HURL_PRETTY)
}

/// Returns the Hurl proxy headers injected by environment variables.
pub fn proxy_header_env_var(&self) -> Option<&str> {
self.hurl_env_vars
.get(HURL_PROXY_HEADER)
.map(|v| v.as_str())
}

/// Returns the env var for retry count.
pub fn retry_env_var(&self) -> Option<&str> {
self.hurl_env_vars.get(HURL_RETRY).map(|v| v.as_str())
Expand Down
32 changes: 29 additions & 3 deletions packages/hurl/src/cli/options/env_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ use hurl_core::types::{BytesPerSec, Count, DurationUnit};
use super::context::{
HURL_CONNECT_TIMEOUT, HURL_DELAY, HURL_ERROR_FORMAT, HURL_FOLLOW_LOCATION,
HURL_FOLLOW_LOCATION_TRUSTED, HURL_HEADER, HURL_JOBS, HURL_LIMIT_RATE, HURL_MAX_FILESIZE,
HURL_MAX_REDIRS, HURL_MAX_TIME, HURL_NO_HEADER, HURL_RETRY, HURL_RETRY_INTERVAL,
HURL_VERBOSITY,
HURL_MAX_REDIRS, HURL_MAX_TIME, HURL_NO_HEADER, HURL_PROXY_HEADER, HURL_RETRY,
HURL_RETRY_INTERVAL, HURL_VERBOSITY,
};
use super::variables::TypeKind;
use super::{
Expand Down Expand Up @@ -124,7 +124,7 @@ fn headers(
let headers = header.split("|").map(|h| h.to_string()).collect::<Vec<_>>();
for h in &headers {
if !h.contains(':') {
let msg = format!("Invalid header <{h}> missing `:`");
let msg = format!("Invalid header <{h}>, missing `:`");
return Err(err_from_cli_err(CliOptionsError::Error(msg), HURL_HEADER));
}
}
Expand Down Expand Up @@ -263,6 +263,30 @@ fn no_headers(
Ok(all_no_headers)
}

fn proxy_headers(
context: &RunContext,
default_value: Vec<String>,
) -> Result<Vec<String>, CliOptionsError> {
let mut all_proxy_headers = default_value;
if let Some(proxy_header) = context.proxy_header_env_var() {
let proxy_headers = proxy_header
.split("|")
.map(|h| h.to_string())
.collect::<Vec<_>>();
for h in &proxy_headers {
if !h.contains(':') {
let msg = format!("Invalid proxy header <{h}>, missing `:`");
return Err(err_from_cli_err(
CliOptionsError::Error(msg),
HURL_PROXY_HEADER,
));
}
}
all_proxy_headers.extend(proxy_headers);
}
Ok(all_proxy_headers)
}

fn no_jsonpath_coercion(context: &RunContext, default_value: bool) -> bool {
context
.no_jsonpath_coercion_env_var()
Expand Down Expand Up @@ -410,6 +434,7 @@ pub fn parse_env_vars(
let parallel = parallel(context, default_options.parallel);
let pretty = pretty(context, default_options.pretty);
let progress_bar = progress_bar(context, default_options.progress_bar);
let proxy_headers = proxy_headers(context, default_options.proxy_headers)?;
let retry = retry(context, default_options.retry)?;
let retry_interval = retry_interval(context, default_options.retry_interval)?;
let secrets = secrets(context, default_options.secrets)?;
Expand Down Expand Up @@ -447,6 +472,7 @@ pub fn parse_env_vars(
parallel,
pretty,
progress_bar,
proxy_headers,
retry,
retry_interval,
secrets,
Expand Down
Loading