Skip to content

Commit

Permalink
Clean up socket in case of error (#98)
Browse files Browse the repository at this point in the history
  • Loading branch information
delvedor authored Oct 29, 2022
1 parent 318afd7 commit 6723582
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 2 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ jobs:
run: |
npm install
- name: Test
- name: Test / 1
run: |
npm run test-ci
- name: Test / 2
run: |
./test/hang-socket/runner.sh
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class HttpProxyAgent extends http.Agent {
if (response.statusCode === 200) {
callback(null, socket)
} else {
socket.destroy()
callback(new Error(`Bad response: ${response.statusCode}`), null)
}
})
Expand Down Expand Up @@ -101,6 +102,7 @@ class HttpsProxyAgent extends https.Agent {
const secureSocket = super.createConnection({ ...options, socket })
callback(null, secureSocket)
} else {
socket.destroy()
callback(new Error(`Bad response: ${response.statusCode}`), null)
}
})
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"./*": "./*.js"
},
"scripts": {
"test": "standard && NODE_EXTRA_CA_CERTS=test/fixtures/certs_unit_test.pem ava -v test/*.test.js && tsd",
"test": "standard && NODE_EXTRA_CA_CERTS=test/fixtures/certs_unit_test.pem ava -v test/*.test.js && NODE_EXTRA_CA_CERTS=test/fixtures/certs_unit_test.pem ./test/hang-socket/runner.sh && tsd",
"test-ci": "standard && ava -v test/*.test.js && tsd"
},
"engines": {
Expand Down
67 changes: 67 additions & 0 deletions test/hang-socket/http.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use strict'

const http = require('http')
const { createServer, SERVER_HOSTNAME } = require('../utils')
const { HttpProxyAgent } = require('../../')

function request (opts) {
return new Promise((resolve, reject) => {
const req = http.request(opts, resolve)
req.on('error', reject)
req.end(opts.body)
})
}

const timeout = setTimeout(() => {
console.log('The http agent is not cleaning up hanging sockets')
process.exit(1)
}, 5000)

async function run () {
const server = await createServer()
server.on('connect', (request, socket, head) => {
socket.on('end', () => {
clearTimeout(timeout)
})
const lines = [
'HTTP/1.1 403 FORBIDDEN',
'',
'Forbidden'
]
socket.write(lines.join('\r\n'))
})

const agent = new HttpProxyAgent({
keepAlive: true,
keepAliveMsecs: 1000,
maxSockets: 256,
maxFreeSockets: 256,
scheduling: 'lifo',
timeout: 500,
proxy: `http://${SERVER_HOSTNAME}:${server.address().port}`
})

try {
await request({
method: 'GET',
hostname: 'www.example.com',
port: '',
path: '/',
agent
})
console.error(new Error('Should throw'))
process.exit(1)
} catch (err) {
if (err.message !== 'Bad response: 403') {
console.error(new Error('Expected a different error'))
process.exit(1)
}
}

server.close()
}

run().catch(err => {
console.error(err)
process.exit(1)
})
67 changes: 67 additions & 0 deletions test/hang-socket/https.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use strict'

const https = require('https')
const { createSecureServer, SERVER_HOSTNAME } = require('../utils')
const { HttpsProxyAgent } = require('../../')

function request (opts) {
return new Promise((resolve, reject) => {
const req = https.request(opts, resolve)
req.on('error', reject)
req.end(opts.body)
})
}

const timeout = setTimeout(() => {
console.log('The https agent is not cleaning up hanging sockets')
process.exit(1)
}, 5000)

async function run () {
const server = await createSecureServer()
server.on('connect', (request, socket, head) => {
socket.on('end', () => {
clearTimeout(timeout)
})
const lines = [
'HTTP/1.1 403 FORBIDDEN',
'',
'Forbidden'
]
socket.write(lines.join('\r\n'))
})

const agent = new HttpsProxyAgent({
keepAlive: true,
keepAliveMsecs: 1000,
maxSockets: 256,
maxFreeSockets: 256,
scheduling: 'lifo',
timeout: 500,
proxy: `https://${SERVER_HOSTNAME}:${server.address().port}`
})

try {
await request({
method: 'GET',
hostname: 'www.example.com',
port: '',
path: '/',
agent
})
console.error(new Error('Should throw'))
process.exit(1)
} catch (err) {
if (err.message !== 'Bad response: 403') {
console.error(new Error('Expected a different error, got:', err.message))
process.exit(1)
}
}

server.close()
}

run().catch(err => {
console.error(err)
process.exit(1)
})
6 changes: 6 additions & 0 deletions test/hang-socket/runner.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

set -euo pipefail

node test/hang-socket/http.js
node test/hang-socket/https.js

0 comments on commit 6723582

Please sign in to comment.