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 = "2.0.0"
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 = "2.0.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 = "2.0.0"
workspace = ".."

[features]
Expand Down
17 changes: 13 additions & 4 deletions data_structures/src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1645,11 +1645,17 @@ pub enum RADType {
/// 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 struct RADRetrieve {
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 @@ impl RADRetrieve {
&[Field::Body, Field::Headers],
)
}
RADType::HttpHead => {
check(&[Field::Kind, Field::Url, Field::Script], &[Field::Headers])
}
}
}

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

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

Expand Down
2 changes: 1 addition & 1 deletion data_structures/src/data_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ impl DataRequestPool {

self.data_requests_by_epoch
.entry(epoch)
.or_insert_with(HashSet::new)
.or_default()
.insert(dr_hash);
self.data_request_pool.insert(dr_hash, dr_state);

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 = "2.0.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
123 changes: 110 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,39 @@ 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();

let retrieve = RADRetrieve {
kind: RADType::HttpHead,
url: "https://en.wikipedia.org/static/images/icons/wikipedia.png".to_string(),
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 +1571,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
Loading
Loading