Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement HttpHead as new RADType #2402

Open
wants to merge 11 commits into
base: 2.0-base
Choose a base branch
from
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "witnet"
version = "1.6.7"
version = "1.7.0"
aesedepece marked this conversation as resolved.
Show resolved Hide resolved
authors = ["Witnet Foundation <[email protected]>"]
publish = false
repository = "witnet/witnet-rust"
Expand Down
2 changes: 1 addition & 1 deletion bridges/centralized-ethereum/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "witnet-centralized-ethereum-bridge"
version = "1.6.7"
version = "1.7.0"
authors = ["Witnet Foundation <[email protected]>"]
edition = "2018"

Expand Down
2 changes: 1 addition & 1 deletion data_structures/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ authors = ["Witnet Foundation <[email protected]>"]
description = "data structures component"
edition = "2021"
name = "witnet_data_structures"
version = "1.6.7"
version = "1.7.0"
workspace = ".."

[features]
Expand Down
13 changes: 11 additions & 2 deletions data_structures/src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1645,11 +1645,17 @@
/// HTTP POST request
#[serde(rename = "HTTP-POST")]
HttpPost,
/// HTTP HEAD request
#[serde(rename = "HTTP-HEAD")]
HttpHead,
}

impl RADType {
pub fn is_http(&self) -> bool {
matches!(self, RADType::HttpGet | RADType::HttpPost)
matches!(
self,
RADType::HttpGet | RADType::HttpPost | RADType::HttpHead
)
}
}

Expand Down Expand Up @@ -1701,7 +1707,7 @@
pub script: Vec<u8>,
/// Body of a HTTP-POST request
pub body: Vec<u8>,
/// Extra headers of a HTTP-GET or HTTP-POST request
/// Extra headers of a HTTP-GET, HTTP-POST or HTTP-HEAD request
pub headers: Vec<(String, String)>,
}

Expand Down Expand Up @@ -1810,6 +1816,9 @@
&[Field::Body, Field::Headers],
)
}
RADType::HttpHead => {
check(&[Field::Kind, Field::Url, Field::Script], &[Field::Headers])
}
}
}

Expand Down Expand Up @@ -2681,7 +2690,7 @@
for input in &vt_tx.body.inputs {
self.output_pointer_map
.entry(input.output_pointer)
.or_insert_with(Vec::new)

Check failure on line 2693 in data_structures/src/chain/mod.rs

View workflow job for this annotation

GitHub Actions / build_ubuntu

use of `or_insert_with` to construct default value

Check failure on line 2693 in data_structures/src/chain/mod.rs

View workflow job for this annotation

GitHub Actions / build_ubuntu

use of `or_insert_with` to construct default value
.push(vt_tx.hash());
}

Expand All @@ -2706,7 +2715,7 @@
for input in &dr_tx.body.inputs {
self.output_pointer_map
.entry(input.output_pointer)
.or_insert_with(Vec::new)

Check failure on line 2718 in data_structures/src/chain/mod.rs

View workflow job for this annotation

GitHub Actions / build_ubuntu

use of `or_insert_with` to construct default value

Check failure on line 2718 in data_structures/src/chain/mod.rs

View workflow job for this annotation

GitHub Actions / build_ubuntu

use of `or_insert_with` to construct default value
.push(dr_tx.hash());
}

Expand Down
2 changes: 2 additions & 0 deletions data_structures/src/proto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ impl ProtobufConvert for chain::RADType {
chain::RADType::HttpGet => witnet::DataRequestOutput_RADRequest_RADType::HttpGet,
chain::RADType::Rng => witnet::DataRequestOutput_RADRequest_RADType::Rng,
chain::RADType::HttpPost => witnet::DataRequestOutput_RADRequest_RADType::HttpPost,
chain::RADType::HttpHead => witnet::DataRequestOutput_RADRequest_RADType::HttpHead,
}
}

Expand All @@ -60,6 +61,7 @@ impl ProtobufConvert for chain::RADType {
witnet::DataRequestOutput_RADRequest_RADType::HttpGet => chain::RADType::HttpGet,
witnet::DataRequestOutput_RADRequest_RADType::Rng => chain::RADType::Rng,
witnet::DataRequestOutput_RADRequest_RADType::HttpPost => chain::RADType::HttpPost,
witnet::DataRequestOutput_RADRequest_RADType::HttpHead => chain::RADType::HttpHead,
})
}
}
Expand Down
4 changes: 2 additions & 2 deletions data_structures/src/serialization_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ struct RADRetrieveSerializationHelperJson {
/// Body of a HTTP-POST request
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub body: Vec<u8>,
/// Extra headers of a HTTP-GET or HTTP-POST request
/// Extra headers of a HTTP-GET, HTTP-HEAD or HTTP-POST request
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub headers: Vec<(String, String)>,
}
Expand All @@ -377,7 +377,7 @@ struct RADRetrieveSerializationHelperBincode {
pub script: Vec<u8>,
/// Body of a HTTP-POST request
pub body: Vec<u8>,
/// Extra headers of a HTTP-GET or HTTP-POST request
/// Extra headers of a HTTP-GET, HTTP-HEAD or HTTP-POST request
pub headers: Vec<(String, String)>,
}

