Skip to content

Commit

Permalink
client: support custom HTTP headers ✅
Browse files Browse the repository at this point in the history
closes #9

Co-Authored-By: Jannis R <[email protected]>
  • Loading branch information
xiaoyun94 and derhuerst committed Feb 25, 2024
1 parent e949dbe commit 4e2ea0f
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 8 deletions.
22 changes: 19 additions & 3 deletions cli/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,23 @@ const mri = require('mri')
const pkg = require('../package.json')

const argv = mri(process.argv.slice(2), {
boolean: ['help', 'h', 'version', 'v']
boolean: ['help', 'h', 'version', 'v'],
alias : {H: 'header'}
})

if (argv.help || argv.h) {
process.stdout.write(`
Usage:
tcp-over-websockets <tunnel-url> <tunnelled-target> <port-to-listen-on>
tcp-over-websockets [options] <tunnel-url> <tunnelled-target> <port-to-listen-on>
Arguments:
tunnel-url The WebSocket address of the tunnel server.
tunnelled-target The hostname & port to let the tunnel server connect to.
port-to-listen-on The (local) port to expose the tunnel on.
Options:
-H, --header <header> Pass custom header(s) to tunnel server
Example:
tcp-over-websockets wss://example.org localhost:22 8022
tcp-over-websockets --header "Cookie:FOOL" wss://example.org localhost:22 8022
\n`)
process.exit(0)
}
Expand All @@ -40,7 +44,19 @@ if (!target) showError('missing target argument')
const port = argv._[2]
if (!port) showError('missing port argument')

startClient(tunnel, target, port, (err) => {
const headers = {}
const headerArgs = Array.isArray(argv.header) ? argv.header : [argv.header]
for (const arg of headerArgs) {
// we follow curl's mechanism here
// https://github.com/curl/curl/blob/d5b0fee39a7898dac42cb4fc64e35f5bc085e766/lib/headers.c#L200-L219
const match = /(?<=\w):\s+(?=.)/.exec(arg);
if (!match) showError(`invalid --header value: '${arg}'`)
const name = arg.slice(0, match.index)
const val = arg.slice(match.index + match[0].length)
headers[name] = val
}

startClient(tunnel, target, port, {headers}, (err) => {
if (err) showError(err)
else console.info(`tunneling ${target} via ${tunnel} & exposing it on port ${port}`)
})
8 changes: 6 additions & 2 deletions client.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
const {createServer} = require('net')
const {tunnelTo} = require('./tunnel')

const startClient = (tunnel, target, port, cb) => {
const tcpServer = createServer(tunnelTo(tunnel, target))
const startClient = (tunnel, target, port, opt, cb) => {
if (arguments.length === 4 && 'function' === typeof opt) {
cb = opt
opt = {}
}
const tcpServer = createServer(tunnelTo(tunnel, target, opt))

tcpServer.listen(port, cb)
return tcpServer
Expand Down
6 changes: 5 additions & 1 deletion test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ httpServer.listen(5000, (err) => {
const server = startServer(8080, (err) => {
if (err) return showError(err)

const client = startClient('ws://localhost:8080', 'localhost:5000', 5001, (err) => {
const headers = {
foo: 'BaR',
hello: 'world',
}
const client = startClient('ws://localhost:8080', 'localhost:5000', 5001, {headers}, (err) => {
if (err) return showError(err)

httpGet('http://localhost:5001', (res) => {
Expand Down
4 changes: 2 additions & 2 deletions tunnel.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ const ws = require('websocket-stream')
const pipe = require('pump')
const debug = require('debug')('tcp-over-websockets:client')

const tunnelTo = (tunnel, target) => (local) => {
const remote = ws(tunnel + (tunnel.slice(-1) === '/' ? '' : '/') + target)
const tunnelTo = (tunnel, target, opt) => (local) => {
const remote = ws(tunnel + (tunnel.slice(-1) === '/' ? '' : '/') + target, opt)

const onError = (err) => {
if (err) debug(err)
Expand Down

0 comments on commit 4e2ea0f

Please sign in to comment.