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

Commit

Permalink
Add TLS support
Browse files Browse the repository at this point in the history
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/
  • Loading branch information
supermari0 committed May 20, 2019
1 parent 93f853d commit b25003a
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 12 deletions.
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
}

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

0 comments on commit b25003a

Please sign in to comment.