关于Deno实现HTTP Tunnel的问题

我是初学者,刚高考完想做一个HTTP Tunnel。下面的代码能运行,但运行几秒就崩了qwq,而且这个错误死活捕获不到

PS C:\Users\hcy\Desktop\test> deno run -A .\test.ts
error: Uncaught (in promise) Interrupted: operation canceled
    at async Object.pull (ext:deno_web/06_streams.js:798:27)
const decoder = new TextDecoder();
const encoder = new TextEncoder();
const listener = Deno.listen({ port: 8100 });
for await (const conn of listener) {
  const a = new Uint8Array(256);
  await conn.read(a);
  const b = decoder.decode(a);
  if (b.startsWith("CONNECT")) {
    const host = (b.match(/Host:\s*([^\s]+)/) as RegExpMatchArray)[1].split(
      ":",
    );
    const hostname = host[0];
    const port = parseInt(host[1]);
    const connect = await Deno.connect({ hostname, port });
    connect.setKeepAlive(true);
    await conn.write(encoder.encode("HTTP/1.1 200\r\n\r\n"));
    conn.readable.pipeTo(connect.writable).catch(console.log);
    connect.readable.pipeTo(conn.writable).catch(console.log);
  }
}

还有一个问题:
如何在同一个端口上监听connect和http请求?
我注意到用Deno.serveHttp(conn)后原始连接就不能用了,不会要手搓http吧qwq

那个错误捕获到了,改了代码没保存结果没发现。程序可以正常代理了,这段话也是用代理发的,不过还是不知道怎么在同一个端口上监听connect和http请求

const decoder = new TextDecoder();
const encoder = new TextEncoder();
const listener = Deno.listen({ port: 8100 });
for await (const conn of listener) {
  let b = "";
  while (true) {
    const a = new Uint8Array(64);
    await conn.read(a);
    const n = decoder.decode(a);
    // console.log(a);
    if (isEOF(a)) break;
    b += n;
  }

  if (b.startsWith("CONNECT")) {
    try {
      const host = (b.match(/Host:\s*([^\s]+)/) as RegExpMatchArray)[1].split(
        ":",
      );
      const hostname = host[0];
      const port = parseInt(host[1]);
      const connect = await Deno.connect({ hostname, port });
      await conn.write(encoder.encode("HTTP/1.1 200\r\n\r\n"));
      conn.readable.pipeTo(connect.writable).catch((_) => {});
      connect.readable.pipeTo(conn.writable).catch((_) => {});
    } catch (_) {
    }
  }
}

function isEOF(data: Uint8Array) {
  if (data.at(-1) === 0) return true;
  if (
    data.at(-1) === 10 && data.at(-2) === 13 &&
    data.at(-3) === 10 && data.at(-4) === 13
  ) {
    return true;
  }
}

成熟了一点点

你可以用Deno.serveHttp监听HTTP请求,然后在收到CONNECT请求之后使用Deno.upgradeHttp获取底层TCP连接,参见Deno.upgradeHttp

1 个赞

这个是我做的:https://deno.land/x/silu

Deno.upgradeHttp 现在已经被删除了

现在可以临时用 Deno[Deno.internal].upgradeHttpRaw 函数。等 RFC: Deno.upgradeHttpConnect API 落地之后就原生支持 CONNECT 请求了