pinokiod 8.2.31 → 8.2.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -74,8 +74,6 @@ class Forwarders {
74
74
  const label = String(dnsName).split('.')[0]
75
75
  const target = `${this.scheme}://${dnsName}:${port}`
76
76
  const proxy = httpProxy.createProxyServer({ target, agent: this.agent(), changeOrigin: true, secure: true, ws: true })
77
- proxy.on('proxyReq', (proxyReq) => { proxyReq.setHeader(FORWARDED_HEADER, '1') })
78
- proxy.on('proxyReqWs', (proxyReq) => { proxyReq.setHeader(FORWARDED_HEADER, '1') })
79
77
  proxy.on('error', (error, req, res) => {
80
78
  const message = `Could not reach ${dnsName}: ${error && error.message ? error.message : error}`
81
79
  if (res && typeof res.writeHead === 'function' && !res.headersSent) {
@@ -85,7 +83,13 @@ class Forwarders {
85
83
  res.destroy()
86
84
  }
87
85
  })
88
- const strip = (req) => { for (const name of STRIPPED_HEADERS) delete req.headers[name] }
86
+ // The headers go out as the incoming request's headers. Setting them in http-proxy's proxyReq
87
+ // hook instead would throw: with the proxy agent the hook fires once the CONNECT completes, and
88
+ // by then the outgoing headers are already written.
89
+ const mark = (req) => {
90
+ for (const name of STRIPPED_HEADERS) delete req.headers[name]
91
+ req.headers[FORWARDED_HEADER] = '1'
92
+ }
89
93
  const server = http.createServer((req, res) => {
90
94
  const url = new URL(req.url, 'http://127.0.0.1')
91
95
  if (url.pathname === OPEN_PATH) {
@@ -100,11 +104,11 @@ class Forwarders {
100
104
  res.end()
101
105
  return
102
106
  }
103
- strip(req)
107
+ mark(req)
104
108
  proxy.web(req, res)
105
109
  })
106
110
  server.on('upgrade', (req, socket, head) => {
107
- strip(req)
111
+ mark(req)
108
112
  proxy.ws(req, socket, head)
109
113
  })
110
114
  // every connection on both sides, upgraded ones included, so stopAll can end a stream a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "8.2.31",
3
+ "version": "8.2.32",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -55,6 +55,39 @@ test('a forwarder relays requests with the forwarded header, the peer as Host, a
55
55
  assert.equal(target.seen[0].headers['x-pinokio-source-host'], undefined)
56
56
  })
57
57
 
58
+ // A forward proxy for plain http targets: the real ProxyAgent sends it absolute URLs, and
59
+ // connects asynchronously, which is what broke the proxyReq-hook version in production.
60
+ async function forwardProxy(t) {
61
+ const server = http.createServer((req, res) => {
62
+ const target = new URL(req.url)
63
+ const upstream = http.request({ host: target.hostname, port: target.port, path: target.pathname + target.search, method: req.method, headers: req.headers }, (answer) => {
64
+ res.writeHead(answer.statusCode, answer.headers)
65
+ answer.pipe(res)
66
+ })
67
+ upstream.on('error', (error) => { res.writeHead(502); res.end(error.message) })
68
+ req.pipe(upstream)
69
+ })
70
+ server.listen(0, '127.0.0.1')
71
+ await once(server, 'listening')
72
+ t.after(() => { server.closeAllConnections(); server.close() })
73
+ return `http://127.0.0.1:${server.address().port}`
74
+ }
75
+
76
+ test('through the real proxy agent, whose connection completes later, the forwarded header still goes out and nothing throws', async (t) => {
77
+ const target = await peer(t)
78
+ const proxyUrl = await forwardProxy(t)
79
+ const forwarders = new Forwarders({ proxyUrl: () => proxyUrl, serverPort: () => 42000, scheme: 'http' })
80
+ t.after(() => forwarders.stopAll())
81
+ const local = await forwarders.open('127.0.0.1', target.port)
82
+ const answer = await get(local, '/ui/?a=1', { 'X-Pinokio-Peer': '1' })
83
+ assert.equal(answer.status, 200)
84
+ const body = JSON.parse(answer.body)
85
+ assert.equal(body.forwarded, '1')
86
+ assert.equal(body.peer, null)
87
+ assert.equal(body.host, `127.0.0.1:${target.port}`)
88
+ assert.equal(target.seen.length, 1)
89
+ })
90
+
58
91
  test('two opens of the same peer and port at once share one forwarder', async (t) => {
59
92
  const target = await peer(t)
60
93
  const forwarders = new Forwarders({ proxyUrl: () => null, serverPort: () => 42000, scheme: 'http' })