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

Add TLS support #87

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ Options:
-w, --wasm [variable=path] Binds variable to wasm located at path (default: [])
-c, --enable-cache Enables cache <BETA>
-r, --watch Watch the worker script and restart the worker when changes are detected
--tls-key <tlsKey> Optional. Path to encryption key for serving requests with TLS enabled. Must specify --tls-cert when using this option.
--tls-cert <tlsCert> Optional. Path to certificate for serving requests with TLS enabled. Must specify --tls-key when using this 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.
-h, --help output usage information
```

Expand Down
76 changes: 66 additions & 10 deletions bin/cloudworker.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ program
.option('-c, --enable-cache', 'Enables cache <BETA>', false)
.option('-r, --watch', 'Watch the worker script and restart the worker when changes are detected', false)
.option('-s, --set [variable.key=value]', '(Deprecated) Binds variable to a local implementation of Workers KV and sets key to value', collect, [])
.option('--tls-key <tlsKey>', 'Optional. Path to encryption key for serving requests with TLS enabled. Must specify --tls-cert when using this option.')
.option('--tls-cert <tlsCert>', 'Optional. Path to certificate for serving requests with TLS enabled. Must specify --tls-key when using this option.')
.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)
.action(f => { file = f })
.parse(process.argv)

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

const opts = {debug: program.debug, enableCache: program.enableCache, bindings: bindings}
let server = new Cloudworker(script, opts).listen(program.port)
if ((program.tlsKey && !program.tlsCert) || (!program.tlsKey && program.tlsCert)) {
console.error('Both --tls-key and --tls-cert must be set when using TLS.')
process.exit(1)
}

let tlsKey = ''
let tlsCert = ''
if (program.tlsKey && program.tlsCert) {
try {
tlsKey = fs.readFileSync(program.tlsKey)
tlsCert = fs.readFileSync(program.tlsCert)
} catch (err) {
console.error('Error reading TLS configuration')
console.error(err)
process.exit(1)
}
if (program.port === program.httpsPort) {
console.error('HTTP port and HTTPS port must be different')
process.exit(1)
}
}

console.log(`Listening on ${program.port}`)
const opts = {
debug: program.debug,
enableCache: program.enableCache,
bindings: bindings,
tlsKey: tlsKey,
tlsCert: tlsCert,
}
let worker = new Cloudworker(script, opts)
let server = worker.listen(program.port)
console.log(`Listening on ${program.port} for HTTP requests`)

let httpsServer = null
if (tlsKey && tlsCert) {
httpsServer = worker.httpsListen(program.httpsPort)
console.log(`Listening on ${program.httpsPort} for HTTPS requests`)
}

let stopping = false
let reloading = false
Expand All @@ -64,12 +101,23 @@ function run (file, wasmBindings) {
console.log('Changes to the worker script detected - reloading...')

server.close(() => {
if (stopping) return

if (stopping) {
if (httpsServer) {
httpsServer.close(() => { })
}
return
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks the return was dropped by this change. It's required so that a new server is created if stopping.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


worker = new Cloudworker(utils.read(fullpath), opts)
server = worker.listen(program.port)

if (httpsServer) {
httpsServer.close(() => {
httpsServer = worker.httpsListen(program.httpsPort)
})
}
reloading = false
console.log('Successfully reloaded!')

server = new Cloudworker(utils.read(fullpath), opts).listen(program.port)
console.log('Successfully reloaded server!')
})
})
}
Expand All @@ -80,8 +128,16 @@ function run (file, wasmBindings) {
stopping = true
console.log('\nShutting down...')
server.close(terminate)

if (reloading) server.on('close', terminate)
if (httpsServer) {
httpsServer.close(terminate)
}

if (reloading) {
server.on('close', terminate)
if (httpsServer) {
httpsServer.on('close', terminate)
}
}
}

function terminate () {
Expand Down
21 changes: 19 additions & 2 deletions lib/cloudworker.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const http = require('http')
const https = require('https')
const vm = require('vm')
const runtime = require('./runtime')
const EventEmitter = require('events')
Expand All @@ -7,13 +8,15 @@ const StubCacheFactory = require('./runtime/cache/stub')
const CacheFactory = require('./runtime/cache/cache')

class Cloudworker {
constructor (workerScript, {debug = false, bindings = {}, enableCache = false} = {}) {
constructor (workerScript, {debug = false, bindings = {}, enableCache = false, tlsKey = null, tlsCert = null} = {}) {
if (!workerScript || typeof workerScript !== 'string') {
throw new TypeError('worker script must be a string')
}

this.debug = debug
this.dispatcher = new EventEmitter()
this.tlsKey = tlsKey
this.tlsCert = tlsCert
const eventListener = (eventType, handler) => {
const wrapper = (event) => {
Promise.resolve(handler(event)).catch((error) => { event.onError(error) })
Expand Down Expand Up @@ -57,10 +60,24 @@ class Cloudworker {
return server.listen(...args)
}

httpsListen (...args) {
const options = {
key: this.tlsKey,
cert: this.tlsCert,
}
const server = https.createServer(options, this._handle.bind(this))
return server.listen(...args)
}

async _handle (req, res) {
const start = new Date()

var url = 'http://' + req.headers['host'] + req.url
let url = ''
if (!req.connection.encrypted) {
url = 'http://' + req.headers['host'] + req.url
} else {
url = 'https://' + req.headers['host'] + req.url
}

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