Creates constructor methods for Request and Response.

This commit is contained in:
jcamiel 2024-02-07 17:49:09 +01:00
parent 3476b9f1ec
commit 7b7343bafe
No known key found for this signature in database
GPG Key ID: 07FF11CFD55356CC
4 changed files with 84 additions and 66 deletions

View File

@ -92,8 +92,7 @@ impl Client {
}
}
/// Executes an HTTP request `request_spec`, optionally follows redirection and returns a
/// list of pair of [`Request`], [`Response`].
/// Executes an HTTP request `request_spec`, optionally follows redirection and returns a list of [`Call`].
pub fn execute_with_redirect(
&mut self,
request_spec: &RequestSpec,
@ -149,7 +148,7 @@ impl Client {
}
/// Executes an HTTP request `request_spec`, without following redirection and returns a
/// pair of [`Request`], [`Response`].
/// pair of [`Call`].
pub fn execute(
&mut self,
request_spec: &RequestSpec,
@ -202,12 +201,12 @@ impl Client {
// because libcurl dont call `easy::InfoType::DataOut` if there is no data
// to send.
if !has_body_data && verbose {
let debug_request = Request {
url: url.to_string(),
method: method.to_string(),
headers: request_headers.clone(),
body: Vec::new(),
};
let debug_request = Request::new(
&method.to_string(),
&url,
request_headers.clone(),
vec![],
);
for header in &debug_request.headers {
logger.debug_header_out(&header.name, &header.value);
}
@ -225,12 +224,12 @@ impl Client {
// As we can be called multiple times in this callback, we only log headers the
// first time we send data (marked when the request body is empty).
if verbose && request_body.is_empty() {
let debug_request = Request {
url: url.to_string(),
method: method.to_string(),
headers: request_headers.clone(),
body: Vec::from(data),
};
let debug_request = Request::new(
&method.to_string(),
&url,
request_headers.clone(),
Vec::from(data),
);
for header in &debug_request.headers {
logger.debug_header_out(&header.name, &header.value);
}
@ -305,21 +304,16 @@ impl Client {
let duration = (stop - start).to_std().unwrap();
let timings = Timings::new(&mut self.handle, start, stop);
let request = Request {
url: url.clone(),
method: method.to_string(),
headers: request_headers,
body: request_body,
};
let response = Response {
let request = Request::new(&method.to_string(), &url, request_headers, request_body);
let response = Response::new(
version,
status,
headers,
body: response_body,
response_body,
duration,
url,
&url,
certificate,
};
);
if verbose {
// FIXME: the cast to u64 seems not necessary.

View File

@ -22,6 +22,11 @@ use url::Url;
use crate::http::core::*;
use crate::http::{header, Header, HttpError};
/// Represents a runtime HTTP request.
/// This is a real request, that has been executed by our HTTP client.
/// It's different from [`crate::http::RequestSpec`] which is the request asked to be executed by our user.
/// For instance, in the request spec, headers implicitly added by curl are not present, while
/// they will be present in the [`Request`] instances.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Request {
pub url: String,
@ -62,6 +67,16 @@ pub enum IpResolve {
}
impl Request {
/// Creates a new request.
pub fn new(method: &str, url: &str, headers: Vec<Header>, body: Vec<u8>) -> Self {
Request {
url: url.to_string(),
method: method.to_string(),
headers,
body,
}
}
/// Extracts query string params from the url of the request.
pub fn query_string_params(&self) -> Vec<Param> {
let u = Url::parse(self.url.as_str()).expect("valid url");
@ -140,34 +155,29 @@ mod tests {
use crate::http::RequestCookie;
fn hello_request() -> Request {
Request {
method: "GET".to_string(),
url: "http://localhost:8000/hello".to_string(),
headers: vec![
Request::new(
"GET",
"http://localhost:8000/hello",
vec![
Header::new("Host", "localhost:8000"),
Header::new("Accept", "*/*"),
Header::new("User-Agent", "hurl/1.0"),
],
body: vec![],
}
vec![],
)
}
fn query_string_request() -> Request {
Request {
method: "GET".to_string(),
url: "http://localhost:8000/querystring-params?param1=value1&param2=&param3=a%3Db&param4=1%2C2%2C3".to_string(),
headers: vec![],
body: vec![],
}
Request::new("GET", "http://localhost:8000/querystring-params?param1=value1&param2=&param3=a%3Db&param4=1%2C2%2C3", vec![], vec![])
}
fn cookies_request() -> Request {
Request {
method: "GET".to_string(),
url: "http://localhost:8000/cookies".to_string(),
headers: vec![Header::new("Cookie", "cookie1=value1; cookie2=value2")],
body: vec![],
}
Request::new(
"GET",
"http://localhost:8000/cookies",
vec![Header::new("Cookie", "cookie1=value1; cookie2=value2")],
vec![],
)
}
#[test]
@ -245,36 +255,26 @@ mod tests {
#[test]
fn test_base_url() {
assert_eq!(
Request {
url: "http://localhost".to_string(),
method: String::new(),
headers: vec![],
body: vec![],
}
.base_url()
.unwrap(),
Request::new("", "http://localhost", vec![], vec![])
.base_url()
.unwrap(),
"http://localhost".to_string()
);
assert_eq!(
Request {
url: "http://localhost:8000/redirect-relative".to_string(),
method: String::new(),
headers: vec![],
body: vec![],
}
Request::new(
"",
"http://localhost:8000/redirect-relative",
vec![],
vec![]
)
.base_url()
.unwrap(),
"http://localhost:8000".to_string()
);
assert_eq!(
Request {
url: "https://localhost:8000".to_string(),
method: String::new(),
headers: vec![],
body: vec![],
}
.base_url()
.unwrap(),
Request::new("", "https://localhost:8000", vec![], vec![])
.base_url()
.unwrap(),
"https://localhost:8000".to_string()
);
}

View File

@ -20,6 +20,8 @@ use core::fmt;
use crate::http::core::*;
use crate::http::{header, Header};
/// Represents the HTTP request asked to be executed by our user (different from the runtime
/// executed HTTP request [`crate::http::Request`].
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RequestSpec {
pub method: Method,

View File

@ -21,7 +21,8 @@ use std::time::Duration;
use crate::http::certificate::Certificate;
use crate::http::{header, Header};
/// Represents an HTTP response.
/// Represents a runtime HTTP response.
/// This is a real response, that has been executed by our HTTP client.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Response {
pub version: HttpVersion,
@ -49,6 +50,27 @@ impl Default for Response {
}
impl Response {
/// Creates a new HTTP response
pub fn new(
version: HttpVersion,
status: u32,
headers: Vec<Header>,
body: Vec<u8>,
duration: Duration,
url: &str,
certificate: Option<Certificate>,
) -> Self {
Response {
version,
status,
headers,
body,
duration,
url: url.to_string(),
certificate,
}
}
/// Returns all header values.
pub fn get_header_values(&self, name: &str) -> Vec<String> {
header::get_values(&self.headers, name)