Skip to main content

rew_extensions/ext/http/
mod.rs

1use super::ExtensionTrait;
2use deno_core::{Extension, extension};
3
4// Copyright 2018-2025 the Deno authors. MIT license.
5
6use std::rc::Rc;
7
8use ::deno_http::http_create_conn_resource;
9use deno_core::OpState;
10use deno_core::ResourceId;
11use deno_core::error::ResourceError;
12use deno_core::op2;
13use deno_net::io::TcpStreamResource;
14
15
16pub const UNSTABLE_FEATURE_NAME: &str = "http";
17
18#[derive(Debug, thiserror::Error, deno_error::JsError)]
19pub enum HttpStartError {
20  #[class("Busy")]
21  #[error("TCP stream is currently in use")]
22  TcpStreamInUse,
23  #[class("Busy")]
24  #[error("TLS stream is currently in use")]
25  TlsStreamInUse,
26  #[class("Busy")]
27  #[error("Unix socket is currently in use")]
28  UnixSocketInUse,
29  #[class(generic)]
30  #[error(transparent)]
31  ReuniteTcp(#[from] tokio::net::tcp::ReuniteError),
32  #[cfg(unix)]
33  #[class(generic)]
34  #[error(transparent)]
35  ReuniteUnix(#[from] tokio::net::unix::ReuniteError),
36  #[class(inherit)]
37  #[error("{0}")]
38  Io(
39    #[from]
40    #[inherit]
41    std::io::Error,
42  ),
43  #[class(inherit)]
44  #[error(transparent)]
45  Resource(#[inherit] ResourceError),
46}
47
48#[op2(fast)]
49#[smi]
50fn op_http_start(
51  state: &mut OpState,
52  #[smi] tcp_stream_rid: ResourceId,
53) -> Result<ResourceId, HttpStartError> {
54  if let Ok(resource_rc) = state
55    .resource_table
56    .take::<TcpStreamResource>(tcp_stream_rid)
57  {
58    // This TCP connection might be used somewhere else. If it's the case, we cannot proceed with the
59    // process of starting a HTTP server on top of this TCP connection, so we just return a Busy error.
60    // See also: https://github.com/denoland/deno/pull/16242
61    let resource = Rc::try_unwrap(resource_rc).map_err(|_| HttpStartError::TcpStreamInUse)?;
62    let (read_half, write_half) = resource.into_inner();
63    let tcp_stream = read_half.reunite(write_half)?;
64    let addr = tcp_stream.local_addr()?;
65    return Ok(http_create_conn_resource(state, tcp_stream, addr, "http"));
66  }
67
68  // if let Ok(resource_rc) = state
69    // .resource_table
70    // .take::<TlsStreamResource>(tcp_stream_rid)
71  // {
72    // This TLS connection might be used somewhere else. If it's the case, we cannot proceed with the
73    // process of starting a HTTP server on top of this TLS connection, so we just return a Busy error.
74    // See also: https://github.com/denoland/deno/pull/16242
75    // let resource = Rc::try_unwrap(resource_rc).map_err(|_| HttpStartError::TlsStreamInUse)?;
76    // let (read_half, write_half) = resource.into_inner();
77    // let tls_stream = read_half.unsplit(write_half);
78    // let addr = tls_stream.local_addr()?;
79    // return Ok(http_create_conn_resource(state, tls_stream, addr, "https"));
80  // }
81
82  #[cfg(unix)]
83  if let Ok(resource_rc) = state
84    .resource_table
85    .take::<deno_net::io::UnixStreamResource>(tcp_stream_rid)
86  {
87    // This UNIX socket might be used somewhere else. If it's the case, we cannot proceed with the
88    // process of starting a HTTP server on top of this UNIX socket, so we just return a Busy error.
89    // See also: https://github.com/denoland/deno/pull/16242
90    let resource = Rc::try_unwrap(resource_rc).map_err(|_| HttpStartError::UnixSocketInUse)?;
91    let (read_half, write_half) = resource.into_inner();
92    let unix_stream = read_half.reunite(write_half)?;
93    let addr = unix_stream.local_addr()?;
94    return Ok(http_create_conn_resource(
95      state,
96      unix_stream,
97      addr,
98      "http+unix",
99    ));
100  }
101
102  Err(HttpStartError::Resource(ResourceError::BadResourceId))
103}
104
105extension!(
106  deno_http,
107  ops = [op_http_start],
108  esm = [ dir "src/ext/http", "00_serve.ts", "01_http.js", "02_websocket.ts" ],
109);
110impl ExtensionTrait<()> for deno_http {
111  fn init((): ()) -> Extension {
112    deno_http::init()
113  }
114}
115extension!(
116  http,
117  esm_entry_point = "ext:http/init_http.js",
118  esm = [ dir "src/ext/http", "init_http.js" ],
119);
120impl ExtensionTrait<()> for http {
121  fn init((): ()) -> Extension {
122    http::init()
123  }
124}
125
126impl ExtensionTrait<()> for ::deno_http::deno_http {
127  fn init((): ()) -> Extension {
128    ::deno_http::deno_http::init(::deno_http::Options::default())
129  }
130}
131
132pub fn extensions(is_snapshot: bool) -> Vec<Extension> {
133  vec![
134    deno_http::build((), is_snapshot),
135    ::deno_http::deno_http::build((), true),
136    http::build((), is_snapshot),
137  ]
138}