chore: initial sanitized public snapshot
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
use base64::Engine;
|
||||
use sha1::{Digest, Sha1};
|
||||
|
||||
use super::{
|
||||
RpcServerConfig,
|
||||
http_surface::{
|
||||
HttpRequest, contains_ascii_case_insensitive, header_value, http_response,
|
||||
http_response_with_headers, normalized_rpc_path,
|
||||
},
|
||||
};
|
||||
|
||||
/// Computes the `Sec-WebSocket-Accept` value for a client-provided handshake key.
|
||||
fn websocket_accept_value(key: &str) -> String {
|
||||
let mut sha1 = Sha1::new();
|
||||
sha1.update(key.as_bytes());
|
||||
sha1.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
let digest = sha1.finalize();
|
||||
base64::engine::general_purpose::STANDARD.encode(digest)
|
||||
}
|
||||
|
||||
/// Builds the HTTP upgrade response for a successful RPC WebSocket handshake.
|
||||
pub(super) fn websocket_upgrade_response(
|
||||
config: &RpcServerConfig,
|
||||
request: &HttpRequest,
|
||||
) -> Vec<u8> {
|
||||
if !config.enable_websocket_rpc {
|
||||
return http_response("404 Not Found", "text/plain", b"websocket-rpc disabled");
|
||||
}
|
||||
if normalized_rpc_path(&request.path) != "/jsonrpc" {
|
||||
return http_response("404 Not Found", "text/plain", b"unknown websocket path");
|
||||
}
|
||||
if !request.method.eq_ignore_ascii_case("GET") {
|
||||
return http_response(
|
||||
"405 Method Not Allowed",
|
||||
"text/plain",
|
||||
b"websocket upgrade requires GET",
|
||||
);
|
||||
}
|
||||
let Some(key) = header_value(&request.headers, "sec-websocket-key") else {
|
||||
return http_response(
|
||||
"400 Bad Request",
|
||||
"text/plain",
|
||||
b"missing sec-websocket-key",
|
||||
);
|
||||
};
|
||||
if !header_value(&request.headers, "upgrade")
|
||||
.is_some_and(|value| value.eq_ignore_ascii_case("websocket"))
|
||||
{
|
||||
return http_response(
|
||||
"400 Bad Request",
|
||||
"text/plain",
|
||||
b"missing websocket upgrade header",
|
||||
);
|
||||
}
|
||||
if !header_value(&request.headers, "connection")
|
||||
.is_some_and(|value| contains_ascii_case_insensitive(value, "upgrade"))
|
||||
{
|
||||
return http_response(
|
||||
"400 Bad Request",
|
||||
"text/plain",
|
||||
b"missing connection upgrade header",
|
||||
);
|
||||
}
|
||||
if header_value(&request.headers, "sec-websocket-version")
|
||||
.is_none_or(|value| value.trim() != "13")
|
||||
{
|
||||
return http_response_with_headers(
|
||||
"426 Upgrade Required",
|
||||
Some("text/plain"),
|
||||
&[("Sec-WebSocket-Version", "13".to_owned())],
|
||||
b"unsupported websocket version",
|
||||
);
|
||||
}
|
||||
|
||||
let mut headers = vec![
|
||||
("Upgrade", "websocket".to_owned()),
|
||||
("Connection", "Upgrade".to_owned()),
|
||||
("Sec-WebSocket-Accept", websocket_accept_value(key)),
|
||||
];
|
||||
if let Some(origin) = &config.allow_origin {
|
||||
headers.push(("Access-Control-Allow-Origin", origin.clone()));
|
||||
}
|
||||
http_response_with_headers("101 Switching Protocols", None, &headers, b"")
|
||||
}
|
||||
Reference in New Issue
Block a user