Repository: denoland/deno
Pull request: fix(ext/ws): send User-Agent in WS handshake

Fixes #30757

Changed files:
filename: ext/fetch/lib.rs
patch: @@ -63,6 +63,7 @@ use deno_tls::TlsKeysHolder;
 use deno_tls::rustls::RootCertStore;
 pub use fs_fetch_handler::FsFetchHandler;
 use http::Extensions;
+use http::HeaderMap;
 use http::Method;
 use http::Uri;
 use http::header::ACCEPT;
@@ -1347,12 +1348,34 @@ impl std::error::Error for ClientSendError {
   }
 }
 
+pub trait CommonRequest {
+  fn uri(&self) -> &Uri;
+  fn headers_mut(&mut self) -> &mut HeaderMap;
+}
+
+impl CommonRequest for http::Request<ReqBody> {
+  fn uri(&self) -> &Uri {
+    self.uri()
+  }
+
+  fn headers_mut(&mut self) -> &mut HeaderMap {
+    self.headers_mut()
+  }
+}
+
+impl CommonRequest for http::request::Builder {
+  fn uri(&self) -> &Uri {
+    http::request::Builder::uri_ref(self).expect("uri not set")
+  }
+
+  fn headers_mut(&mut self) -> &mut HeaderMap {
+    http::request::Builder::headers_mut(self).expect("headers not set")
+  }
+}
+
 impl Client {
   /// Injects common headers like User-Agent and Proxy-Authorization.
-  pub fn inject_common_headers(
-    &self,
-    mut req: http::Request<ReqBody>,
-  ) -> http::Request<ReqBody> {
+  pub fn inject_common_headers(&self, req: &mut impl CommonRequest) {
     req
       .headers_mut()
       .entry(USER_AGENT)
@@ -1361,15 +1384,13 @@ impl Client {
     if let Some(auth) = self.connector.proxies.http_forward_auth(req.uri()) {
       req.headers_mut().insert(PROXY_AUTHORIZATION, auth.clone());
     }
-
-    req
   }
 
   pub async fn send(
     self,
     mut req: http::Request<ReqBody>,
   ) -> Result<http::Response<ResBody>, ClientSendError> {
-    req = self.inject_common_headers(req);
+    self.inject_common_headers(&mut req);
 
     req.headers_mut().entry(ACCEPT).or_insert(STAR_STAR);
 

filename: ext/websocket/lib.rs
patch: @@ -302,6 +302,7 @@ async fn handshake_http1(
 
   let mut request = Request::builder().method(Method::GET).uri(req_uri);
 
+  client.inject_common_headers(&mut request);
   request =
     populate_common_request_headers(request, protocols, headers, allow_host)?;
 
@@ -342,6 +343,7 @@ async fn handshake_http2(
   let mut request = Request::builder();
   request = request.method(Method::CONNECT);
   request = request.uri(uri);
+  client.inject_common_headers(&mut request);
   request =
     populate_common_request_headers(request, protocols, headers, allow_host)?;
   request = request.extension(h2::ext::Protocol::from("websocket"));

filename: tests/util/server/src/servers/ws.rs
patch: @@ -18,6 +18,7 @@ use h2::Reason;
 use h2::RecvStream;
 use h2::server::Handshake;
 use h2::server::SendResponse;
+use http_body_util::Empty;
 use hyper::Method;
 use hyper::Request;
 use hyper::Response;
@@ -149,6 +150,13 @@ where
 {
   let service = hyper::service::service_fn(
     move |mut req: http::Request<hyper::body::Incoming>| async move {
+      if req.headers().get("user-agent").is_none() {
+        return Response::builder()
+          .status(StatusCode::BAD_REQUEST)
+          .body(Empty::new())
+          .map_err(|e| anyhow!("Error creating response: {}", e));
+      }
+
       let (response, upgrade_fut) = fastwebsockets::upgrade::upgrade(&mut req)
         .map_err(|e| anyhow!("Error upgrading websocket connection: {}", e))?;