Skip to content
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
20 changes: 20 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,26 @@ exports.compileTrust = function(val) {
// Support comma-separated values
val = val.split(',')
.map(function (v) { return v.trim() })

// For large lists (>1000 IPs), use lazy compilation to avoid
// blocking the event loop during app initialization.
// While proxyaddr.compile() has O(n) complexity, large IP lists
// can still cause significant startup delays (2+ seconds for 1M+ IPs).
if (val.length > 1000) {
let compiledFn = null;
return function(address, i) {
// compile on first access to avoid startup delay
if (!compiledFn) {
try {
compiledFn = proxyaddr.compile(val);
} catch (err) {
// If compilation fails, fall back to immediate compilation
return proxyaddr.compile(val)(address, i);
}
}
return compiledFn(address, i);
};
}
}

return proxyaddr.compile(val || []);
Expand Down
108 changes: 108 additions & 0 deletions test/utils.compileTrust.perf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
'use strict'

const utils = require('../lib/utils')

describe('utils.compileTrust', function () {
describe('performance', function () {
it('should use lazy compilation for large IP lists', function (done) {
// Test with large IP list (10,000 IPs)
const largeIpList = Array(10000).fill('127.0.0.1').join(',')

// Measure compileTrust time (should be fast with lazy compilation)
const start = Date.now()
const trustFn = utils.compileTrust(largeIpList)
const compileTime = Date.now() - start

// CompileTrust should be fast (< 10ms) with lazy compilation
if (compileTime > 10) {
return done(new Error(`compileTrust took ${compileTime}ms, expected < 10ms with lazy compilation`))
}

// First call should trigger compilation (will be slower)
const firstCallStart = Date.now()
const result1 = trustFn('127.0.0.1', 0)
const firstCallTime = Date.now() - firstCallStart

// Subsequent calls should be fast (cached)
const secondCallStart = Date.now()
const result2 = trustFn('192.168.1.1', 0)
const secondCallTime = Date.now() - secondCallStart

// Verify results
if (result1 !== true) {
return done(new Error('Expected first call to return true'))
}
if (result2 !== false) {
return done(new Error('Expected second call to return false'))
}

// Second call should be much faster than first
if (secondCallTime >= firstCallTime) {
return done(new Error(`Second call (${secondCallTime}ms) should be faster than first call (${firstCallTime}ms)`))
}

console.log(`Performance test results:`)
console.log(` compileTrust: ${compileTime}ms (lazy compilation)`)
console.log(` First call: ${firstCallTime}ms (compilation + execution)`)
console.log(` Second call: ${secondCallTime}ms (cached execution)`)
console.log(` Note: proxyaddr.compile() has O(n) complexity, but large lists`)
console.log(` can still cause significant startup delays without lazy compilation`)

done()
})

it('should work correctly with small IP lists', function (done) {
// Test with small IP list (should use immediate compilation)
const smallIpList = '127.0.0.1,192.168.1.1,10.0.0.1'

const trustFn = utils.compileTrust(smallIpList)

// Test various IPs
if (trustFn('127.0.0.1', 0) !== true) {
return done(new Error('Expected 127.0.0.1 to be trusted'))
}
if (trustFn('192.168.1.1', 0) !== true) {
return done(new Error('Expected 192.168.1.1 to be trusted'))
}
if (trustFn('8.8.8.8', 0) !== false) {
return done(new Error('Expected 8.8.8.8 to not be trusted'))
}

done()
})

it('should maintain backward compatibility', function (done) {
// Test all existing functionality still works

// Boolean true
const trueFn = utils.compileTrust(true)
if (trueFn() !== true) {
return done(new Error('Boolean true should return true'))
}

// Number (hop count)
const hopFn = utils.compileTrust(2)
if (hopFn('127.0.0.1', 0) !== true) {
return done(new Error('Hop count 0 should be trusted'))
}
if (hopFn('127.0.0.1', 2) !== false) {
return done(new Error('Hop count 2 should not be trusted'))
}

// Function
const customFn = function() { return 'custom' }
const returnedFn = utils.compileTrust(customFn)
if (returnedFn !== customFn) {
return done(new Error('Custom function should be returned as-is'))
}

// Array
const arrayFn = utils.compileTrust(['127.0.0.1', '192.168.1.1'])
if (arrayFn('127.0.0.1', 0) !== true) {
return done(new Error('Array IP should be trusted'))
}

done()
})
})
})