mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-30 00:37:52 +03:00
Merge pull request #17 from Orange-OpenSource/feature/text-decoding
Get Http response body as text
This commit is contained in:
commit
1adaf37b08
@ -105,6 +105,7 @@ pub enum RunnerError {
|
|||||||
//??CaptureError {},
|
//??CaptureError {},
|
||||||
InvalidUtf8,
|
InvalidUtf8,
|
||||||
InvalidDecoding { charset: String },
|
InvalidDecoding { charset: String },
|
||||||
|
InvalidCharset { charset: String },
|
||||||
|
|
||||||
// Query
|
// Query
|
||||||
QueryHeaderNotFound,
|
QueryHeaderNotFound,
|
||||||
@ -161,9 +162,11 @@ impl FormatError for Error {
|
|||||||
RunnerError::PredicateType { .. } => "Assert - Inconsistent predicate type".to_string(),
|
RunnerError::PredicateType { .. } => "Assert - Inconsistent predicate type".to_string(),
|
||||||
RunnerError::SubqueryInvalidInput { .. } => "Subquery error".to_string(),
|
RunnerError::SubqueryInvalidInput { .. } => "Subquery error".to_string(),
|
||||||
RunnerError::InvalidDecoding { ..} => "Invalid Decoding".to_string(),
|
RunnerError::InvalidDecoding { ..} => "Invalid Decoding".to_string(),
|
||||||
|
RunnerError::InvalidCharset { ..} => "Invalid Charset".to_string(),
|
||||||
RunnerError::AssertFailure { .. } => "Assert Failure".to_string(),
|
RunnerError::AssertFailure { .. } => "Assert Failure".to_string(),
|
||||||
RunnerError::UnrenderableVariable { .. } => "Unrenderable Variable".to_string(),
|
RunnerError::UnrenderableVariable { .. } => "Unrenderable Variable".to_string(),
|
||||||
RunnerError::NoQueryResult { .. } => "No query result".to_string(),
|
RunnerError::NoQueryResult { .. } => "No query result".to_string(),
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,6 +192,7 @@ impl FormatError for Error {
|
|||||||
RunnerError::PredicateType { .. } => "predicate type inconsistent with value return by query".to_string(),
|
RunnerError::PredicateType { .. } => "predicate type inconsistent with value return by query".to_string(),
|
||||||
RunnerError::SubqueryInvalidInput => "Type from query result and subquery do not match".to_string(),
|
RunnerError::SubqueryInvalidInput => "Type from query result and subquery do not match".to_string(),
|
||||||
RunnerError::InvalidDecoding { charset } => format!("The body can not be decoded with charset '{}'", charset),
|
RunnerError::InvalidDecoding { charset } => format!("The body can not be decoded with charset '{}'", charset),
|
||||||
|
RunnerError::InvalidCharset { charset } => format!("The charset '{}' is not valid", charset),
|
||||||
RunnerError::AssertFailure { actual, expected, .. } => format!("actual: {}\nexpected: {}", actual, expected),
|
RunnerError::AssertFailure { actual, expected, .. } => format!("actual: {}\nexpected: {}", actual, expected),
|
||||||
RunnerError::VariableNotDefined { name } => format!("You must set the variable {}", name),
|
RunnerError::VariableNotDefined { name } => format!("You must set the variable {}", name),
|
||||||
RunnerError::UnrenderableVariable { value } => format!("value {} can not be rendered", value),
|
RunnerError::UnrenderableVariable { value } => format!("value {} can not be rendered", value),
|
||||||
|
182
src/runner/http_response.rs
Normal file
182
src/runner/http_response.rs
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* hurl (https://hurl.dev)
|
||||||
|
* Copyright (C) 2020 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::libcurl::core::Response;
|
||||||
|
use super::core::RunnerError;
|
||||||
|
use encoding::{EncodingRef, DecoderTrap};
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// get body content as text from http response
|
||||||
|
/// used by query
|
||||||
|
///
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl Response {
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return optional Content-type header value
|
||||||
|
///
|
||||||
|
fn content_type(&self) -> Option<String> {
|
||||||
|
for header in self.headers.clone() {
|
||||||
|
if header.name.to_lowercase() == "content-type" {
|
||||||
|
return Some(header.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Return encoding of the response
|
||||||
|
///
|
||||||
|
fn encoding(&self) -> Result<EncodingRef, RunnerError> {
|
||||||
|
match self.content_type() {
|
||||||
|
Some(content_type) => {
|
||||||
|
match mime_charset(content_type) {
|
||||||
|
Some(charset) => match encoding::label::encoding_from_whatwg_label(charset.as_str()) {
|
||||||
|
None => Err(RunnerError::InvalidCharset { charset }),
|
||||||
|
Some(enc) => Ok(enc)
|
||||||
|
},
|
||||||
|
None => Ok(encoding::all::UTF_8),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Ok(encoding::all::UTF_8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text(&self) -> Result<String, RunnerError> {
|
||||||
|
let encoding = self.encoding()?;
|
||||||
|
match encoding.decode(&self.body, DecoderTrap::Strict) {
|
||||||
|
Ok(s) => Ok(s),
|
||||||
|
Err(_) => Err(RunnerError::InvalidDecoding { charset: encoding.name().to_string() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Extract charset from mime-type String
|
||||||
|
///
|
||||||
|
fn mime_charset(mime_type: String) -> Option<String> {
|
||||||
|
match mime_type.find("charset=") {
|
||||||
|
None => None,
|
||||||
|
Some(index) => {
|
||||||
|
Some(mime_type[(index + 8)..].to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::http::libcurl::core::{Version, Header};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_charset() {
|
||||||
|
assert_eq!(mime_charset("text/plain; charset=utf-8".to_string()), Some("utf-8".to_string()));
|
||||||
|
assert_eq!(mime_charset("text/plain; charset=ISO-8859-1".to_string()), Some("ISO-8859-1".to_string()));
|
||||||
|
assert_eq!(mime_charset("text/plain;".to_string()), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn hello_response() -> Response {
|
||||||
|
Response {
|
||||||
|
version: Version::Http10,
|
||||||
|
status: 200,
|
||||||
|
headers: vec![],
|
||||||
|
body: b"Hello World!".to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn utf8_encoding_response() -> Response {
|
||||||
|
Response {
|
||||||
|
version: Version::Http10,
|
||||||
|
status: 200,
|
||||||
|
headers: vec![
|
||||||
|
Header { name: "Content-Type".to_string(), value: "text/plain; charset=utf-8".to_string() }
|
||||||
|
],
|
||||||
|
body: vec![0x63, 0x61, 0x66, 0xc3, 0xa9],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn latin1_encoding_response() -> Response {
|
||||||
|
Response {
|
||||||
|
version: Version::Http10,
|
||||||
|
status: 200,
|
||||||
|
headers: vec![
|
||||||
|
Header { name: "Content-Type".to_string(), value: "text/plain; charset=ISO-8859-1".to_string() }
|
||||||
|
],
|
||||||
|
body: vec![0x63, 0x61, 0x66, 0xe9],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_content_type() {
|
||||||
|
assert_eq!(hello_response().content_type(), None);
|
||||||
|
assert_eq!(utf8_encoding_response().content_type(), Some("text/plain; charset=utf-8".to_string()));
|
||||||
|
assert_eq!(latin1_encoding_response().content_type(), Some("text/plain; charset=ISO-8859-1".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_encoding() {
|
||||||
|
assert_eq!(hello_response().encoding().unwrap().name(), "utf-8");
|
||||||
|
assert_eq!(utf8_encoding_response().encoding().unwrap().name(), "utf-8");
|
||||||
|
assert_eq!(latin1_encoding_response().encoding().unwrap().name(), "windows-1252");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_text() {
|
||||||
|
assert_eq!(hello_response().text().unwrap(), "Hello World!".to_string());
|
||||||
|
assert_eq!(utf8_encoding_response().text().unwrap(), "café".to_string());
|
||||||
|
assert_eq!(latin1_encoding_response().text().unwrap(), "café".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_invalid_charset() {
|
||||||
|
assert_eq!(Response {
|
||||||
|
version: Version::Http10,
|
||||||
|
status: 200,
|
||||||
|
headers: vec![
|
||||||
|
Header { name: "Content-Type".to_string(), value:"test/plain; charset=xxx".to_string()}
|
||||||
|
],
|
||||||
|
body: b"Hello World!".to_vec(),
|
||||||
|
}.encoding().err().unwrap(), RunnerError::InvalidCharset { charset: "xxx".to_string()});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_invalid_decoding() {
|
||||||
|
assert_eq!(Response {
|
||||||
|
version: Version::Http10,
|
||||||
|
status: 200,
|
||||||
|
headers: vec![],
|
||||||
|
body: vec![0x63, 0x61, 0x66, 0xe9],
|
||||||
|
}.text().err().unwrap(), RunnerError::InvalidDecoding { charset: "utf-8".to_string()});
|
||||||
|
|
||||||
|
assert_eq!(Response {
|
||||||
|
version: Version::Http10,
|
||||||
|
status: 200,
|
||||||
|
headers: vec![
|
||||||
|
Header { name: "Content-Type".to_string(), value: "text/plain; charset=ISO-8859-1".to_string() }
|
||||||
|
],
|
||||||
|
body: vec![0x63, 0x61, 0x66, 0xc3, 0xa9],
|
||||||
|
}.text().unwrap(), "café".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -30,6 +30,7 @@ mod cookie;
|
|||||||
pub mod core;
|
pub mod core;
|
||||||
mod entry;
|
mod entry;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
|
mod http_response;
|
||||||
mod json;
|
mod json;
|
||||||
pub mod log;
|
pub mod log;
|
||||||
mod predicate;
|
mod predicate;
|
||||||
|
Loading…
Reference in New Issue
Block a user