Skip to content
This repository was archived by the owner on Jun 6, 2024. It is now read-only.

Commit e2edb35

Browse files
committed
Add TLS support
This adds support for processing HTTPS requests on a separate port from the usual HTTP requests. It does so by adding options for specifying the path to a TLS key and a TLS certificate. This can be useful for testing worker scripts that do things like custom redirects depending on whether the user is making an encrypted request or not. Note: This PR does not yet set special `request.cf` attributes such as `tlsVersion` and `tlsCipher` as described here: https://developers.cloudflare.com/workers/reference/request-attributes/
1 parent 93f853d commit e2edb35

File tree

3 files changed

+87
-12
lines changed

3 files changed

+87
-12
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ Options:
4242
-w, --wasm [variable=path] Binds variable to wasm located at path (default: [])
4343
-c, --enable-cache Enables cache <BETA>
4444
-r, --watch Watch the worker script and restart the worker when changes are detected
45+
--tls-key <tlsKey> Optional. Path to encryption key for serving requests with TLS enabled. Must specify --tls-cert when using this option.
46+
--tls-cert <tlsCert> Optional. Path to certificate for serving requests with TLS enabled. Must specify --tls-key when using this option.
47+
--https-port <httpsPort> Optional. Port to listen on for HTTPS requests. Must specify --tls-cert and --tls-key when using this option. May not be the same value as --port.
4548
-h, --help output usage information
4649
```
4750

bin/cloudworker.js

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ program
2424
.option('-c, --enable-cache', 'Enables cache <BETA>', false)
2525
.option('-r, --watch', 'Watch the worker script and restart the worker when changes are detected', false)
2626
.option('-s, --set [variable.key=value]', '(Deprecated) Binds variable to a local implementation of Workers KV and sets key to value', collect, [])
27+
.option('--tls-key <tlsKey>', 'Optional. Path to encryption key for serving requests with TLS enabled. Must specify --tls-cert when using this option.')
28+
.option('--tls-cert <tlsCert>', 'Optional. Path to certificate for serving requests with TLS enabled. Must specify --tls-key when using this option.')
29+
.option('--https-port <httpsPort>', 'Optional. Port to listen on for HTTPS requests. Must specify --tls-cert and --tls-key when using this option. May not be the same value as --port.', 3001)
2730
.action(f => { file = f })
2831
.parse(process.argv)
2932

@@ -50,10 +53,44 @@ function run (file, wasmBindings) {
5053
// Add a warning log for deprecation
5154
if (program.set.length > 0) console.warn('Warning: Flag --set is now deprecated, please use --kv-set instead')
5255

53-
const opts = {debug: program.debug, enableCache: program.enableCache, bindings: bindings}
54-
let server = new Cloudworker(script, opts).listen(program.port)
56+
if ((program.tlsKey && !program.tlsCert) || (!program.tlsKey && program.tlsCert)) {
57+
console.error('Both --tls-key and --tls-cert must be set when using TLS.')
58+
process.exit(1)
59+
}
60+
61+
let tlsKey = ''
62+
let tlsCert = ''
63+
if (program.tlsKey && program.tlsCert) {
64+
try {
65+
tlsKey = fs.readFileSync(program.tlsKey)
66+
tlsCert = fs.readFileSync(program.tlsCert)
67+
} catch (err) {
68+
console.error('Error reading TLS configuration')
69+
console.error(err)
70+
process.exit(1)
71+
}
72+
if (program.port === program.httpsPort) {
73+
console.error('HTTP port and HTTPS port must be different')
74+
process.exit(1)
75+
}
76+
}
5577

56-
console.log(`Listening on ${program.port}`)
78+
const opts = {
79+
debug: program.debug,
80+
enableCache: program.enableCache,
81+
bindings: bindings,
82+
tlsKey: tlsKey,
83+
tlsCert: tlsCert,
84+
}
85+
let worker = new Cloudworker(script, opts)
86+
let server = worker.listen(program.port)
87+
console.log(`Listening on ${program.port} for HTTP requests`)
88+
89+
let httpsServer = null
90+
if (tlsKey && tlsCert) {
91+
httpsServer = worker.httpsListen(program.httpsPort)
92+
console.log(`Listening on ${program.httpsPort} for HTTPS requests`)
93+
}
5794

5895
let stopping = false
5996
let reloading = false
@@ -64,12 +101,22 @@ function run (file, wasmBindings) {
64101
console.log('Changes to the worker script detected - reloading...')
65102

66103
server.close(() => {
67-
if (stopping) return
68-
104+
if (stopping) {
105+
if (httpsServer) {
106+
httpsServer.close(() => { })
107+
}
108+
}
109+
110+
worker = new Cloudworker(utils.read(fullpath), opts)
111+
server = worker.listen(program.port)
112+
113+
if (httpsServer) {
114+
httpsServer.close(() => {
115+
httpsServer = worker.httpsListen(program.httpsPort)
116+
})
117+
}
69118
reloading = false
70-
console.log('Successfully reloaded!')
71-
72-
server = new Cloudworker(utils.read(fullpath), opts).listen(program.port)
119+
console.log('Successfully reloaded server!')
73120
})
74121
})
75122
}
@@ -80,8 +127,16 @@ function run (file, wasmBindings) {
80127
stopping = true
81128
console.log('\nShutting down...')
82129
server.close(terminate)
83-
84-
if (reloading) server.on('close', terminate)
130+
if (httpsServer) {
131+
httpsServer.close(terminate)
132+
}
133+
134+
if (reloading) {
135+
server.on('close', terminate)
136+
if (httpsServer) {
137+
httpsServer.on('close', terminate)
138+
}
139+
}
85140
}
86141

87142
function terminate () {

lib/cloudworker.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const http = require('http')
2+
const https = require('https')
23
const vm = require('vm')
34
const runtime = require('./runtime')
45
const EventEmitter = require('events')
@@ -7,13 +8,15 @@ const StubCacheFactory = require('./runtime/cache/stub')
78
const CacheFactory = require('./runtime/cache/cache')
89

910
class Cloudworker {
10-
constructor (workerScript, {debug = false, bindings = {}, enableCache = false} = {}) {
11+
constructor (workerScript, {debug = false, bindings = {}, enableCache = false, tlsKey = null, tlsCert = null} = {}) {
1112
if (!workerScript || typeof workerScript !== 'string') {
1213
throw new TypeError('worker script must be a string')
1314
}
1415

1516
this.debug = debug
1617
this.dispatcher = new EventEmitter()
18+
this.tlsKey = tlsKey
19+
this.tlsCert = tlsCert
1720
const eventListener = (eventType, handler) => {
1821
const wrapper = (event) => {
1922
Promise.resolve(handler(event)).catch((error) => { event.onError(error) })
@@ -57,10 +60,24 @@ class Cloudworker {
5760
return server.listen(...args)
5861
}
5962

63+
httpsListen (...args) {
64+
const options = {
65+
key: this.tlsKey,
66+
cert: this.tlsCert,
67+
}
68+
const server = https.createServer(options, this._handle.bind(this))
69+
return server.listen(...args)
70+
}
71+
6072
async _handle (req, res) {
6173
const start = new Date()
6274

63-
var url = 'http://' + req.headers['host'] + req.url
75+
let url = ''
76+
if (!req.connection.encrypted) {
77+
url = 'http://' + req.headers['host'] + req.url
78+
} else {
79+
url = 'https://' + req.headers['host'] + req.url
80+
}
6481

6582
let body = null
6683
if (req.method !== 'GET' && req.method !== 'HEAD') {

0 commit comments

Comments
 (0)