Initial commit of massive v2 rewrite
This commit is contained in:
parent
1025f3b523
commit
dc120fe78a
55 changed files with 21733 additions and 0 deletions
426
.tests/network.test.js
Normal file
426
.tests/network.test.js
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
import { jest } from '@jest/globals';
|
||||
|
||||
// Mock the logs module
|
||||
jest.unstable_mockModule('../dist/utils/logs.js', () => ({
|
||||
warn: jest.fn(),
|
||||
error: jest.fn()
|
||||
}));
|
||||
|
||||
// Import modules after mocking
|
||||
const { getRequestURL, getRealIP } = await import('../dist/utils/network.js');
|
||||
const logs = await import('../dist/utils/logs.js');
|
||||
|
||||
describe('Network utilities', () => {
|
||||
|
||||
describe('getRequestURL', () => {
|
||||
test('should handle http URLs', () => {
|
||||
const request = { url: 'http://example.com/path' };
|
||||
const result = getRequestURL(request);
|
||||
|
||||
expect(result).toBeInstanceOf(URL);
|
||||
expect(result.href).toBe('http://example.com/path');
|
||||
});
|
||||
|
||||
test('should handle https URLs', () => {
|
||||
const request = { url: 'https://example.com/path' };
|
||||
const result = getRequestURL(request);
|
||||
|
||||
expect(result).toBeInstanceOf(URL);
|
||||
expect(result.href).toBe('https://example.com/path');
|
||||
});
|
||||
|
||||
test('should construct URL from path and host header', () => {
|
||||
const request = {
|
||||
url: '/path',
|
||||
headers: { host: 'example.com' }
|
||||
};
|
||||
const result = getRequestURL(request);
|
||||
|
||||
expect(result).toBeInstanceOf(URL);
|
||||
expect(result.href).toBe('http://example.com/path');
|
||||
});
|
||||
|
||||
test('should use https when secure property is true', () => {
|
||||
const request = {
|
||||
url: '/path',
|
||||
secure: true,
|
||||
headers: { host: 'example.com' }
|
||||
};
|
||||
const result = getRequestURL(request);
|
||||
|
||||
expect(result.href).toBe('https://example.com/path');
|
||||
});
|
||||
|
||||
test('should use https when x-forwarded-proto is https', () => {
|
||||
const request = {
|
||||
url: '/path',
|
||||
headers: {
|
||||
host: 'example.com',
|
||||
'x-forwarded-proto': 'https'
|
||||
}
|
||||
};
|
||||
const result = getRequestURL(request);
|
||||
|
||||
expect(result.href).toBe('https://example.com/path');
|
||||
});
|
||||
|
||||
test('should handle Fetch-style headers with get() method', () => {
|
||||
const request = {
|
||||
url: '/path',
|
||||
headers: {
|
||||
get: jest.fn((name) => {
|
||||
if (name === 'host') return 'example.com';
|
||||
return null;
|
||||
})
|
||||
}
|
||||
};
|
||||
const result = getRequestURL(request);
|
||||
|
||||
expect(result.href).toBe('http://example.com/path');
|
||||
});
|
||||
|
||||
test('should return null for missing URL', () => {
|
||||
const request = {};
|
||||
const result = getRequestURL(request);
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
test('should return null for invalid URL', () => {
|
||||
const request = {
|
||||
url: '/test',
|
||||
headers: { host: 'localhost' }
|
||||
};
|
||||
|
||||
// Mock URL constructor to throw
|
||||
const originalURL = global.URL;
|
||||
global.URL = function() {
|
||||
throw new TypeError('Invalid URL');
|
||||
};
|
||||
|
||||
const result = getRequestURL(request);
|
||||
expect(result).toBeNull();
|
||||
expect(logs.warn).toHaveBeenCalled();
|
||||
|
||||
// Restore
|
||||
global.URL = originalURL;
|
||||
});
|
||||
|
||||
test('should handle non-Error objects in catch block', () => {
|
||||
const request = {
|
||||
url: '/test',
|
||||
headers: { host: 'localhost' }
|
||||
};
|
||||
|
||||
// Mock URL constructor to throw non-Error
|
||||
const originalURL = global.URL;
|
||||
global.URL = function() {
|
||||
throw "String error instead of Error object";
|
||||
};
|
||||
|
||||
const result = getRequestURL(request);
|
||||
expect(result).toBeNull();
|
||||
|
||||
// Restore
|
||||
global.URL = originalURL;
|
||||
});
|
||||
|
||||
test('should handle array host headers in Express requests', () => {
|
||||
const request = {
|
||||
url: '/path',
|
||||
headers: { host: ['example.com', 'backup.com'] } // Array host
|
||||
};
|
||||
|
||||
const result = getRequestURL(request);
|
||||
expect(result.href).toBe('http://example.com/path');
|
||||
});
|
||||
|
||||
test('should handle empty array host headers', () => {
|
||||
const request = {
|
||||
url: '/path',
|
||||
headers: { host: [] } // Empty array
|
||||
};
|
||||
|
||||
const result = getRequestURL(request);
|
||||
expect(result.href).toBe('http://localhost/path'); // Falls back to localhost
|
||||
});
|
||||
|
||||
test('should handle x-forwarded-host with Fetch-style headers', () => {
|
||||
const request = {
|
||||
url: '/path',
|
||||
headers: {
|
||||
get: jest.fn((name) => {
|
||||
if (name === 'host') return null;
|
||||
if (name === 'x-forwarded-host') return 'forwarded.example.com';
|
||||
return null;
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
const result = getRequestURL(request);
|
||||
expect(result.href).toBe('http://forwarded.example.com/path');
|
||||
});
|
||||
|
||||
test('should fallback to localhost for Fetch-style headers when all host headers are missing', () => {
|
||||
const request = {
|
||||
url: '/path',
|
||||
headers: {
|
||||
get: jest.fn(() => null) // All headers return null
|
||||
}
|
||||
};
|
||||
|
||||
const result = getRequestURL(request);
|
||||
expect(result.href).toBe('http://localhost/path');
|
||||
});
|
||||
|
||||
test('should handle x-forwarded-host in Express headers', () => {
|
||||
const request = {
|
||||
url: '/path',
|
||||
headers: {
|
||||
'x-forwarded-host': 'forwarded.example.com'
|
||||
// No host header
|
||||
}
|
||||
};
|
||||
|
||||
const result = getRequestURL(request);
|
||||
expect(result.href).toBe('http://forwarded.example.com/path');
|
||||
});
|
||||
|
||||
test('should handle array x-forwarded-host headers', () => {
|
||||
const request = {
|
||||
url: '/path',
|
||||
headers: {
|
||||
'x-forwarded-host': ['forwarded.example.com', 'backup.example.com']
|
||||
}
|
||||
};
|
||||
|
||||
const result = getRequestURL(request);
|
||||
expect(result.href).toBe('http://forwarded.example.com/path');
|
||||
});
|
||||
|
||||
test('should handle empty array x-forwarded-host headers', () => {
|
||||
const request = {
|
||||
url: '/path',
|
||||
headers: {
|
||||
'x-forwarded-host': []
|
||||
}
|
||||
};
|
||||
|
||||
const result = getRequestURL(request);
|
||||
expect(result.href).toBe('http://localhost/path');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRealIP', () => {
|
||||
test('should extract IP from x-forwarded-for header', () => {
|
||||
const request = {
|
||||
headers: { 'x-forwarded-for': '192.168.1.100' }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should extract first IP from comma-separated x-forwarded-for', () => {
|
||||
const request = {
|
||||
headers: { 'x-forwarded-for': '192.168.1.100, 10.0.0.1, 127.0.0.1' }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should use x-real-ip when x-forwarded-for is missing', () => {
|
||||
const request = {
|
||||
headers: { 'x-real-ip': '192.168.1.100' }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should handle Fetch-style headers using get() method', () => {
|
||||
const request = {
|
||||
headers: {
|
||||
get: jest.fn((name) => {
|
||||
if (name === 'x-forwarded-for') return '192.168.1.100';
|
||||
return null;
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should use server remoteAddress when headers are empty', () => {
|
||||
const request = { headers: {} };
|
||||
const server = { remoteAddress: '192.168.1.100' };
|
||||
|
||||
const result = getRealIP(request, server);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should use connection.remoteAddress for Express requests', () => {
|
||||
const request = {
|
||||
headers: {},
|
||||
connection: { remoteAddress: '192.168.1.100' }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should use req.ip property when available', () => {
|
||||
const request = {
|
||||
headers: {},
|
||||
ip: '192.168.1.100'
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should clean IPv6 mapped IPv4 addresses', () => {
|
||||
const request = {
|
||||
headers: { 'x-forwarded-for': '::ffff:192.168.1.100' }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should return 127.0.0.1 as ultimate fallback', () => {
|
||||
const request = { headers: {} };
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('127.0.0.1');
|
||||
});
|
||||
|
||||
test('should prioritize x-forwarded-for over other sources', () => {
|
||||
const request = {
|
||||
headers: { 'x-forwarded-for': '192.168.1.100' },
|
||||
connection: { remoteAddress: '10.0.0.1' },
|
||||
ip: '172.16.0.1'
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should handle array x-forwarded-for headers', () => {
|
||||
const request = {
|
||||
headers: { 'x-forwarded-for': ['192.168.1.100', '10.0.0.1'] }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should handle array x-real-ip headers', () => {
|
||||
const request = {
|
||||
headers: { 'x-real-ip': ['192.168.1.100', '10.0.0.1'] }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should use x-real-ip with Fetch-style headers when x-forwarded-for is missing', () => {
|
||||
const request = {
|
||||
headers: {
|
||||
get: jest.fn((name) => {
|
||||
if (name === 'x-forwarded-for') return null;
|
||||
if (name === 'x-real-ip') return '192.168.1.100';
|
||||
return null;
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should use socket.remoteAddress when connection.remoteAddress is missing', () => {
|
||||
const request = {
|
||||
headers: {},
|
||||
connection: {}, // connection exists but no remoteAddress
|
||||
socket: { remoteAddress: '192.168.1.100' }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should handle missing connection but present socket', () => {
|
||||
const request = {
|
||||
headers: {},
|
||||
socket: { remoteAddress: '192.168.1.100' }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
// Note: socket.remoteAddress is only checked within the connection block
|
||||
// When no connection exists, it falls back to URL hostname/127.0.0.1
|
||||
expect(result).toBe('127.0.0.1');
|
||||
});
|
||||
|
||||
test('should handle whitespace in comma-separated IPs', () => {
|
||||
const request = {
|
||||
headers: { 'x-forwarded-for': ' 192.168.1.100 , 10.0.0.1 , 127.0.0.1 ' }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('192.168.1.100');
|
||||
});
|
||||
|
||||
test('should fallback to URL hostname when all IP sources fail', () => {
|
||||
const request = {
|
||||
headers: {},
|
||||
url: '/test'
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
// getRequestURL constructs URL with localhost as default host, so hostname is 'localhost'
|
||||
expect(result).toBe('localhost');
|
||||
});
|
||||
|
||||
test('should handle undefined IP values gracefully', () => {
|
||||
const request = {
|
||||
headers: { 'x-forwarded-for': undefined, 'x-real-ip': undefined }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('127.0.0.1');
|
||||
});
|
||||
|
||||
test('should handle null IP values gracefully', () => {
|
||||
const request = {
|
||||
headers: { 'x-forwarded-for': null, 'x-real-ip': null }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('127.0.0.1');
|
||||
});
|
||||
|
||||
test('should handle empty string IP values', () => {
|
||||
const request = {
|
||||
headers: { 'x-forwarded-for': '', 'x-real-ip': '' }
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('127.0.0.1');
|
||||
});
|
||||
|
||||
test('should handle empty array header values', () => {
|
||||
const request = {
|
||||
headers: {
|
||||
'x-forwarded-for': [],
|
||||
'x-real-ip': []
|
||||
}
|
||||
};
|
||||
|
||||
const result = getRealIP(request);
|
||||
expect(result).toBe('127.0.0.1');
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue