-
-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathworker.ts
More file actions
61 lines (51 loc) · 2.22 KB
/
worker.ts
File metadata and controls
61 lines (51 loc) · 2.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/// <reference path="./worker.d.ts" />
import { connect } from 'cloudflare:sockets';
// note: as at 11 September 2023, Safari needs:
// compatibility_flags = [ "no_web_socket_compression" ]
// in wrangler.toml (or disabled 'NSURLSession WebSockets' under Develop > Experimental Features)
export default {
fetch(req: Request, env: any, ctx: ExecutionContext) {
// various sanity checks
if (req.method !== 'GET') return new Response('Expected GET request', { status: 405 });
const upgradeHeader = req.headers.get('Upgrade');
if (upgradeHeader !== 'websocket') return new Response('Expected header: "Upgrade: websocket"', { status: 426 });
const url = new URL(req.url);
const address = url.searchParams.get('address');
if (typeof address !== 'string')
return new Response('Expected search param: ?address=example.com:443', { status: 400 });
const addressRegExp = env.ADDRESS_REGEXP;
if (!addressRegExp) return new Response('Environment variable ADDRESS_REGEXP not set', { status: 500 });
if (!new RegExp(addressRegExp).test(address)) return new Response('Address is not permitted', { status: 400 });
// open TCP socket
const socket = connect(address);
const socketWriter = socket.writable.getWriter();
// open WebSocket
const { 0: wsClient, 1: wsServer } = new WebSocketPair();
wsServer.accept();
// deal with data from WebSocket to TCP
wsServer.addEventListener('message', (event) => {
const writePromise = socketWriter.write(event.data);
ctx.waitUntil(writePromise);
});
wsServer.addEventListener('close', () => {
const closePromise = socket.close();
ctx.waitUntil(closePromise);
});
// deal with data from TCP to WebSocket
const wsWritableStream = new WritableStream({
write(chunk) {
wsServer.send(chunk);
},
close() {
wsServer.close(1000 /* normal closure */, 'TCP connection closed');
},
abort(reason) {
wsServer.close(1001 /* endpoint going away */, reason);
},
});
const pipePromise = socket.readable.pipeTo(wsWritableStream);
ctx.waitUntil(pipePromise);
// return WebSocket to client
return new Response(null, { status: 101, webSocket: wsClient });
},
};