1use std::rc::Rc;
4
5use deno_core::op2;
6use deno_core::OpState;
7use deno_core::ResourceId;
8use deno_http::http_create_conn_resource;
9use deno_net::io::TcpStreamResource;
10use deno_net::ops_tls::TlsStreamResource;
11
12pub const UNSTABLE_FEATURE_NAME: &str = "http";
13
14deno_core::extension!(deno_http_runtime, ops = [op_http_start],);
15
16#[derive(Debug, thiserror::Error)]
17pub enum HttpStartError {
18 #[error("TCP stream is currently in use")]
19 TcpStreamInUse,
20 #[error("TLS stream is currently in use")]
21 TlsStreamInUse,
22 #[error("Unix socket is currently in use")]
23 UnixSocketInUse,
24 #[error(transparent)]
25 ReuniteTcp(#[from] tokio::net::tcp::ReuniteError),
26 #[cfg(unix)]
27 #[error(transparent)]
28 ReuniteUnix(#[from] tokio::net::unix::ReuniteError),
29 #[error("{0}")]
30 Io(#[from] std::io::Error),
31 #[error(transparent)]
32 Other(deno_core::error::AnyError),
33}
34
35#[op2(fast)]
36#[smi]
37fn op_http_start(
38 state: &mut OpState,
39 #[smi] tcp_stream_rid: ResourceId,
40) -> Result<ResourceId, HttpStartError> {
41 if let Ok(resource_rc) = state
42 .resource_table
43 .take::<TcpStreamResource>(tcp_stream_rid)
44 {
45 let resource = Rc::try_unwrap(resource_rc)
49 .map_err(|_| HttpStartError::TcpStreamInUse)?;
50 let (read_half, write_half) = resource.into_inner();
51 let tcp_stream = read_half.reunite(write_half)?;
52 let addr = tcp_stream.local_addr()?;
53 return Ok(http_create_conn_resource(state, tcp_stream, addr, "http"));
54 }
55
56 if let Ok(resource_rc) = state
57 .resource_table
58 .take::<TlsStreamResource>(tcp_stream_rid)
59 {
60 let resource = Rc::try_unwrap(resource_rc)
64 .map_err(|_| HttpStartError::TlsStreamInUse)?;
65 let (read_half, write_half) = resource.into_inner();
66 let tls_stream = read_half.unsplit(write_half);
67 let addr = tls_stream.local_addr()?;
68 return Ok(http_create_conn_resource(state, tls_stream, addr, "https"));
69 }
70
71 #[cfg(unix)]
72 if let Ok(resource_rc) = state
73 .resource_table
74 .take::<deno_net::io::UnixStreamResource>(tcp_stream_rid)
75 {
76 let resource = Rc::try_unwrap(resource_rc)
80 .map_err(|_| HttpStartError::UnixSocketInUse)?;
81 let (read_half, write_half) = resource.into_inner();
82 let unix_stream = read_half.reunite(write_half)?;
83 let addr = unix_stream.local_addr()?;
84 return Ok(http_create_conn_resource(
85 state,
86 unix_stream,
87 addr,
88 "http+unix",
89 ));
90 }
91
92 Err(HttpStartError::Other(deno_core::error::bad_resource_id()))
93}