diff --git a/integration/tests_ok/follow_redirect.curl b/integration/tests_ok/follow_redirect.curl
index 49e9321d3..e4bc887bb 100644
--- a/integration/tests_ok/follow_redirect.curl
+++ b/integration/tests_ok/follow_redirect.curl
@@ -1,2 +1,3 @@
curl --location 'http://localhost:8000/follow-redirect'
-curl --location --request POST 'http://localhost:8000/follow-redirect-308'
+curl --request POST --location 'http://localhost:8000/follow-redirect'
+curl --request POST --location 'http://localhost:8000/follow-redirect-308'
diff --git a/integration/tests_ok/follow_redirect.html b/integration/tests_ok/follow_redirect.html
index 00e990f8a..918aa57cc 100644
--- a/integration/tests_ok/follow_redirect.html
+++ b/integration/tests_ok/follow_redirect.html
@@ -2,6 +2,12 @@
HTTP 200
`Followed redirect!`
+
+
+POST http://localhost:8000/follow-redirect
+HTTP 200
+`Followed redirect!`
+
POST http://localhost:8000/follow-redirect-308
HTTP 200
`Followed redirect POST!`
diff --git a/integration/tests_ok/follow_redirect.hurl b/integration/tests_ok/follow_redirect.hurl
index 708b06168..862212eef 100644
--- a/integration/tests_ok/follow_redirect.hurl
+++ b/integration/tests_ok/follow_redirect.hurl
@@ -2,6 +2,12 @@ GET http://localhost:8000/follow-redirect
HTTP 200
`Followed redirect!`
+# On 301, 302, 303, redirected request switch to GET.
+# Otherwise, method are untouched.
+POST http://localhost:8000/follow-redirect
+HTTP 200
+`Followed redirect!`
+
POST http://localhost:8000/follow-redirect-308
HTTP 200
`Followed redirect POST!`
diff --git a/integration/tests_ok/follow_redirect.json b/integration/tests_ok/follow_redirect.json
index 468c4adfb..ff1a037cb 100644
--- a/integration/tests_ok/follow_redirect.json
+++ b/integration/tests_ok/follow_redirect.json
@@ -1 +1 @@
-{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/follow-redirect"},"response":{"status":200,"body":{"type":"text","value":"Followed redirect!"}}},{"request":{"method":"POST","url":"http://localhost:8000/follow-redirect-308"},"response":{"status":200,"body":{"type":"text","value":"Followed redirect POST!"}}}]}
+{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/follow-redirect"},"response":{"status":200,"body":{"type":"text","value":"Followed redirect!"}}},{"request":{"method":"POST","url":"http://localhost:8000/follow-redirect"},"response":{"status":200,"body":{"type":"text","value":"Followed redirect!"}}},{"request":{"method":"POST","url":"http://localhost:8000/follow-redirect-308"},"response":{"status":200,"body":{"type":"text","value":"Followed redirect POST!"}}}]}
diff --git a/integration/tests_ok/follow_redirect.py b/integration/tests_ok/follow_redirect.py
index e40ed7f2f..06a121e3f 100644
--- a/integration/tests_ok/follow_redirect.py
+++ b/integration/tests_ok/follow_redirect.py
@@ -2,7 +2,7 @@ from app import app
from flask import redirect, Response
-@app.route("/follow-redirect")
+@app.route("/follow-redirect", methods=["GET", "POST"])
def follow_redirect():
return redirect("http://localhost:8000/following-redirect")
diff --git a/integration/tests_ok/follow_redirect_option.curl b/integration/tests_ok/follow_redirect_option.curl
index 528bb6e7f..c0c9ccc79 100644
--- a/integration/tests_ok/follow_redirect_option.curl
+++ b/integration/tests_ok/follow_redirect_option.curl
@@ -1,3 +1,5 @@
curl 'http://localhost:8000/follow-redirect'
curl 'http://localhost:8000/follow-redirect'
curl --location 'http://localhost:8000/follow-redirect'
+curl --request POST --location 'http://localhost:8000/follow-redirect'
+curl --request POST --location 'http://localhost:8000/follow-redirect-308'
diff --git a/integration/tests_ok/follow_redirect_option.html b/integration/tests_ok/follow_redirect_option.html
index 015d55ad1..fbee320f2 100644
--- a/integration/tests_ok/follow_redirect_option.html
+++ b/integration/tests_ok/follow_redirect_option.html
@@ -23,5 +23,26 @@
header "Location" not exists
`Followed redirect!`
-
-
+
+
+
+
+POST http://localhost:8000/follow-redirect
+
+location: true
+
+HTTP 200
+
+header "Location" not exists
+`Followed redirect!`
+
+
+POST http://localhost:8000/follow-redirect-308
+
+location: true
+
+HTTP 200
+
+header "Location" not exists
+`Followed redirect POST!`
+
diff --git a/integration/tests_ok/follow_redirect_option.hurl b/integration/tests_ok/follow_redirect_option.hurl
index a69be16c5..06db133bb 100644
--- a/integration/tests_ok/follow_redirect_option.hurl
+++ b/integration/tests_ok/follow_redirect_option.hurl
@@ -24,3 +24,24 @@ HTTP 200
header "Location" not exists
`Followed redirect!`
+
+# On 301, 302, 303, redirected request switch to GET.
+# Otherwise, method are untouched.
+POST http://localhost:8000/follow-redirect
+[Options]
+location: true
+
+HTTP 200
+[Asserts]
+header "Location" not exists
+`Followed redirect!`
+
+
+POST http://localhost:8000/follow-redirect-308
+[Options]
+location: true
+
+HTTP 200
+[Asserts]
+header "Location" not exists
+`Followed redirect POST!`
diff --git a/integration/tests_ok/follow_redirect_option.json b/integration/tests_ok/follow_redirect_option.json
index 40a455d7d..36b839b46 100644
--- a/integration/tests_ok/follow_redirect_option.json
+++ b/integration/tests_ok/follow_redirect_option.json
@@ -1 +1 @@
-{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/follow-redirect"},"response":{"status":302,"asserts":[{"query":{"type":"header","name":"Location"},"predicate":{"type":"equal","value":"http://localhost:8000/following-redirect"}}]}},{"request":{"method":"GET","url":"http://localhost:8000/follow-redirect","options":[{"name":"location","value":false}]},"response":{"status":302,"asserts":[{"query":{"type":"header","name":"Location"},"predicate":{"type":"equal","value":"http://localhost:8000/following-redirect"}}]}},{"request":{"method":"GET","url":"http://localhost:8000/follow-redirect","options":[{"name":"location","value":true}]},"response":{"status":200,"asserts":[{"query":{"type":"header","name":"Location"},"predicate":{"not":true,"type":"exist"}}],"body":{"type":"text","value":"Followed redirect!"}}}]}
+{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/follow-redirect"},"response":{"status":302,"asserts":[{"query":{"type":"header","name":"Location"},"predicate":{"type":"equal","value":"http://localhost:8000/following-redirect"}}]}},{"request":{"method":"GET","url":"http://localhost:8000/follow-redirect","options":[{"name":"location","value":false}]},"response":{"status":302,"asserts":[{"query":{"type":"header","name":"Location"},"predicate":{"type":"equal","value":"http://localhost:8000/following-redirect"}}]}},{"request":{"method":"GET","url":"http://localhost:8000/follow-redirect","options":[{"name":"location","value":true}]},"response":{"status":200,"asserts":[{"query":{"type":"header","name":"Location"},"predicate":{"not":true,"type":"exist"}}],"body":{"type":"text","value":"Followed redirect!"}}},{"request":{"method":"POST","url":"http://localhost:8000/follow-redirect","options":[{"name":"location","value":true}]},"response":{"status":200,"asserts":[{"query":{"type":"header","name":"Location"},"predicate":{"not":true,"type":"exist"}}],"body":{"type":"text","value":"Followed redirect!"}}},{"request":{"method":"POST","url":"http://localhost:8000/follow-redirect-308","options":[{"name":"location","value":true}]},"response":{"status":200,"asserts":[{"query":{"type":"header","name":"Location"},"predicate":{"not":true,"type":"exist"}}],"body":{"type":"text","value":"Followed redirect POST!"}}}]}
diff --git a/integration/tests_ok/follow_redirect_option.out b/integration/tests_ok/follow_redirect_option.out
index 1ce8d0b1d..8cf3b25c1 100644
--- a/integration/tests_ok/follow_redirect_option.out
+++ b/integration/tests_ok/follow_redirect_option.out
@@ -1 +1 @@
-Followed redirect!
\ No newline at end of file
+Followed redirect POST!
\ No newline at end of file
diff --git a/packages/hurl/src/http/client.rs b/packages/hurl/src/http/client.rs
index 2124f7c19..2b07c5fa9 100644
--- a/packages/hurl/src/http/client.rs
+++ b/packages/hurl/src/http/client.rs
@@ -86,7 +86,7 @@ impl Client {
let call = self.execute(&request_spec, options, logger)?;
let base_url = call.request.base_url()?;
let redirect_url = self.get_follow_location(&call.response, &base_url);
- let call_response_status = call.response.status;
+ let status = call.response.status;
calls.push(call);
if !options.follow_location || redirect_url.is_none() {
break;
@@ -94,21 +94,16 @@ impl Client {
let redirect_url = redirect_url.unwrap();
logger.debug("");
logger.debug(format!("=> Redirect to {redirect_url}").as_str());
+ logger.debug("");
redirect_count += 1;
if let Some(max_redirect) = options.max_redirect {
if redirect_count > max_redirect {
return Err(HttpError::TooManyRedirect);
}
}
- let new_request_method = self.get_redirected_request_method(
- options,
- logger,
- call_response_status,
- request_spec.method,
- );
- logger.debug("");
+ let redirect_method = get_redirect_method(status, request_spec.method);
request_spec = RequestSpec {
- method: new_request_method,
+ method: redirect_method,
url: redirect_url,
..Default::default()
};
@@ -116,32 +111,6 @@ impl Client {
Ok(calls)
}
- pub fn get_redirected_request_method(
- &self,
- options: &ClientOptions,
- logger: &Logger,
- response_status: u32,
- original_method: Method,
- ) -> Method {
- // this replicates curls behavior
- return match response_status {
- 301 | 302 | 303 => {
- // spaces at the start to align with the arrow used in a previous
- // debug line
- logger.debug(
- format!(
- " Resending with method GET because response code was {response_status}"
- )
- .as_str(),
- );
- Method("GET".to_string())
- }
- // Could be only 307 and 308, but curl does this for all 3xx
- // codes not converted to GET above.
- _ => original_method,
- };
- }
-
/// Executes an HTTP request `request_spec`, without following redirection and returns a
/// pair of [`Request`], [`Response`].
pub fn execute(
@@ -685,6 +654,17 @@ fn get_redirect_url(location: &str, base_url: &str) -> String {
}
}
+/// Returns the method used for redirecting a request/response with `response_status`.
+fn get_redirect_method(response_status: u32, original_method: Method) -> Method {
+ // This replicates curl's behavior
+ match response_status {
+ 301 | 302 | 303 => Method("GET".to_string()),
+ // Could be only 307 and 308, but curl does this for all 3xx
+ // codes not converted to GET above.
+ _ => original_method,
+ }
+}
+
/// Returns cookies from both cookies from the cookie storage and the request.
pub fn all_cookies(cookie_storage: &[Cookie], request_spec: &RequestSpec) -> Vec {
let mut cookies = request_spec.cookies.clone();
@@ -844,4 +824,32 @@ mod tests {
"http://localhost:8000/redirected".to_string()
);
}
+
+ #[test]
+ fn test_redirect_method() {
+ // Status of the response to be redirected | method of the original request | method of the new request
+ let datas = [
+ (301, "GET", "GET"),
+ (301, "POST", "GET"),
+ (301, "DELETE", "GET"),
+ (302, "GET", "GET"),
+ (302, "POST", "GET"),
+ (302, "DELETE", "GET"),
+ (303, "GET", "GET"),
+ (303, "POST", "GET"),
+ (303, "DELETE", "GET"),
+ (304, "GET", "GET"),
+ (304, "POST", "POST"),
+ (304, "DELETE", "DELETE"),
+ (308, "GET", "GET"),
+ (308, "POST", "POST"),
+ (308, "DELETE", "DELETE"),
+ ];
+ for (status, original, redirected) in datas {
+ assert_eq!(
+ get_redirect_method(status, Method(original.to_string())),
+ Method(redirected.to_string())
+ );
+ }
+ }
}