Skip to content

Commit

Permalink
Move method between Request / Response.
Browse files Browse the repository at this point in the history
This is a preliminary work for issue #628.
  • Loading branch information
jcamiel committed Jun 30, 2022
1 parent 038d23c commit 67ef7c7
Show file tree
Hide file tree
Showing 9 changed files with 277 additions and 66 deletions.
42 changes: 1 addition & 41 deletions packages/hurl/src/http/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ impl Client {
url,
method: (&request.method).to_string(),
headers: request_headers,
body: vec![], // TODO: we don't record the request body for the moment.
};
let response = Response {
version,
Expand Down Expand Up @@ -638,47 +639,6 @@ pub fn decode_header(data: &[u8]) -> Option<String> {
}
}

impl Response {
///
/// Log a response body as text if possible, or a slice of body bytes.
///
/// # Arguments
///
/// * `response` - The HTTP response
fn log_body(&self) {
eprintln!("* Response:");

// We try to decode the HTTP body as text if the response has a text kind content type.
// If it ok, we print each line of the body in debug format. Otherwise, we
// print the body first 64 bytes.
if let Some(content_type) = self.content_type() {
if !content_type.contains("text") {
self.log_bytes(64);
return;
}
}
match self.text() {
Ok(text) => text.split('\n').for_each(|l| eprintln!("* {}", l)),
Err(_) => self.log_bytes(64),
}
}

///
/// Log a response bytes with a maximum size.
///
/// # Arguments
///
/// * `max` - The maximum number if bytes to log
fn log_bytes(&self, max: usize) {
let bytes = if self.body.len() > max {
&self.body[..max]
} else {
&self.body
};
eprintln!("* Bytes <{}...>", hex::encode(bytes))
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
52 changes: 52 additions & 0 deletions packages/hurl/src/http/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Hurl (https://hurl.dev)
* Copyright (C) 2022 Orange
*
* 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.
*
*/
use crate::http::Header;

/// Debug log HTTP request headers.
pub fn log_headers_out(headers: &[Header]) {
for header in headers {
eprintln!("> {}", header);
}
}

/// Debug log HTTP response headers.
pub fn log_headers_in(headers: &[Header]) {
for header in headers {
eprintln!("< {}", header);
}
}

/// Debug log text.
pub fn log_text(text: &str) {
text.split('\n').for_each(|l| eprintln!("* {}", l))
}

/// Debug log bytes with a maximum size.
///
/// # Arguments
///
/// * `bytes`- the bytes to log
/// * `max` - The maximum number if bytes to log
pub fn log_bytes(bytes: &[u8], max: usize) {
let bytes = if bytes.len() > max {
&bytes[..max]
} else {
bytes
};
eprintln!("* Bytes <{}...>", hex::encode(bytes))
}
55 changes: 55 additions & 0 deletions packages/hurl/src/http/mimetype.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Hurl (https://hurl.dev)
* Copyright (C) 2022 Orange
*
* 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.
*
*/

/// Returns true if binary data with this `content_type` can be decoded as text.
pub fn is_kind_of_text(content_type: &str) -> bool {
content_type.contains("text/")
|| content_type.contains("application/json")
|| content_type.contains("application/xml")
|| content_type.contains("application/x-www-form-urlencoded")
}

/// Returns true if this `content_type` is HTML.
pub fn is_html(content_type: &str) -> bool {
content_type.starts_with("text/html")
}

/// Extracts charset from mime-type String
pub fn charset(mime_type: &str) -> Option<String> {
mime_type
.find("charset=")
.map(|index| mime_type[(index + 8)..].to_string())
}

#[cfg(test)]
pub mod tests {
use super::*;

#[test]
pub fn test_charset() {
assert_eq!(
charset("text/plain; charset=utf-8"),
Some("utf-8".to_string())
);
assert_eq!(
charset("text/plain; charset=ISO-8859-1"),
Some("ISO-8859-1".to_string())
);
assert_eq!(charset("text/plain;"), None);
}
}
5 changes: 5 additions & 0 deletions packages/hurl/src/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,18 @@ pub use self::version::libcurl_version_info;
mod client;
mod cookie;
mod core;
mod debug;
mod error;
mod header;
mod mimetype;
mod options;
mod request;
mod request_debug;
mod request_decoding;
mod request_spec;
mod request_spec_curl_args;
mod response;
mod response_cookie;
mod response_debug;
mod response_decoding;
mod version;
20 changes: 18 additions & 2 deletions packages/hurl/src/http/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,20 @@

use super::core::*;
use super::Header;
use crate::http::header;
use url::Url;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Request {
pub url: String,
pub method: String,
pub headers: Vec<Header>,
pub body: Vec<u8>,
}

impl Request {
pub fn query_string_params(self) -> Vec<Param> {
/// 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");
let mut params = vec![];
for (name, value) in u.query_pairs() {
Expand All @@ -41,13 +44,23 @@ impl Request {
params
}

pub fn cookies(self) -> Vec<RequestCookie> {
/// Returns a list of request headers cookie.
///
/// see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie
pub fn cookies(&self) -> Vec<RequestCookie> {
self.headers
.iter()
.filter(|h| h.name.as_str() == "Cookie")
.flat_map(|h| parse_cookies(h.value.as_str().trim()))
.collect()
}

/// Returns optional Content-type header value.
pub fn content_type(&self) -> Option<String> {
header::get_values(&self.headers, "Content-Type")
.get(0)
.cloned()
}
}

fn parse_cookies(s: &str) -> Vec<RequestCookie> {
Expand Down Expand Up @@ -90,6 +103,7 @@ pub mod tests {
value: "hurl/1.0".to_string(),
},
],
body: vec![],
}
}

Expand All @@ -98,6 +112,7 @@ pub mod tests {
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![],
}
}

Expand All @@ -109,6 +124,7 @@ pub mod tests {
name: "Cookie".to_string(),
value: "cookie1=value1; cookie2=value2".to_string(),
}],
body: vec![],
}
}

Expand Down
45 changes: 45 additions & 0 deletions packages/hurl/src/http/request_debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Hurl (https://hurl.dev)
* Copyright (C) 2022 Orange
*
* 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.
*
*/

use crate::http::{debug, mimetype, Request};

impl Request {
/// Log request headers.
pub fn log_headers(&self) {
debug::log_headers_out(&self.headers)
}

/// Log request body.
pub fn log_body(&self) {
debug::log_text("Request:");

// We try to decode the HTTP body as text if the response has a text kind content type.
// If it ok, we print each line of the body in debug format. Otherwise, we
// print the body first 64 bytes.
if let Some(content_type) = self.content_type() {
if !mimetype::is_kind_of_text(&content_type) {
debug::log_bytes(&self.body, 64);
return;
}
}
match self.text() {
Ok(text) => debug::log_text(&text),
Err(_) => debug::log_bytes(&self.body, 64),
}
}
}
49 changes: 49 additions & 0 deletions packages/hurl/src/http/request_decoding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Hurl (https://hurl.dev)
* Copyright (C) 2022 Orange
*
* 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.
*
*/

use crate::http::{mimetype, HttpError, Request};
use encoding::{DecoderTrap, EncodingRef};

impl Request {
/// Returns character encoding of the HTTP request.
fn character_encoding(&self) -> Result<EncodingRef, HttpError> {
match self.content_type() {
Some(content_type) => match mimetype::charset(&content_type) {
Some(charset) => {
match encoding::label::encoding_from_whatwg_label(charset.as_str()) {
None => Err(HttpError::InvalidCharset { charset }),
Some(enc) => Ok(enc),
}
}
None => Ok(encoding::all::UTF_8),
},
None => Ok(encoding::all::UTF_8),
}
}

/// Returns response body as text.
pub fn text(&self) -> Result<String, HttpError> {
let encoding = self.character_encoding()?;
match encoding.decode(&self.body, DecoderTrap::Strict) {
Ok(s) => Ok(s),
Err(_) => Err(HttpError::InvalidDecoding {
charset: encoding.name().to_string(),
}),
}
}
}
Loading

0 comments on commit 67ef7c7

Please sign in to comment.