update
This commit is contained in:
@ -1,564 +1,180 @@
|
||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||||
import * as plugins from './plugins.js';
|
||||
import { createTestServer } from '../../helpers/server.loader.js';
|
||||
import { createSmtpClient } from '../../helpers/smtp.client.js';
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
import { startTestServer, stopTestServer, type ITestServer } from '../../helpers/server.loader.js';
|
||||
import { createSmtpClient } from '../../../ts/mail/delivery/smtpclient/index.js';
|
||||
import { Email } from '../../../ts/mail/core/classes.email.js';
|
||||
|
||||
tap.test('CEDGE-06: should handle large headers gracefully', async (tools) => {
|
||||
const testId = 'CEDGE-06-large-headers';
|
||||
console.log(`\n${testId}: Testing large header handling...`);
|
||||
let testServer: ITestServer;
|
||||
|
||||
let scenarioCount = 0;
|
||||
tap.test('setup test SMTP server', async () => {
|
||||
testServer = await startTestServer({
|
||||
port: 2575,
|
||||
tlsEnabled: false,
|
||||
authRequired: false
|
||||
});
|
||||
expect(testServer).toBeTruthy();
|
||||
expect(testServer.port).toEqual(2575);
|
||||
});
|
||||
|
||||
// Scenario 1: Very long subject lines
|
||||
await (async () => {
|
||||
scenarioCount++;
|
||||
console.log(`\nScenario ${scenarioCount}: Testing very long subject lines`);
|
||||
tap.test('CEDGE-06: Very long subject lines', async () => {
|
||||
console.log('Testing very long subject lines');
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
});
|
||||
|
||||
// Test various subject line lengths
|
||||
const testSubjects = [
|
||||
'Normal Subject Line',
|
||||
'A'.repeat(100), // 100 chars
|
||||
'B'.repeat(500), // 500 chars
|
||||
'C'.repeat(1000), // 1000 chars
|
||||
'D'.repeat(2000), // 2000 chars - very long
|
||||
];
|
||||
|
||||
for (const subject of testSubjects) {
|
||||
console.log(` Testing subject length: ${subject.length} chars`);
|
||||
|
||||
const testServer = await createTestServer({
|
||||
onConnection: async (socket) => {
|
||||
console.log(' [Server] Client connected');
|
||||
socket.write('220 mail.example.com ESMTP\r\n');
|
||||
|
||||
let inData = false;
|
||||
let subjectLength = 0;
|
||||
|
||||
socket.on('data', (data) => {
|
||||
const text = data.toString();
|
||||
|
||||
if (inData) {
|
||||
// Look for Subject header
|
||||
const subjectMatch = text.match(/^Subject:\s*(.+?)(?:\r\n(?:\s+.+)?)*\r\n/m);
|
||||
if (subjectMatch) {
|
||||
subjectLength = subjectMatch[0].length;
|
||||
console.log(` [Server] Subject header length: ${subjectLength} chars`);
|
||||
}
|
||||
|
||||
if (text.includes('\r\n.\r\n')) {
|
||||
inData = false;
|
||||
socket.write('250 OK\r\n');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const command = text.trim();
|
||||
console.log(` [Server] Received: ${command}`);
|
||||
|
||||
if (command.startsWith('EHLO')) {
|
||||
socket.write('250-mail.example.com\r\n');
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command.startsWith('MAIL FROM:')) {
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command.startsWith('RCPT TO:')) {
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command === 'DATA') {
|
||||
socket.write('354 Start mail input\r\n');
|
||||
inData = true;
|
||||
} else if (command === 'QUIT') {
|
||||
socket.write('221 Bye\r\n');
|
||||
socket.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false
|
||||
});
|
||||
|
||||
// Test various subject lengths
|
||||
const subjectLengths = [100, 500, 1000, 2000, 5000];
|
||||
|
||||
for (const length of subjectLengths) {
|
||||
const subject = 'A'.repeat(length);
|
||||
console.log(` Testing subject with ${length} characters...`);
|
||||
|
||||
const email = new plugins.smartmail.Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
subject: subject,
|
||||
text: 'Testing long subject header folding'
|
||||
});
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
}
|
||||
|
||||
await testServer.server.close();
|
||||
})();
|
||||
|
||||
// Scenario 2: Many recipients (large To/Cc/Bcc headers)
|
||||
await (async () => {
|
||||
scenarioCount++;
|
||||
console.log(`\nScenario ${scenarioCount}: Testing many recipients`);
|
||||
|
||||
const testServer = await createTestServer({
|
||||
onConnection: async (socket) => {
|
||||
console.log(' [Server] Client connected');
|
||||
socket.write('220 mail.example.com ESMTP\r\n');
|
||||
|
||||
let recipientCount = 0;
|
||||
|
||||
socket.on('data', (data) => {
|
||||
const command = data.toString().trim();
|
||||
|
||||
if (command.startsWith('RCPT TO:')) {
|
||||
recipientCount++;
|
||||
console.log(` [Server] Recipient ${recipientCount}`);
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command.startsWith('EHLO')) {
|
||||
socket.write('250-mail.example.com\r\n');
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command.startsWith('MAIL FROM:')) {
|
||||
recipientCount = 0;
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command === 'DATA') {
|
||||
console.log(` [Server] Total recipients: ${recipientCount}`);
|
||||
socket.write('354 Start mail input\r\n');
|
||||
} else if (command === '.') {
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command === 'QUIT') {
|
||||
socket.write('221 Bye\r\n');
|
||||
socket.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false
|
||||
});
|
||||
|
||||
// Create email with many recipients
|
||||
const recipientCounts = [10, 50, 100];
|
||||
|
||||
for (const count of recipientCounts) {
|
||||
console.log(` Testing with ${count} recipients...`);
|
||||
|
||||
const toAddresses = Array(Math.floor(count / 3))
|
||||
.fill(null)
|
||||
.map((_, i) => `recipient${i + 1}@example.com`);
|
||||
|
||||
const ccAddresses = Array(Math.floor(count / 3))
|
||||
.fill(null)
|
||||
.map((_, i) => `cc${i + 1}@example.com`);
|
||||
|
||||
const bccAddresses = Array(count - toAddresses.length - ccAddresses.length)
|
||||
.fill(null)
|
||||
.map((_, i) => `bcc${i + 1}@example.com`);
|
||||
|
||||
const email = new plugins.smartmail.Email({
|
||||
from: 'sender@example.com',
|
||||
to: toAddresses,
|
||||
cc: ccAddresses,
|
||||
bcc: bccAddresses,
|
||||
subject: `Test with ${count} total recipients`,
|
||||
text: 'Testing large recipient lists'
|
||||
});
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
}
|
||||
|
||||
await testServer.server.close();
|
||||
})();
|
||||
|
||||
// Scenario 3: Many custom headers
|
||||
await (async () => {
|
||||
scenarioCount++;
|
||||
console.log(`\nScenario ${scenarioCount}: Testing many custom headers`);
|
||||
|
||||
const testServer = await createTestServer({
|
||||
onConnection: async (socket) => {
|
||||
console.log(' [Server] Client connected');
|
||||
socket.write('220 mail.example.com ESMTP\r\n');
|
||||
|
||||
let inData = false;
|
||||
let headerCount = 0;
|
||||
|
||||
socket.on('data', (data) => {
|
||||
const text = data.toString();
|
||||
|
||||
if (inData) {
|
||||
// Count headers
|
||||
const headerLines = text.split('\r\n');
|
||||
headerLines.forEach(line => {
|
||||
if (line.match(/^[A-Za-z0-9-]+:\s*.+$/)) {
|
||||
headerCount++;
|
||||
}
|
||||
});
|
||||
|
||||
if (text.includes('\r\n.\r\n')) {
|
||||
inData = false;
|
||||
console.log(` [Server] Total headers: ${headerCount}`);
|
||||
socket.write('250 OK\r\n');
|
||||
headerCount = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const command = text.trim();
|
||||
console.log(` [Server] Received: ${command}`);
|
||||
|
||||
if (command.startsWith('EHLO')) {
|
||||
socket.write('250-mail.example.com\r\n');
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command.startsWith('MAIL FROM:')) {
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command.startsWith('RCPT TO:')) {
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command === 'DATA') {
|
||||
socket.write('354 Start mail input\r\n');
|
||||
inData = true;
|
||||
} else if (command === 'QUIT') {
|
||||
socket.write('221 Bye\r\n');
|
||||
socket.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false
|
||||
});
|
||||
|
||||
// Create email with many headers
|
||||
const headerCounts = [10, 50, 100];
|
||||
|
||||
for (const count of headerCounts) {
|
||||
console.log(` Testing with ${count} custom headers...`);
|
||||
|
||||
const headers: { [key: string]: string } = {};
|
||||
for (let i = 0; i < count; i++) {
|
||||
headers[`X-Custom-Header-${i}`] = `This is custom header value number ${i} with some additional text to make it longer`;
|
||||
}
|
||||
|
||||
const email = new plugins.smartmail.Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
subject: `Test with ${count} headers`,
|
||||
text: 'Testing many custom headers',
|
||||
headers
|
||||
});
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
}
|
||||
|
||||
await testServer.server.close();
|
||||
})();
|
||||
|
||||
// Scenario 4: Very long header values
|
||||
await (async () => {
|
||||
scenarioCount++;
|
||||
console.log(`\nScenario ${scenarioCount}: Testing very long header values`);
|
||||
|
||||
const testServer = await createTestServer({
|
||||
onConnection: async (socket) => {
|
||||
console.log(' [Server] Client connected');
|
||||
socket.write('220 mail.example.com ESMTP\r\n');
|
||||
|
||||
let inData = false;
|
||||
let maxHeaderLength = 0;
|
||||
|
||||
socket.on('data', (data) => {
|
||||
const text = data.toString();
|
||||
|
||||
if (inData) {
|
||||
// Find longest header
|
||||
const headers = text.match(/^[A-Za-z0-9-]+:\s*.+?(?=\r\n(?:[A-Za-z0-9-]+:|$))/gms);
|
||||
if (headers) {
|
||||
headers.forEach(header => {
|
||||
if (header.length > maxHeaderLength) {
|
||||
maxHeaderLength = header.length;
|
||||
console.log(` [Server] New longest header: ${header.substring(0, 50)}... (${header.length} chars)`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (text.includes('\r\n.\r\n')) {
|
||||
inData = false;
|
||||
socket.write('250 OK\r\n');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const command = text.trim();
|
||||
console.log(` [Server] Received: ${command}`);
|
||||
|
||||
if (command.startsWith('EHLO')) {
|
||||
socket.write('250-mail.example.com\r\n');
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command.startsWith('MAIL FROM:')) {
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command.startsWith('RCPT TO:')) {
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command === 'DATA') {
|
||||
socket.write('354 Start mail input\r\n');
|
||||
inData = true;
|
||||
} else if (command === 'QUIT') {
|
||||
socket.write('221 Bye\r\n');
|
||||
socket.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false
|
||||
});
|
||||
|
||||
// Test with very long header values
|
||||
const longValues = [
|
||||
'A'.repeat(500),
|
||||
'Word '.repeat(200), // Many words
|
||||
Array(100).fill('item').join(', '), // Comma-separated list
|
||||
'This is a very long header value that contains multiple sentences. ' +
|
||||
'Each sentence adds to the overall length of the header. ' +
|
||||
'The header should be properly folded according to RFC 5322. ' +
|
||||
'This ensures compatibility with various email servers and clients. '.repeat(5)
|
||||
];
|
||||
|
||||
for (let i = 0; i < longValues.length; i++) {
|
||||
console.log(` Testing long header value ${i + 1} (${longValues[i].length} chars)...`);
|
||||
|
||||
const email = new plugins.smartmail.Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
subject: `Test ${i + 1}`,
|
||||
text: 'Testing long header values',
|
||||
headers: {
|
||||
'X-Long-Header': longValues[i],
|
||||
'X-Another-Long': longValues[i].split('').reverse().join('')
|
||||
}
|
||||
});
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
}
|
||||
|
||||
await testServer.server.close();
|
||||
})();
|
||||
|
||||
// Scenario 5: Headers with special folding requirements
|
||||
await (async () => {
|
||||
scenarioCount++;
|
||||
console.log(`\nScenario ${scenarioCount}: Testing header folding edge cases`);
|
||||
|
||||
const testServer = await createTestServer({
|
||||
onConnection: async (socket) => {
|
||||
console.log(' [Server] Client connected');
|
||||
socket.write('220 mail.example.com ESMTP\r\n');
|
||||
|
||||
let inData = false;
|
||||
|
||||
socket.on('data', (data) => {
|
||||
const text = data.toString();
|
||||
|
||||
if (inData) {
|
||||
// Check for proper folding (continuation lines start with whitespace)
|
||||
const lines = text.split('\r\n');
|
||||
let foldedHeaders = 0;
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
if (index > 0 && (line.startsWith(' ') || line.startsWith('\t'))) {
|
||||
foldedHeaders++;
|
||||
}
|
||||
});
|
||||
|
||||
if (foldedHeaders > 0) {
|
||||
console.log(` [Server] Found ${foldedHeaders} folded header lines`);
|
||||
}
|
||||
|
||||
if (text.includes('\r\n.\r\n')) {
|
||||
inData = false;
|
||||
socket.write('250 OK\r\n');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const command = text.trim();
|
||||
console.log(` [Server] Received: ${command}`);
|
||||
|
||||
if (command.startsWith('EHLO')) {
|
||||
socket.write('250-mail.example.com\r\n');
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command.startsWith('MAIL FROM:')) {
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command.startsWith('RCPT TO:')) {
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command === 'DATA') {
|
||||
socket.write('354 Start mail input\r\n');
|
||||
inData = true;
|
||||
} else if (command === 'QUIT') {
|
||||
socket.write('221 Bye\r\n');
|
||||
socket.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false
|
||||
});
|
||||
|
||||
// Test headers that require special folding
|
||||
const email = new plugins.smartmail.Email({
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
subject: 'Testing header folding',
|
||||
text: 'Testing special folding cases',
|
||||
headers: {
|
||||
// Long header with no natural break points
|
||||
'X-No-Spaces': 'A'.repeat(100),
|
||||
|
||||
// Header with URLs that shouldn't be broken
|
||||
'X-URLs': 'Visit https://example.com/very/long/path/that/should/not/be/broken/in/the/middle and https://another-example.com/another/very/long/path',
|
||||
|
||||
// Header with quoted strings
|
||||
'X-Quoted': '"This is a very long quoted string that should be kept together if possible when folding the header" and some more text',
|
||||
|
||||
// Header with structured data
|
||||
'X-Structured': 'key1=value1; key2="a very long value that might need folding"; key3=value3; key4="another long value"',
|
||||
|
||||
// References header (common to have many message IDs)
|
||||
'References': Array(20).fill(null).map((_, i) => `<message-id-${i}@example.com>`).join(' ')
|
||||
}
|
||||
subject: subject,
|
||||
text: 'Testing large subject headers'
|
||||
});
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
console.log(` Result: ${result.messageId ? 'Success' : 'Failed'}`);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
}
|
||||
|
||||
await testServer.server.close();
|
||||
})();
|
||||
await smtpClient.close();
|
||||
});
|
||||
|
||||
// Scenario 6: Headers at server limits
|
||||
await (async () => {
|
||||
scenarioCount++;
|
||||
console.log(`\nScenario ${scenarioCount}: Testing headers at server limits`);
|
||||
|
||||
const maxHeaderSize = 8192; // Common limit
|
||||
|
||||
const testServer = await createTestServer({
|
||||
onConnection: async (socket) => {
|
||||
console.log(' [Server] Client connected');
|
||||
socket.write('220 mail.example.com ESMTP\r\n');
|
||||
|
||||
let inData = false;
|
||||
let headerSection = '';
|
||||
|
||||
socket.on('data', (data) => {
|
||||
const text = data.toString();
|
||||
|
||||
if (inData) {
|
||||
if (!headerSection && text.includes('\r\n\r\n')) {
|
||||
// Extract header section
|
||||
headerSection = text.substring(0, text.indexOf('\r\n\r\n'));
|
||||
console.log(` [Server] Header section size: ${headerSection.length} bytes`);
|
||||
|
||||
if (headerSection.length > maxHeaderSize) {
|
||||
socket.write('552 5.3.4 Header size exceeds maximum allowed\r\n');
|
||||
socket.end();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (text.includes('\r\n.\r\n')) {
|
||||
inData = false;
|
||||
socket.write('250 OK\r\n');
|
||||
headerSection = '';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const command = text.trim();
|
||||
console.log(` [Server] Received: ${command}`);
|
||||
|
||||
if (command.startsWith('EHLO')) {
|
||||
socket.write('250-mail.example.com\r\n');
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command.startsWith('MAIL FROM:')) {
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command.startsWith('RCPT TO:')) {
|
||||
socket.write('250 OK\r\n');
|
||||
} else if (command === 'DATA') {
|
||||
socket.write('354 Start mail input\r\n');
|
||||
inData = true;
|
||||
} else if (command === 'QUIT') {
|
||||
socket.write('221 Bye\r\n');
|
||||
socket.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
tap.test('CEDGE-06: Multiple large headers', async () => {
|
||||
console.log('Testing multiple large headers');
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
});
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false
|
||||
});
|
||||
|
||||
// Test with headers near the limit
|
||||
const testSizes = [
|
||||
{ size: 1000, desc: 'well below limit' },
|
||||
{ size: 7000, desc: 'near limit' },
|
||||
{ size: 8000, desc: 'very close to limit' }
|
||||
];
|
||||
|
||||
for (const test of testSizes) {
|
||||
console.log(` Testing with header size ${test.desc} (${test.size} bytes)...`);
|
||||
|
||||
// Create headers that total approximately the target size
|
||||
const headers: { [key: string]: string } = {};
|
||||
let currentSize = 0;
|
||||
let headerIndex = 0;
|
||||
|
||||
while (currentSize < test.size) {
|
||||
const headerName = `X-Test-Header-${headerIndex}`;
|
||||
const remainingSize = test.size - currentSize;
|
||||
const headerValue = 'A'.repeat(Math.min(remainingSize - headerName.length - 4, 200)); // -4 for ": \r\n"
|
||||
|
||||
headers[headerName] = headerValue;
|
||||
currentSize += headerName.length + headerValue.length + 4;
|
||||
headerIndex++;
|
||||
}
|
||||
|
||||
const email = new plugins.smartmail.Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
subject: `Testing ${test.desc}`,
|
||||
text: 'Testing header size limits',
|
||||
headers
|
||||
});
|
||||
|
||||
try {
|
||||
const result = await smtpClient.sendMail(email);
|
||||
console.log(` Result: Success`);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
} catch (error) {
|
||||
console.log(` Result: Failed (${error.message})`);
|
||||
// This is expected for very large headers
|
||||
}
|
||||
// Create email with multiple large headers
|
||||
const largeValue = 'X'.repeat(500);
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
subject: 'Multiple large headers test',
|
||||
text: 'Testing multiple large headers',
|
||||
headers: {
|
||||
'X-Large-Header-1': largeValue,
|
||||
'X-Large-Header-2': largeValue,
|
||||
'X-Large-Header-3': largeValue,
|
||||
'X-Large-Header-4': largeValue,
|
||||
'X-Large-Header-5': largeValue,
|
||||
'X-Very-Long-Header-Name-That-Exceeds-Normal-Limits': 'Value for long header name',
|
||||
'X-Mixed-Content': `Start-${largeValue}-Middle-${largeValue}-End`
|
||||
}
|
||||
});
|
||||
|
||||
await testServer.server.close();
|
||||
})();
|
||||
const result = await smtpClient.sendMail(email);
|
||||
console.log(`Result: ${result.messageId ? 'Success' : 'Failed'}`);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
|
||||
console.log(`\n${testId}: All ${scenarioCount} large header scenarios tested ✓`);
|
||||
});
|
||||
await smtpClient.close();
|
||||
});
|
||||
|
||||
tap.test('CEDGE-06: Header folding and wrapping', async () => {
|
||||
console.log('Testing header folding and wrapping');
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
});
|
||||
|
||||
// Create headers that should be folded
|
||||
const longHeaderValue = 'This is a very long header value that should exceed the recommended 78 character line limit and force the header to be folded across multiple lines according to RFC 5322 specifications';
|
||||
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
subject: 'Header folding test with a very long subject line that should also be folded properly',
|
||||
text: 'Testing header folding',
|
||||
headers: {
|
||||
'X-Long-Header': longHeaderValue,
|
||||
'X-Multi-Line': `Line 1 ${longHeaderValue}\nLine 2 ${longHeaderValue}\nLine 3 ${longHeaderValue}`,
|
||||
'X-Special-Chars': `Header with special chars: \t\r\n\x20 and unicode: 🎉 émojis`
|
||||
}
|
||||
});
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
console.log(`Result: ${result.messageId ? 'Success' : 'Failed'}`);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
|
||||
await smtpClient.close();
|
||||
});
|
||||
|
||||
tap.test('CEDGE-06: Maximum header size limits', async () => {
|
||||
console.log('Testing maximum header size limits');
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
});
|
||||
|
||||
// Test near RFC limits (recommended 998 chars per line)
|
||||
const nearMaxValue = 'Y'.repeat(900); // Near but under limit
|
||||
const overMaxValue = 'Z'.repeat(1500); // Over recommended limit
|
||||
|
||||
const testCases = [
|
||||
{ name: 'Near limit', value: nearMaxValue },
|
||||
{ name: 'Over limit', value: overMaxValue }
|
||||
];
|
||||
|
||||
for (const testCase of testCases) {
|
||||
console.log(` Testing ${testCase.name}: ${testCase.value.length} chars`);
|
||||
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
subject: `Header size test: ${testCase.name}`,
|
||||
text: 'Testing header size limits',
|
||||
headers: {
|
||||
'X-Size-Test': testCase.value
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const result = await smtpClient.sendMail(email);
|
||||
console.log(` ${testCase.name}: Success`);
|
||||
expect(result).toBeDefined();
|
||||
} catch (error) {
|
||||
console.log(` ${testCase.name}: Failed (${error.message})`);
|
||||
// Some failures might be expected for oversized headers
|
||||
expect(error).toBeDefined();
|
||||
}
|
||||
}
|
||||
|
||||
await smtpClient.close();
|
||||
});
|
||||
|
||||
tap.test('cleanup test SMTP server', async () => {
|
||||
if (testServer) {
|
||||
await stopTestServer(testServer);
|
||||
}
|
||||
});
|
||||
|
||||
export default tap.start();
|
Reference in New Issue
Block a user