Skip to content

Commit

Permalink
Merge pull request #1105 from dusk-network/http-rusk-version
Browse files Browse the repository at this point in the history
Implement HTTP version Handshake
  • Loading branch information
herr-seppia authored Oct 26, 2023
2 parents 42c9966 + 72df460 commit fd3a267
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 44 deletions.
4 changes: 2 additions & 2 deletions rusk/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rusk"
version = "0.6.0"
version = "0.7.0-rc.0"
edition = "2021"
autobins = false

Expand Down Expand Up @@ -82,7 +82,7 @@ rusk-recovery = { version = "0.6", path = "../rusk-recovery", features = ["state
ff = { version = "0.13", default-features = false }

[build-dependencies]
rustc_tools_util = "=0.2.0"
rustc_tools_util = "0.3"

[features]
default = ["ephemeral"]
Expand Down
13 changes: 1 addition & 12 deletions rusk/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("cargo:rerun-if-changed=../Cargo.lock");

// Get crate version + commit + toolchain for `-v` arg support.
println!(
"cargo:rustc-env=GIT_HASH={}",
rustc_tools_util::get_commit_hash().unwrap_or_default()
);
println!(
"cargo:rustc-env=COMMIT_DATE={}",
rustc_tools_util::get_commit_date().unwrap_or_default()
);
println!(
"cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
rustc_tools_util::get_channel().unwrap_or_default()
);
rustc_tools_util::setup_version_info!();

Ok(())
}
4 changes: 1 addition & 3 deletions rusk/src/bin/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ use std::path::PathBuf;
use clap::builder::PossibleValuesParser;
use clap::Parser;

use crate::version::VERSION_BUILD;

#[derive(Parser, Debug)]
#[command(
author="Dusk Network B.V. All Rights Reserved.",
version = &VERSION_BUILD[..],
version = &rusk::VERSION_BUILD[..],
about = "Rusk server node",
)]
pub struct Args {
Expand Down
1 change: 0 additions & 1 deletion rusk/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ mod args;
mod config;
#[cfg(feature = "ephemeral")]
mod ephemeral;
mod version;

use clap::Parser;
use node::database::rocksdb;
Expand Down
35 changes: 23 additions & 12 deletions rusk/src/lib/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ use tungstenite::protocol::{CloseFrame, Message};
use futures_util::{stream, SinkExt, StreamExt};

use crate::chain::RuskNode;
use crate::Rusk;
use crate::{Rusk, VERSION};

use self::event::MessageRequest;

const RUSK_VERSION_HEADER: &str = "Rusk-Version";

pub struct HttpServer {
handle: task::JoinHandle<()>,
local_addr: SocketAddr,
Expand Down Expand Up @@ -92,6 +94,7 @@ impl HandleRequest for DataSources {
"Received {:?}:{} request",
request.event.target, request.event.topic
);
request.check_rusk_version()?;
match request.event.to_route() {
(Target::Contract(_), ..) | (_, "rusk", _) => {
self.rusk.handle_request(request).await
Expand Down Expand Up @@ -348,7 +351,7 @@ where
let (execution_request, is_binary) =
MessageRequest::from_request(req).await?;

let x_headers = execution_request.x_headers();
let mut resp_headers = execution_request.x_headers();

let (responder, mut receiver) = mpsc::unbounded_channel();
handle_execution(sources, execution_request, responder).await;
Expand All @@ -357,11 +360,16 @@ where
.recv()
.await
.expect("An execution should always return a response");
resp_headers.extend(execution_response.headers.clone());
let mut resp = execution_response.into_http(is_binary)?;

for (k, v) in x_headers {
for (k, v) in resp_headers {
let k = HeaderName::from_str(&k)?;
let v = HeaderValue::from_str(&v.to_string())?;
let v = match v {
serde_json::Value::String(s) => HeaderValue::from_str(&s),
serde_json::Value::Null => HeaderValue::from_str(""),
_ => HeaderValue::from_str(&v.to_string()),
}?;
resp.headers_mut().append(k, v);
}

Expand All @@ -376,7 +384,7 @@ async fn handle_execution<H>(
) where
H: HandleRequest,
{
let rsp = sources
let mut rsp = sources
.handle(&request)
.await
.map(|data| EventResponse {
Expand All @@ -386,6 +394,7 @@ async fn handle_execution<H>(
})
.unwrap_or_else(|e| request.to_error(e.to_string()));

rsp.set_header(RUSK_VERSION_HEADER, serde_json::json!(*VERSION));
let _ = responder.send(rsp);
}

Expand Down Expand Up @@ -495,27 +504,26 @@ mod tests {
data: RequestData::Text("Not used".into()),
topic: "stream".into(),
};
let headers: serde_json::Map<String, serde_json::Value> =
let request_x_header: serde_json::Map<String, serde_json::Value> =
serde_json::from_str(r#"{"X-requestid": "100"}"#)
.expect("headers to be serialized");

let request = MessageRequest {
event,
headers: headers.clone(),
headers: request_x_header.clone(),
};

let request = serde_json::to_string(&request).unwrap();

stream
.write_message(Message::Text(request))
.send(Message::Text(request))
.expect("Sending request to the server should succeed");

let mut responses = vec![];
// Vec::<ExecutionResponse>::with_capacity(request_num);

while responses.len() < STREAMED_DATA.len() {
let msg = stream
.read_message()
.read()
.expect("Response should be received without error");

let msg = match msg {
Expand All @@ -524,9 +532,12 @@ mod tests {
};
let response: EventResponse = serde_json::from_str(&msg)
.expect("Response should deserialize successfully");

let mut response_x_header = response.headers.clone();
response_x_header.retain(|k, _| k.to_lowercase().starts_with("x-"));
assert_eq!(
response.headers, headers,
"x- headers to be propagated back"
response_x_header, request_x_header,
"x-headers to be propagated back"
);
assert!(matches!(response.error, None), "There should be noerror");
match response.data {
Expand Down
48 changes: 43 additions & 5 deletions rusk/src/lib/http/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use super::RUSK_VERSION_HEADER;
use futures_util::{stream, StreamExt};
use hyper::header::{InvalidHeaderName, InvalidHeaderValue};
use hyper::Body;
use semver::{Version, VersionReq};
use serde::{Deserialize, Serialize};
use serde_with::{self, serde_as};
use std::collections::HashMap;
Expand Down Expand Up @@ -125,11 +127,16 @@ impl MessageRequest {
let headers = req
.headers()
.iter()
.filter_map(|(k, v)| {
let a = v.as_bytes();
serde_json::from_slice::<serde_json::Value>(a)
.ok()
.map(|v| (k.to_string(), v))
.map(|(k, v)| {
let v = if v.is_empty() {
serde_json::Value::Null
} else {
serde_json::from_slice::<serde_json::Value>(v.as_bytes())
.unwrap_or(serde_json::Value::String(
v.to_str().unwrap().to_string(),
))
};
(k.to_string().to_lowercase(), v)
})
.collect();
let (event, is_binary) = Event::from_request(req).await?;
Expand All @@ -138,6 +145,23 @@ impl MessageRequest {

Ok((req, is_binary))
}

pub fn check_rusk_version(&self) -> anyhow::Result<()> {
if let Some(v) = self.header(RUSK_VERSION_HEADER) {
let req = match v.as_str() {
Some(v) => VersionReq::from_str(v),
None => VersionReq::from_str(&v.to_string()),
}?;

let current = Version::from_str(&crate::VERSION)?;
if !req.matches(&current) {
return Err(anyhow::anyhow!(
"Mismatched rusk version: requested {req} - current {current}",
));
}
}
Ok(())
}
}

#[derive(Debug, Deserialize, Serialize)]
Expand Down Expand Up @@ -194,6 +218,20 @@ impl MessageResponse {

Ok(hyper::Response::new(body))
}

pub fn set_header(&mut self, key: &str, value: serde_json::Value) {
// search for the key in a case-insensitive way
let v = self
.headers
.iter_mut()
.find_map(|(k, v)| k.eq_ignore_ascii_case(key).then_some(v));

if let Some(v) = v {
*v = value;
} else {
self.headers.insert(key.into(), value);
}
}
}

#[derive(Debug, Serialize, Deserialize)]
Expand Down
3 changes: 3 additions & 0 deletions rusk/src/lib/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod chain;
pub mod error;
pub mod http;
pub mod prover;
mod version;
mod vm;

use dusk_bytes::DeserializableSlice;
Expand Down Expand Up @@ -44,6 +45,8 @@ use rusk_abi::{
use rusk_profile::to_rusk_state_id_path;
use sha3::{Digest, Sha3_256};

pub use version::{VERSION, VERSION_BUILD};

const A: usize = 4;

pub type Result<T, E = Error> = core::result::Result<T, E>;
Expand Down
22 changes: 13 additions & 9 deletions rusk/src/bin/version.rs → rusk/src/lib/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,29 @@
use std::sync::LazyLock;

use rustc_tools_util::VersionInfo;

#[inline]
pub(crate) fn show_version(info: VersionInfo) -> String {
let version = format!("{}.{}.{}", info.major, info.minor, info.patch);
pub(crate) fn show_version(verbose: bool) -> String {
let info = rustc_tools_util::get_version_info!();
let pre = std::env!("CARGO_PKG_VERSION_PRE");
let version = if pre.is_empty() {
format!("{}.{}.{}", info.major, info.minor, info.patch)
} else {
format!("{}.{}.{}-{}", info.major, info.minor, info.patch, pre)
};
let build = format!(
"{} {}",
info.commit_hash.unwrap_or_default(),
info.commit_date.unwrap_or_default()
);

if build.len() > 1 {
if verbose && build.trim().len() > 1 {
format!("{version} ({build})")
} else {
version
}
}

pub static VERSION_BUILD: LazyLock<String> = LazyLock::new(|| {
let info = rustc_tools_util::get_version_info!();
show_version(info)
});
pub static VERSION_BUILD: LazyLock<String> =
LazyLock::new(|| show_version(true));

pub static VERSION: LazyLock<String> = LazyLock::new(|| show_version(false));

0 comments on commit fd3a267

Please sign in to comment.