diff --git a/lib/http.ts b/lib/http.ts index 1008733..fcdc1a8 100644 --- a/lib/http.ts +++ b/lib/http.ts @@ -46,31 +46,6 @@ function getErrorMessage( return status; } -// Class to represent an HTTP request -export class HTTPRequest { - public method: string; - public uri: string; - public headers: { [key: string]: string }; - - constructor( - method: string, - uri: string, - headers: { [key: string]: string } = {}, - ) { - this.method = method; - this.uri = uri; - this.headers = headers; - } - - public addHeader(key: string, value: string): void { - this.headers[key] = value; - } - - public setHeaders(headers: { [key: string]: string }): void { - this.headers = { ...this.headers, ...headers }; - } -} - // Interface to represent an HTTP response export interface HTTPResponse { statusMessage: string; @@ -79,71 +54,6 @@ export interface HTTPResponse { body?: string; } -// Class for parsing HTTP responses -export class HTTPParser { - public static parseChunkedBody(chunkedData: string): string { - const { chunks } = HTTPParser.extractChunks(chunkedData); - return chunks.join(''); - } - - public static extractChunks(buffer: string): { - chunks: string[]; - remainingBuffer: string; - } { - const chunks: string[] = []; - let remainingBuffer = buffer; - let pos = 0; - - while (pos < remainingBuffer.length) { - // Find the chunk size line - const crlfPos = remainingBuffer.indexOf('\r\n', pos); - if (crlfPos === -1) break; - - const chunkSizeLine = remainingBuffer - .substring(pos, crlfPos) - .trim(); - if (!chunkSizeLine) { - pos = crlfPos + 2; - continue; - } - - const chunkSize = parseInt(chunkSizeLine, 16); - - // If chunk size is 0, this is the end marker (empty chunk) - if (chunkSize === 0) { - // Add empty chunk to indicate end of transfer - chunks.push(''); - // Include the end marker in remaining buffer for proper completion detection - remainingBuffer = remainingBuffer.substring(pos); - break; - } - - // Calculate where the chunk data starts and ends - const chunkDataStart = crlfPos + 2; - const chunkDataEnd = chunkDataStart + chunkSize; - const chunkEnd = chunkDataEnd + 2; // +2 for trailing \r\n - - // Check if we have the complete chunk - if (chunkEnd > remainingBuffer.length) break; - - // Extract the chunk data - const chunkData = remainingBuffer.substring( - chunkDataStart, - chunkDataEnd, - ); - chunks.push(chunkData); - - // Move past this chunk - pos = chunkEnd; - } - - // Update remaining buffer to remove processed chunks - remainingBuffer = remainingBuffer.substring(pos); - - return { chunks, remainingBuffer }; - } -} - /** * HTTPClient provides HTTP communication capabilities over TCP sockets. * Supports GET, POST, and DELETE requests with query parameters and request bodies. diff --git a/test/http.test.ts b/test/http.test.ts deleted file mode 100644 index 21fee4b..0000000 --- a/test/http.test.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { assert, test } from 'vitest'; -import { HTTPParser } from '../lib/http.js'; - -test('parseChunkedBody should parse simple chunked data', () => { - const chunkedData = '5\r\nhello\r\n5\r\nworld\r\n0\r\n\r\n'; - const result = HTTPParser.parseChunkedBody(chunkedData); - assert.deepEqual(result, 'helloworld'); -}); - -test('parseChunkedBody should handle single chunk', () => { - const chunkedData = 'A\r\nhello test\r\n0\r\n\r\n'; - const result = HTTPParser.parseChunkedBody(chunkedData); - assert.deepEqual(result, 'hello test'); -}); - -test('parseChunkedBody should handle empty chunks', () => { - const chunkedData = '0\r\n\r\n'; - const result = HTTPParser.parseChunkedBody(chunkedData); - assert.deepEqual(result, ''); -}); - -test('parseChunkedBody should handle chunks with newlines', () => { - const chunkedData = '6\r\nhello\n\r\n6\r\nworld\n\r\n0\r\n\r\n'; - const result = HTTPParser.parseChunkedBody(chunkedData); - assert.deepEqual(result, 'hello\nworld\n'); -}); - -test('parseChunkedBody should handle hexadecimal chunk sizes', () => { - const chunkedData = 'F\r\nhello wonderful\r\n0\r\n\r\n'; - const result = HTTPParser.parseChunkedBody(chunkedData); - assert.deepEqual(result, 'hello wonderful'); -}); - -test('parseChunkedBody should handle JSON data in chunks', () => { - const jsonData = '{"message":"test"}'; - const chunkSize = jsonData.length.toString(16); - const chunkedData = `${chunkSize}\r\n${jsonData}\r\n0\r\n\r\n`; - const result = HTTPParser.parseChunkedBody(chunkedData); - assert.deepEqual(result, jsonData); -}); - -// Tests for extractChunks function -test('extractChunks should extract single complete chunk', () => { - const buffer = '5\r\nhello\r\n0\r\n\r\n'; - const result = HTTPParser.extractChunks(buffer); - assert.deepEqual(result.chunks.length, 2); - assert.deepEqual(result.chunks[0], 'hello'); - assert.deepEqual(result.chunks[1], ''); -}); - -test('extractChunks should extract multiple complete chunks', () => { - const buffer = '5\r\nhello\r\n5\r\nworld\r\n0\r\n\r\n'; - const result = HTTPParser.extractChunks(buffer); - assert.deepEqual(result.chunks.length, 3); - assert.deepEqual(result.chunks[0], 'hello'); - assert.deepEqual(result.chunks[1], 'world'); - assert.deepEqual(result.chunks[2], ''); -}); - -test('extractChunks should handle incomplete chunk', () => { - const buffer = '5\r\nhel'; - const result = HTTPParser.extractChunks(buffer); - assert.deepEqual(result.chunks.length, 0); - assert.deepEqual(result.remainingBuffer, '5\r\nhel'); -}); - -test('extractChunks should handle incomplete chunk size line', () => { - const buffer = '5'; - const result = HTTPParser.extractChunks(buffer); - assert.deepEqual(result.chunks.length, 0); - assert.deepEqual(result.remainingBuffer, '5'); -}); - -test('extractChunks should handle empty buffer', () => { - const buffer = ''; - const result = HTTPParser.extractChunks(buffer); - assert.deepEqual(result.chunks.length, 0); - assert.deepEqual(result.remainingBuffer, ''); -}); - -test('extractChunks should handle text with newlines', () => { - const buffer = '6\r\nhello\n\r\n6\r\nworld\n\r\n0\r\n\r\n'; - const result = HTTPParser.extractChunks(buffer); - assert.deepEqual(result.chunks.length, 3); - assert.deepEqual(result.chunks[0], 'hello\n'); - assert.deepEqual(result.chunks[1], 'world\n'); - assert.deepEqual(result.chunks[2], ''); -}); - -test('extractChunks should handle hexadecimal chunk sizes', () => { - const buffer = 'A\r\nhello test\r\n0\r\n\r\n'; - const result = HTTPParser.extractChunks(buffer); - assert.deepEqual(result.chunks.length, 2); - assert.deepEqual(result.chunks[0], 'hello test'); - assert.deepEqual(result.chunks[1], ''); -}); - -test('extractChunks should handle partial end marker', () => { - const buffer = '5\r\nhello\r\n0\r\n'; - const result = HTTPParser.extractChunks(buffer); - assert.deepEqual(result.chunks.length, 2); - assert.deepEqual(result.chunks[0], 'hello'); - assert.deepEqual(result.chunks[1], ''); - assert.deepEqual(result.remainingBuffer, ''); -}); - -test('extractChunks should handle mixed complete and incomplete chunks', () => { - const buffer = '5\r\nhello\r\n3\r\nwo'; - const result = HTTPParser.extractChunks(buffer); - assert.deepEqual(result.chunks.length, 1); - assert.deepEqual(result.chunks[0], 'hello'); - assert.deepEqual(result.remainingBuffer, '3\r\nwo'); -});