Expand Down
2 changes: 1 addition & 1 deletion net/src/client/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ pub struct WitnetHttpResponse {

impl WitnetHttpResponse {
#[inline]
/// Simple wrapper around `isahc::Response::status`.
/// Simple wrapper around `isahc::Response`.
pub fn inner(self) -> isahc::Response<isahc::AsyncBody> {
self.res
}
Expand Down
2 changes: 1 addition & 1 deletion node/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "witnet_node"
version = "1.6.7"
version = "1.7.0"
authors = ["Witnet Foundation <[email protected]>"]
workspace = ".."
description = "node component"
Expand Down
2 changes: 1 addition & 1 deletion rad/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "witnet_rad"
version = "0.3.2"
version = "0.3.3"
authors = ["Witnet Foundation <[email protected]>"]
edition = "2021"
workspace = ".."
Expand Down
124 changes: 111 additions & 13 deletions rad/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,10 @@ pub fn run_retrieval_with_data_report(
settings: RadonScriptExecutionSettings,
) -> Result<RadonReport<RadonTypes>> {
match retrieve.kind {
RADType::HttpGet => string_response_with_data_report(retrieve, response, context, settings),
RADType::Rng => rng_response_with_data_report(response, context),
RADType::HttpPost => {
RADType::HttpGet | RADType::HttpPost | RADType::HttpHead => {
string_response_with_data_report(retrieve, response, context, settings)
}
RADType::Rng => rng_response_with_data_report(response, context),
_ => Err(RadError::UnknownRetrieval),
}
}
Expand All @@ -214,7 +213,7 @@ pub fn run_retrieval_with_data(
.map(RadonReport::into_inner)
}

/// Handle generic HTTP (GET/POST) response
/// Handle generic HTTP (GET/POST/HEAD) response
async fn http_response(
retrieve: &RADRetrieve,
context: &mut ReportContext<RadonTypes>,
Expand Down Expand Up @@ -259,6 +258,10 @@ async fn http_response(
WitnetHttpBody::from(retrieve.body.clone()),
)
}
RADType::HttpHead => (
builder.method("HEAD").uri(&retrieve.url),
WitnetHttpBody::empty(),
),
_ => panic!(
"Called http_response with invalid retrieval kind {:?}",
retrieve.kind
Expand Down Expand Up @@ -298,13 +301,21 @@ async fn http_response(

// If at some point we want to support the retrieval of non-UTF8 data (e.g. raw bytes), this is
// where we need to decide how to read the response body
let (_parts, mut body) = response.into_parts();
let mut response_string = String::default();
body.read_to_string(&mut response_string)
.await
.map_err(|x| RadError::HttpOther {
message: x.to_string(),
})?;

let (parts, mut body) = response.into_parts();
match retrieve.kind {
RADType::HttpHead => {
response_string = format!("{:?}", parts.headers);
aesedepece marked this conversation as resolved.
Show resolved Hide resolved
}
_ => {
body.read_to_string(&mut response_string)
.await
.map_err(|x| RadError::HttpOther {
message: x.to_string(),
})?;
}
}

let result = run_retrieval_with_data_report(retrieve, &response_string, context, settings);

Expand Down Expand Up @@ -354,9 +365,10 @@ pub async fn run_retrieval_report(
context.set_active_wips(active_wips);

match retrieve.kind {
RADType::HttpGet => http_response(retrieve, context, settings, client).await,
RADType::HttpGet | RADType::HttpHead | RADType::HttpPost => {
http_response(retrieve, context, settings, client).await
}
RADType::Rng => rng_response(context, settings).await,
RADType::HttpPost => http_response(retrieve, context, settings, client).await,
_ => Err(RadError::UnknownRetrieval),
}
}
Expand Down Expand Up @@ -649,7 +661,7 @@ fn validate_header(name: &str, value: &str) -> Result<()> {
Err(RadError::InvalidHttpHeader {
name: name.to_string(),
value: value.to_string(),
error: error_message.to_string(),
error: error_message,
})
} else {
Ok(())
Expand Down Expand Up @@ -829,6 +841,40 @@ mod tests {

use super::*;

#[test]
fn test_run_http_head_retrieval() {
let script_r = Value::Array(vec![
Value::Integer(RadonOpCodes::StringParseJSONMap as i128),
Value::Array(vec![
Value::Integer(RadonOpCodes::MapGetString as i128),
Value::Text("etag".to_string()),
]),
]);
let packed_script_r = serde_cbor::to_vec(&script_r).unwrap();
println!("{:?}", packed_script_r);

let retrieve = RADRetrieve {
kind: RADType::HttpHead,
url: "https://witnet.io/_nuxt/img/dragon_reading.a37f8cb.png".to_string(),
aesedepece marked this conversation as resolved.
Show resolved Hide resolved
script: packed_script_r,
body: vec![],
headers: vec![],
};
let response = r#"{"date": "Wed, 11 Oct 2023 15:18:42 GMT", "content-type": "image/png", "content-length": "498219", "x-origin-cache": "HIT", "last-modified": "Mon, 28 Aug 2023 13:30:41 GMT", "access-control-allow-origin": "*", "etag": "\"64eca181-79a2b\"", "expires": "Wed, 11 Oct 2023 15:28:41 GMT", "cache-control": "max-age=1800", "x-proxy-cache": "MISS", "x-github-request-id": "6750:35DB:BF8211:FEFD2B:652602FA", "via": "1.1 varnish", "x-served-by": "cache-hnd18736-HND", "x-cache": "MISS", "x-cache-hits": "0", "x-timer": "S1696989946.496383,VS0,VE487", "vary": "Accept-Encoding", "x-fastly-request-id": "118bdfd8a926cbdc781bc23079c3dc07a22d2223", "cf-cache-status": "REVALIDATED", "accept-ranges": "bytes", "report-to": "{\"endpoints\":[{\"url\":\"https:\/\/a.nel.cloudflare.com\/report\/v3?s=FlzxKRCYYN4SL0x%2FraG7ugKCqdC%2BeQqVrucvsfeDWf%2F7A0Nv9fv7TYRgU0WL4k1kbZyxt%2B04VjOyv0XK55sF37GEPwXHE%2FdXnoFlWutID762k2ktcX6hUml6oNk%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}", "nel": "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}", "strict-transport-security": "max-age=0", "x-content-type-options": "nosniff", "server": "cloudflare", "cf-ray": "814813bf3a73f689-NRT", "alt-svc": "h3=\":443\"; ma=86400"}"#;
let result = run_retrieval_with_data(
&retrieve,
response,
RadonScriptExecutionSettings::disable_all(),
current_active_wips(),
)
.unwrap();

match result {
RadonTypes::String(_) => {}
err => panic!("Error in run_retrieval: {:?}", err),
}
}

#[test]
fn test_run_retrieval() {
let script_r = Value::Array(vec![
Expand Down Expand Up @@ -1526,6 +1572,58 @@ mod tests {
}
}

#[test]
fn test_try_data_request_http_get_non_ascii_header_key() {
let script_r = Value::Array(vec![]);
let packed_script_r = serde_cbor::to_vec(&script_r).unwrap();
let body = Vec::from(String::from(""));
let headers = vec![("ñ", "value")];
let headers = headers
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect();
let request = RADRequest {
time_lock: 0,
retrieve: vec![RADRetrieve {
kind: RADType::HttpGet,
url: String::from("http://127.0.0.1"),
aesedepece marked this conversation as resolved.
Show resolved Hide resolved
script: packed_script_r,
body,
headers,
}],
aggregate: RADAggregate {
filters: vec![],
reducer: RadonReducers::Mode as u32,
},
tally: RADTally {
filters: vec![],
reducer: RadonReducers::Mode as u32,
},
};
let report = try_data_request(
&request,
RadonScriptExecutionSettings::enable_all(),
None,
None,
);
let tally_result = report.tally.into_inner();

assert_eq!(
tally_result,
RadonTypes::RadonError(
RadonError::try_from(RadError::UnhandledIntercept {
inner: Some(Box::new(RadError::InvalidHttpHeader {
name: "ñ".to_string(),
value: "value".to_string(),
error: "invalid HTTP header name".to_string()
})),
message: None
})
.unwrap()
)
);
}

#[test]
fn test_try_data_request_http_post_non_ascii_header_key() {
let script_r = Value::Array(vec![]);
Expand Down
3 changes: 2 additions & 1 deletion schemas/witnet/witnet.proto
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ message DataRequestOutput {
HttpGet = 1;
Rng = 2;
HttpPost = 3;
HttpHead = 4;
}
message RADFilter {
uint32 op = 1;
Expand All @@ -133,7 +134,7 @@ message DataRequestOutput {
bytes script = 3;
// Body of HTTP-POST request
bytes body = 4;
// Extra headers for HTTP-GET and HTTP-POST requests
// Extra headers for HTTP-GET, HTTP-HEAD and HTTP-POST requests
repeated StringPair headers = 5;
}
message RADAggregate {
Expand Down
2 changes: 1 addition & 1 deletion toolkit/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "witnet_toolkit"
version = "1.6.7"
version = "1.7.0"
authors = ["Adán SDPC <[email protected]>"]
edition = "2021"

Expand Down
Loading
Loading