mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-22 15:42:20 +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 {},
|
||||
InvalidUtf8,
|
||||
InvalidDecoding { charset: String },
|
||||
InvalidCharset { charset: String },
|
||||
|
||||
// Query
|
||||
QueryHeaderNotFound,
|
||||
@ -160,10 +161,12 @@ impl FormatError for Error {
|
||||
RunnerError::QueryInvalidJsonpathExpression { .. } => "Invalid jsonpath".to_string(),
|
||||
RunnerError::PredicateType { .. } => "Assert - Inconsistent predicate type".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::UnrenderableVariable { .. } => "Unrenderable Variable".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::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::InvalidCharset { charset } => format!("The charset '{}' is not valid", charset),
|
||||
RunnerError::AssertFailure { actual, expected, .. } => format!("actual: {}\nexpected: {}", actual, expected),
|
||||
RunnerError::VariableNotDefined { name } => format!("You must set the variable {}", name),
|
||||
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;
|
||||
mod entry;
|
||||
pub mod file;
|
||||
mod http_response;
|
||||
mod json;
|
||||
pub mod log;
|
||||
mod predicate;
|
||||
|
Loading…
Reference in New Issue
Block a user