mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-12-23 02:52:34 +03:00
Fix relative redirect
This commit is contained in:
parent
1c2e2ffc72
commit
1ae68efd82
@ -1,2 +1,5 @@
|
||||
curl 'http://localhost:8000/redirect'
|
||||
curl 'http://localhost:8000/redirected'
|
||||
curl 'http://localhost:8000/redirect-absolute'
|
||||
curl 'http://localhost:8000/redirect-absolute' -L
|
||||
curl 'http://localhost:8000/redirect-relative'
|
||||
curl 'http://localhost:8000/redirect-relative' -L
|
||||
|
@ -1,13 +1,37 @@
|
||||
<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/redirect</span></span>
|
||||
<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/redirected</span></span>
|
||||
</span><span class="response"><span class="line"><span class="version">HTTP/1.0</span> <span class="number">200</span></span>
|
||||
<span class="raw"><span class="line">```Redirected```</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"># Absolute redirects</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/redirect-absolute</span></span>
|
||||
</span><span class="response"><span class="line"><span class="version">HTTP/1.0</span> <span class="number">302</span></span>
|
||||
<span class="line"><span class="string">Location</span><span>:</span> <span class="string">http://localhost:8000/redirected</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">http://localhost:8000/redirected</span></span>
|
||||
</span><span class="response"><span class="line"><span class="version">HTTP/1.0</span> <span class="number">200</span></span>
|
||||
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/redirect-absolute</span></span>
|
||||
<span class="line section-header">[Options]</span>
|
||||
<span class="line"><span class="string">location</span><span>:</span> <span class="boolean">true</span></span>
|
||||
</span><span class="response"><span class="line"></span>
|
||||
<span class="line"><span class="version">HTTP/1.0</span> <span class="number">200</span></span>
|
||||
<span class="raw"><span class="line">```Redirected```</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"># Relative redirects</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/redirect-relative</span></span>
|
||||
</span><span class="response"><span class="line"><span class="version">HTTP/1.0</span> <span class="number">302</span></span>
|
||||
<span class="line"><span class="string">Location</span><span>:</span> <span class="string">/redirected</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">http://localhost:8000/redirect-relative</span></span>
|
||||
<span class="line section-header">[Options]</span>
|
||||
<span class="line"><span class="string">location</span><span>:</span> <span class="boolean">true</span></span>
|
||||
</span><span class="response"><span class="line"></span>
|
||||
<span class="line"><span class="version">HTTP/1.0</span> <span class="number">200</span></span>
|
||||
<span class="raw"><span class="line">```Redirected```</span></span>
|
||||
</span></span><span class="line"></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"></span>
|
||||
</code></pre>
|
@ -1,10 +1,34 @@
|
||||
GET http://localhost:8000/redirect
|
||||
GET http://localhost:8000/redirected
|
||||
HTTP/1.0 200
|
||||
```Redirected```
|
||||
|
||||
|
||||
# Absolute redirects
|
||||
|
||||
GET http://localhost:8000/redirect-absolute
|
||||
HTTP/1.0 302
|
||||
Location: http://localhost:8000/redirected
|
||||
|
||||
GET http://localhost:8000/redirected
|
||||
GET http://localhost:8000/redirect-absolute
|
||||
[Options]
|
||||
location: true
|
||||
|
||||
HTTP/1.0 200
|
||||
|
||||
```Redirected```
|
||||
|
||||
|
||||
# Relative redirects
|
||||
|
||||
GET http://localhost:8000/redirect-relative
|
||||
HTTP/1.0 302
|
||||
Location: /redirected
|
||||
|
||||
GET http://localhost:8000/redirect-relative
|
||||
[Options]
|
||||
location: true
|
||||
|
||||
HTTP/1.0 200
|
||||
```Redirected```
|
||||
|
||||
|
||||
|
||||
|
@ -1 +1 @@
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/redirect"},"response":{"version":"HTTP/1.0","status":302,"headers":[{"name":"Location","value":"http://localhost:8000/redirected"}]}},{"request":{"method":"GET","url":"http://localhost:8000/redirected"},"response":{"version":"HTTP/1.0","status":200}}]}
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/redirected"},"response":{"version":"HTTP/1.0","status":200,"body":{"type":"raw-string","value":"Redirected"}}},{"request":{"method":"GET","url":"http://localhost:8000/redirect-absolute"},"response":{"version":"HTTP/1.0","status":302,"headers":[{"name":"Location","value":"http://localhost:8000/redirected"}]}},{"request":{"method":"GET","url":"http://localhost:8000/redirect-absolute"},"response":{"version":"HTTP/1.0","status":200,"body":{"type":"raw-string","value":"Redirected"}}},{"request":{"method":"GET","url":"http://localhost:8000/redirect-relative"},"response":{"version":"HTTP/1.0","status":302,"headers":[{"name":"Location","value":"/redirected"}]}},{"request":{"method":"GET","url":"http://localhost:8000/redirect-relative"},"response":{"version":"HTTP/1.0","status":200,"body":{"type":"raw-string","value":"Redirected"}}}]}
|
@ -1,12 +1,20 @@
|
||||
from app import app
|
||||
from flask import redirect
|
||||
from flask import redirect, Response
|
||||
|
||||
|
||||
@app.route("/redirect")
|
||||
def redirectme():
|
||||
@app.route("/redirect-absolute")
|
||||
def redirect_absolute():
|
||||
return redirect("http://localhost:8000/redirected")
|
||||
|
||||
|
||||
@app.route("/redirect-relative")
|
||||
def redirect_relative():
|
||||
response = Response(status=302)
|
||||
response.headers["Location"] = "/redirected"
|
||||
response.autocorrect_location_header = False
|
||||
return response
|
||||
|
||||
|
||||
@app.route("/redirected")
|
||||
def redirected():
|
||||
return ""
|
||||
return "Redirected"
|
||||
|
@ -82,12 +82,13 @@ impl Client {
|
||||
self.redirect_count = 0;
|
||||
loop {
|
||||
let (request, response) = self.execute(&request_spec, options, logger)?;
|
||||
calls.push((request, response.clone()));
|
||||
calls.push((request.clone(), response.clone()));
|
||||
if !options.follow_location {
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(url) = self.get_follow_location(&response) {
|
||||
let base_url = request.base_url()?;
|
||||
if let Some(url) = self.get_follow_location(&response, &base_url) {
|
||||
logger.debug("");
|
||||
logger.debug(format!("=> Redirect to {}", url).as_str());
|
||||
logger.debug("");
|
||||
@ -513,14 +514,14 @@ impl Client {
|
||||
/// 1. the option follow_location set to true
|
||||
/// 2. a 3xx response code
|
||||
/// 3. a header Location
|
||||
fn get_follow_location(&mut self, response: &Response) -> Option<String> {
|
||||
fn get_follow_location(&mut self, response: &Response, base_url: &str) -> Option<String> {
|
||||
let response_code = response.status;
|
||||
if !(300..400).contains(&response_code) {
|
||||
return None;
|
||||
}
|
||||
let location = match response.get_header_values("Location").get(0) {
|
||||
None => return None,
|
||||
Some(value) => value.clone(),
|
||||
Some(value) => get_redirect_url(value, base_url),
|
||||
};
|
||||
|
||||
if location.is_empty() {
|
||||
@ -590,6 +591,15 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the redirect url.
|
||||
fn get_redirect_url(location: &str, base_url: &str) -> String {
|
||||
if location.starts_with('/') {
|
||||
format!("{}{}", base_url, location)
|
||||
} else {
|
||||
location.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns cookies from both cookies from the cookie storage and the request.
|
||||
pub fn all_cookies(cookie_storage: &[Cookie], request_spec: &RequestSpec) -> Vec<RequestCookie> {
|
||||
let mut cookies = request_spec.cookies.clone();
|
||||
@ -739,4 +749,16 @@ mod tests {
|
||||
assert!(match_cookie(&cookie, "http://sub.example.com/toto"));
|
||||
assert!(!match_cookie(&cookie, "http://example.com/tata"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_redirect_url() {
|
||||
assert_eq!(
|
||||
get_redirect_url("http://localhost:8000/redirected", "http://localhost:8000"),
|
||||
"http://localhost:8000/redirected".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
get_redirect_url("/redirected", "http://localhost:8000"),
|
||||
"http://localhost:8000/redirected".to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -40,4 +40,5 @@ pub enum HttpError {
|
||||
UnsupportedContentEncoding {
|
||||
description: String,
|
||||
},
|
||||
InvalidUrl(String),
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
use super::core::*;
|
||||
use super::Header;
|
||||
use crate::http::header;
|
||||
use crate::http::{header, HttpError};
|
||||
use url::Url;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@ -61,6 +61,26 @@ impl Request {
|
||||
.get(0)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
/// Returns the base url http(s)://host(:port)
|
||||
pub fn base_url(&self) -> Result<String, HttpError> {
|
||||
// FIXME: is it possible to do it with libcurl?
|
||||
let url = match Url::parse(&self.url) {
|
||||
Ok(url) => url,
|
||||
Err(_) => return Err(HttpError::InvalidUrl(self.url.clone())),
|
||||
};
|
||||
let base_url = format!(
|
||||
"{}://{}{}",
|
||||
url.scheme(),
|
||||
url.host().unwrap(),
|
||||
if let Some(port) = url.port() {
|
||||
format!(":{}", port)
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
);
|
||||
Ok(base_url)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_cookies(s: &str) -> Vec<RequestCookie> {
|
||||
@ -136,20 +156,20 @@ pub mod tests {
|
||||
vec![
|
||||
Param {
|
||||
name: "param1".to_string(),
|
||||
value: "value1".to_string()
|
||||
value: "value1".to_string(),
|
||||
},
|
||||
Param {
|
||||
name: "param2".to_string(),
|
||||
value: "".to_string()
|
||||
value: "".to_string(),
|
||||
},
|
||||
Param {
|
||||
name: "param3".to_string(),
|
||||
value: "a=b".to_string()
|
||||
value: "a=b".to_string(),
|
||||
},
|
||||
Param {
|
||||
name: "param4".to_string(),
|
||||
value: "1,2,3".to_string()
|
||||
}
|
||||
value: "1,2,3".to_string(),
|
||||
},
|
||||
]
|
||||
)
|
||||
}
|
||||
@ -162,12 +182,12 @@ pub mod tests {
|
||||
vec![
|
||||
RequestCookie {
|
||||
name: "cookie1".to_string(),
|
||||
value: "value1".to_string()
|
||||
value: "value1".to_string(),
|
||||
},
|
||||
RequestCookie {
|
||||
name: "cookie2".to_string(),
|
||||
value: "value2".to_string()
|
||||
}
|
||||
value: "value2".to_string(),
|
||||
},
|
||||
]
|
||||
)
|
||||
}
|
||||
@ -179,12 +199,12 @@ pub mod tests {
|
||||
vec![
|
||||
RequestCookie {
|
||||
name: "cookie1".to_string(),
|
||||
value: "value1".to_string()
|
||||
value: "value1".to_string(),
|
||||
},
|
||||
RequestCookie {
|
||||
name: "cookie2".to_string(),
|
||||
value: "value2".to_string()
|
||||
}
|
||||
value: "value2".to_string(),
|
||||
},
|
||||
]
|
||||
)
|
||||
}
|
||||
@ -195,8 +215,45 @@ pub mod tests {
|
||||
parse_cookie("cookie1=value1"),
|
||||
RequestCookie {
|
||||
name: "cookie1".to_string(),
|
||||
value: "value1".to_string()
|
||||
value: "value1".to_string(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_base_url() {
|
||||
assert_eq!(
|
||||
Request {
|
||||
url: "http://localhost".to_string(),
|
||||
method: "".to_string(),
|
||||
headers: vec![],
|
||||
body: vec![],
|
||||
}
|
||||
.base_url()
|
||||
.unwrap(),
|
||||
"http://localhost".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
Request {
|
||||
url: "http://localhost:8000/redirect-relative".to_string(),
|
||||
method: "".to_string(),
|
||||
headers: vec![],
|
||||
body: vec![],
|
||||
}
|
||||
.base_url()
|
||||
.unwrap(),
|
||||
"http://localhost:8000".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
Request {
|
||||
url: "https://localhost:8000".to_string(),
|
||||
method: "".to_string(),
|
||||
headers: vec![],
|
||||
body: vec![],
|
||||
}
|
||||
.base_url()
|
||||
.unwrap(),
|
||||
"https://localhost:8000".to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -172,6 +172,7 @@ impl From<HttpError> for RunnerError {
|
||||
HttpError::UnsupportedContentEncoding { description } => {
|
||||
RunnerError::UnsupportedContentEncoding(description)
|
||||
}
|
||||
HttpError::InvalidUrl(url) => RunnerError::InvalidUrl(url),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -358,13 +358,16 @@ fn test_form_params() {
|
||||
|
||||
#[test]
|
||||
fn test_redirect() {
|
||||
let request_spec = default_get_request("http://localhost:8000/redirect");
|
||||
let request_spec = default_get_request("http://localhost:8000/redirect-absolute");
|
||||
let logger = Logger::new(false, false, "", "");
|
||||
let options = ClientOptions::default();
|
||||
let mut client = Client::new(None);
|
||||
let (request, response) = client.execute(&request_spec, &options, &logger).unwrap();
|
||||
assert_eq!(request.method, "GET".to_string());
|
||||
assert_eq!(request.url, "http://localhost:8000/redirect".to_string());
|
||||
assert_eq!(
|
||||
request.url,
|
||||
"http://localhost:8000/redirect-absolute".to_string()
|
||||
);
|
||||
assert_eq!(request.headers.len(), 3);
|
||||
|
||||
assert_eq!(response.status, 302);
|
||||
@ -377,7 +380,7 @@ fn test_redirect() {
|
||||
|
||||
#[test]
|
||||
fn test_follow_location() {
|
||||
let request_spec = default_get_request("http://localhost:8000/redirect");
|
||||
let request_spec = default_get_request("http://localhost:8000/redirect-absolute");
|
||||
let logger = Logger::new(false, false, "", "");
|
||||
let options = ClientOptions {
|
||||
follow_location: true,
|
||||
@ -388,7 +391,7 @@ fn test_follow_location() {
|
||||
assert_eq!(options.curl_args(), vec!["-L".to_string()]);
|
||||
assert_eq!(
|
||||
client.curl_command_line(&request_spec, &context_dir, &options),
|
||||
"curl 'http://localhost:8000/redirect' -L".to_string()
|
||||
"curl 'http://localhost:8000/redirect-absolute' -L".to_string()
|
||||
);
|
||||
|
||||
let calls = client
|
||||
@ -398,7 +401,10 @@ fn test_follow_location() {
|
||||
|
||||
let (request1, response1) = calls.get(0).unwrap();
|
||||
assert_eq!(request1.method, "GET".to_string());
|
||||
assert_eq!(request1.url, "http://localhost:8000/redirect".to_string());
|
||||
assert_eq!(
|
||||
request1.url,
|
||||
"http://localhost:8000/redirect-absolute".to_string()
|
||||
);
|
||||
assert_eq!(request1.headers.len(), 3);
|
||||
assert_eq!(response1.status, 302);
|
||||
assert!(response1.headers.contains(&Header {
|
||||
|
Loading…
Reference in New Issue
Block a user