1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-28 16:20:57 -05:00

fix(runtime): use host header for inspector websocket URL (#20171)

If a `host` header is specified, use that for the generated websocket
URLs.

Fixes #20087
This commit is contained in:
Matt Mastracci 2023-08-15 16:30:33 -06:00 committed by GitHub
parent 4380a09a05
commit 71d2f4cb97
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 19 deletions

View file

@ -9,6 +9,8 @@ use deno_runtime::deno_fetch::reqwest;
use fastwebsockets::FragmentCollector;
use fastwebsockets::Frame;
use fastwebsockets::WebSocket;
use http::header::HOST;
use hyper::header::HeaderValue;
use hyper::upgrade::Upgraded;
use hyper::Body;
use hyper::Request;
@ -704,14 +706,34 @@ async fn inspector_json() {
let mut url = ws_url.clone();
let _ = url.set_scheme("http");
url.set_path("/json");
let resp = reqwest::get(url).await.unwrap();
let client = reqwest::Client::new();
// Ensure that the webSocketDebuggerUrl matches the host header
for (host, expected) in [
(None, ws_url.as_str()),
(Some("some.random.host"), "ws://some.random.host/"),
(Some("some.random.host:1234"), "ws://some.random.host:1234/"),
(Some("[::1]:1234"), "ws://[::1]:1234/"),
] {
let mut req = reqwest::Request::new(reqwest::Method::GET, url.clone());
if let Some(host) = host {
req
.headers_mut()
.insert(HOST, HeaderValue::from_static(host));
}
let resp = client.execute(req).await.unwrap();
assert_eq!(resp.status(), reqwest::StatusCode::OK);
let endpoint_list: Vec<deno_core::serde_json::Value> =
serde_json::from_str(&resp.text().await.unwrap()).unwrap();
let matching_endpoint = endpoint_list
.iter()
.find(|e| e["webSocketDebuggerUrl"] == ws_url.as_str());
let matching_endpoint = endpoint_list.iter().find(|e| {
e["webSocketDebuggerUrl"]
.as_str()
.unwrap()
.contains(expected)
});
assert!(matching_endpoint.is_some());
}
child.kill().unwrap();
}

View file

@ -16,6 +16,7 @@ use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::task::spawn;
use deno_core::url::Url;
use deno_core::InspectorMsg;
use deno_core::InspectorSessionProxy;
use deno_core::JsRuntime;
@ -189,11 +190,12 @@ fn handle_ws_request(
fn handle_json_request(
inspector_map: Rc<RefCell<HashMap<Uuid, InspectorInfo>>>,
host: Option<String>,
) -> http::Result<http::Response<hyper::Body>> {
let data = inspector_map
.borrow()
.values()
.map(|info| info.get_json_metadata())
.map(move |info| info.get_json_metadata(&host))
.collect::<Vec<_>>();
http::Response::builder()
.status(http::StatusCode::OK)
@ -224,7 +226,7 @@ async fn server(
.map(|info| {
eprintln!(
"Debugger listening on {}",
info.get_websocket_debugger_url()
info.get_websocket_debugger_url(&info.host.to_string())
);
eprintln!("Visit chrome://inspect to connect to the debugger.");
if info.wait_for_session {
@ -258,6 +260,17 @@ async fn server(
future::ok::<_, Infallible>(hyper::service::service_fn(
move |req: http::Request<hyper::Body>| {
future::ready({
// If the host header can make a valid URL, use it
let host = req
.headers()
.get("host")
.and_then(|host| host.to_str().ok())
.and_then(|host| Url::parse(&format!("http://{host}")).ok())
.and_then(|url| match (url.host(), url.port()) {
(Some(host), Some(port)) => Some(format!("{host}:{port}")),
(Some(host), None) => Some(format!("{host}")),
_ => None,
});
match (req.method(), req.uri().path()) {
(&http::Method::GET, path) if path.starts_with("/ws/") => {
handle_ws_request(req, Rc::clone(&inspector_map))
@ -266,10 +279,10 @@ async fn server(
handle_json_version_request(json_version_response.clone())
}
(&http::Method::GET, "/json") => {
handle_json_request(Rc::clone(&inspector_map))
handle_json_request(Rc::clone(&inspector_map), host)
}
(&http::Method::GET, "/json/list") => {
handle_json_request(Rc::clone(&inspector_map))
handle_json_request(Rc::clone(&inspector_map), host)
}
_ => http::Response::builder()
.status(http::StatusCode::NOT_FOUND)
@ -381,27 +394,29 @@ impl InspectorInfo {
}
}
fn get_json_metadata(&self) -> Value {
fn get_json_metadata(&self, host: &Option<String>) -> Value {
let host_listen = format!("{}", self.host);
let host = host.as_ref().unwrap_or(&host_listen);
json!({
"description": "deno",
"devtoolsFrontendUrl": self.get_frontend_url(),
"devtoolsFrontendUrl": self.get_frontend_url(host),
"faviconUrl": "https://deno.land/favicon.ico",
"id": self.uuid.to_string(),
"title": self.get_title(),
"type": "node",
"url": self.url.to_string(),
"webSocketDebuggerUrl": self.get_websocket_debugger_url(),
"webSocketDebuggerUrl": self.get_websocket_debugger_url(host),
})
}
pub fn get_websocket_debugger_url(&self) -> String {
format!("ws://{}/ws/{}", &self.host, &self.uuid)
pub fn get_websocket_debugger_url(&self, host: &str) -> String {
format!("ws://{}/ws/{}", host, &self.uuid)
}
fn get_frontend_url(&self) -> String {
fn get_frontend_url(&self, host: &str) -> String {
format!(
"devtools://devtools/bundled/js_app.html?ws={}/ws/{}&experiments=true&v8only=true",
&self.host, &self.uuid
host, &self.uuid
)
}