CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-http-parser-js

A pure JavaScript HTTP parser for Node.js, compatible replacement for http_parser.c

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

HTTP Parser JS

HTTP Parser JS is a pure JavaScript HTTP protocol parser for Node.js that serves as a compatible replacement for the native C++ http_parser.c. It provides more flexible and tolerant parsing of HTTP messages, making it ideal for working with legacy services that don't meet strict HTTP parsing standards.

Package Information

  • Package Name: http-parser-js
  • Package Type: npm
  • Language: JavaScript with TypeScript definitions
  • Installation: npm install http-parser-js

Core Imports

const { HTTPParser } = require("http-parser-js");

For accessing the methods array:

const { HTTPParser, methods } = require("http-parser-js");

Basic Usage

Monkey-patching Node.js HTTP Parser

The primary intended use is to replace Node.js's built-in HTTP parser:

// Monkey patch before requiring http for the first time
process.binding('http_parser').HTTPParser = require('http-parser-js').HTTPParser;

const http = require('http');
// Now Node.js will use the JavaScript parser

Standalone Usage

const { HTTPParser } = require('http-parser-js');

// Parse an HTTP request
const parser = new HTTPParser(HTTPParser.REQUEST);
let requestData = {};

parser[HTTPParser.kOnHeadersComplete] = function(req) {
  requestData.method = HTTPParser.methods[req.method];
  requestData.url = req.url;
  requestData.headers = req.headers;
  requestData.versionMajor = req.versionMajor;
  requestData.versionMinor = req.versionMinor;
};

parser[HTTPParser.kOnBody] = function(chunk, offset, length) {
  console.log('Body chunk:', chunk.slice(offset, offset + length));
};

parser[HTTPParser.kOnMessageComplete] = function() {
  console.log('Parsing complete');
};

// Execute parsing
const httpMessage = Buffer.from('GET / HTTP/1.1\\r\\nHost: example.com\\r\\n\\r\\n');
parser.execute(httpMessage);
parser.finish();

Architecture

HTTP Parser JS is designed around a single main class with callback-based event handling:

  • HTTPParser Class: Main parser that handles both REQUEST and RESPONSE parsing modes
  • Event-Driven Architecture: Uses callback functions for different parsing events (headers, body, completion)
  • State Machine: Internal state management for parsing different parts of HTTP messages
  • Compatibility Layer: Maintains API compatibility with Node.js's native http_parser
  • Error Tolerant: More lenient parsing compared to strict HTTP specification compliance

Capabilities

HTTPParser Constructor

Creates a new HTTP parser instance for parsing requests or responses.

/**
 * Creates a new HTTP parser instance
 * @param {string} [type] - Parser type: HTTPParser.REQUEST or HTTPParser.RESPONSE
 */
function HTTPParser(type) {}

// Static constants
HTTPParser.REQUEST = 'REQUEST';
HTTPParser.RESPONSE = 'RESPONSE';
HTTPParser.encoding = 'ascii';
HTTPParser.maxHeaderSize = 81920; // 80KB default

// Event constants
HTTPParser.kOnHeaders = 1;
HTTPParser.kOnHeadersComplete = 2;
HTTPParser.kOnBody = 3;
HTTPParser.kOnMessageComplete = 4;

Parser Initialization

Initialize or reinitialize the parser with a specific type.

/**
 * Initialize parser with type and optional async resource
 * @param {string} type - HTTPParser.REQUEST or HTTPParser.RESPONSE
 * @param {*} [async_resource] - Optional async resource for tracking
 */
initialize(type, async_resource) {}

/**
 * Reinitialize parser (alias to constructor)
 */
reinitialize(type) {}

HTTP Message Parsing

Execute parsing on HTTP data and signal completion.

/**
 * Parse HTTP data from buffer
 * @param {Buffer} chunk - Buffer containing HTTP data
 * @param {number} [start=0] - Start offset in buffer
 * @param {number} [length] - Length to parse, defaults to chunk.length
 * @returns {number|Error} Number of bytes parsed or Error object on failure
 */
execute(chunk, start, length) {}

/**
 * Signal end of HTTP message
 * @returns {void|Error} Error object if called in invalid state
 */
finish() {}

Event Handlers

Set callback functions for parsing events.

// Event handler properties (assign functions to these)
parser[HTTPParser.kOnHeaders] = function(headers, url) {
  // Called for trailer headers in chunked encoding
};

parser[HTTPParser.kOnHeadersComplete] = function(info) {
  // Called when all headers are parsed
  // info contains: versionMajor, versionMinor, headers, method, url, 
  // statusCode, statusMessage, upgrade, shouldKeepAlive
};

parser[HTTPParser.kOnBody] = function(chunk, offset, length) {
  // Called for each body data chunk
};

parser[HTTPParser.kOnMessageComplete] = function() {
  // Called when entire HTTP message is parsed
};

Header and Connection Analysis

Utilities for analyzing parsed HTTP data.

/**
 * Parse individual header line
 * @param {string} line - Header line to parse
 * @param {string[]} headers - Array to append parsed header to
 */
parseHeader(line, headers) {}

/**
 * Check if connection should be kept alive
 * @returns {boolean} True if connection should persist
 */
shouldKeepAlive() {}

/**
 * Complete current message and prepare for next request
 */
nextRequest() {}

/**
 * Consume a line from the input buffer (internal method)
 * @returns {string|void} Parsed line or undefined if incomplete
 */
consumeLine() {}

Instance Properties and Configuration

Parser configuration and state properties.

// Instance properties
parser.maxHeaderSize = 81920; // Max header size in bytes

// Compatibility stub methods (no-ops)
parser.close = function() {};
parser.pause = function() {};
parser.resume = function() {};
parser.remove = function() {};
parser.free = function() {};
parser.consume = function() {};
parser.unconsume = function() {};
parser.getCurrentBuffer = function() {};
parser.getAsyncId = function() { return 0; };

HTTP Methods Array

Array of all supported HTTP methods.

/**
 * Array of supported HTTP method strings
 */
const methods = [
  'DELETE', 'GET', 'HEAD', 'POST', 'PUT', 'CONNECT', 'OPTIONS', 'TRACE',
  'COPY', 'LOCK', 'MKCOL', 'MOVE', 'PROPFIND', 'PROPPATCH', 'SEARCH', 'UNLOCK',
  'BIND', 'REBIND', 'UNBIND', 'ACL', 'REPORT', 'MKACTIVITY', 'CHECKOUT', 'MERGE',
  'M-SEARCH', 'NOTIFY', 'SUBSCRIBE', 'UNSUBSCRIBE', 'PATCH', 'PURGE', 'MKCALENDAR',
  'LINK', 'UNLINK', 'SOURCE'
];

// Also available as HTTPParser.methods

Error Utilities

Internal error handling utilities.

/**
 * Create a standardized parse error with error code
 * @param {string} code - Error code (HPE_LF_EXPECTED, HPE_INVALID_CONSTANT, etc.)
 * @returns {Error} Error object with code property
 */
function parseErrorCode(code) {}

Internal Parsing Methods

Internal state machine methods used during HTTP parsing. These methods are called automatically by the parser and generally should not be called directly.

/**
 * Parse HTTP request line (internal state method)
 */
REQUEST_LINE() {}

/**
 * Parse HTTP response line (internal state method)
 */
RESPONSE_LINE() {}

/**
 * Parse header lines (internal state method)
 * @returns {void|boolean} May return true to indicate upgrade request
 */
HEADER() {}

/**
 * Parse chunked transfer encoding header (internal state method)
 */
BODY_CHUNKHEAD() {}

/**
 * Parse chunked transfer encoding body (internal state method)
 */
BODY_CHUNK() {}

/**
 * Parse empty line after chunk (internal state method)
 */
BODY_CHUNKEMPTYLINE() {}

/**
 * Parse chunked transfer encoding trailers (internal state method)
 */
BODY_CHUNKTRAILERS() {}

/**
 * Parse raw body data (internal state method)
 */
BODY_RAW() {}

/**
 * Parse sized body data (internal state method)
 */
BODY_SIZED() {}

Legacy Compatibility

Getter/setter properties for older Node.js versions.

// Legacy callback properties (Node.js < 0.11.6)
parser.onHeaders = function(headers, url) {};
parser.onHeadersComplete = function(info) {};
parser.onBody = function(chunk, offset, length) {};
parser.onMessageComplete = function() {};

Types

type ParserType = 'REQUEST' | 'RESPONSE';

type RequestMethod = 
  | 'DELETE' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'CONNECT' | 'OPTIONS' | 'TRACE'
  | 'COPY' | 'LOCK' | 'MKCOL' | 'MOVE' | 'PROPFIND' | 'PROPPATCH' | 'SEARCH' | 'UNLOCK'
  | 'BIND' | 'REBIND' | 'UNBIND' | 'ACL' | 'REPORT' | 'MKACTIVITY' | 'CHECKOUT' | 'MERGE'
  | 'M-SEARCH' | 'NOTIFY' | 'SUBSCRIBE' | 'UNSUBSCRIBE' | 'PATCH' | 'PURGE' | 'MKCALENDAR'
  | 'LINK' | 'UNLINK' | 'SOURCE'
  | string;

type HeaderObject = Array<string>;

interface HeaderInfo {
  versionMajor: number;
  versionMinor: number;
  headers: HeaderObject;
  method: number;
  url: string;
  statusCode: number;
  statusMessage: string;
  upgrade: boolean;
  shouldKeepAlive: boolean;
}

type OnHeadersCompleteParser = (info: HeaderInfo) => number | void;
type OnBodyParser = (chunk: Buffer, offset: number, length: number) => void;
type OnHeadersParser = (headers: string[], url: string) => void;
type OnMessageCompleteParser = () => void;

interface HTTPParserConstructor {
  new(type?: ParserType): HTTPParser;
  (type?: ParserType): void;
  
  readonly REQUEST: 'REQUEST';
  readonly RESPONSE: 'RESPONSE';
  readonly methods: RequestMethod[];
  
  encoding: string;
  maxHeaderSize: number;
  
  readonly kOnHeaders: 1;
  readonly kOnHeadersComplete: 2;
  readonly kOnBody: 3;
  readonly kOnMessageComplete: 4;
}

interface HTTPParser {
  initialize(type: ParserType, async_resource?: unknown): void;
  execute(chunk: Buffer, start?: number, length?: number): number | Error;
  finish(): void | Error;
  
  maxHeaderSize: number;
  
  [HTTPParser.kOnHeaders]: OnHeadersParser;
  [HTTPParser.kOnHeadersComplete]: OnHeadersCompleteParser;
  [HTTPParser.kOnBody]: OnBodyParser;
  [HTTPParser.kOnMessageComplete]: OnMessageCompleteParser;
  
  // Legacy compatibility
  onHeaders: OnHeadersParser;
  onHeadersComplete: OnHeadersCompleteParser;
  onBody: OnBodyParser;
  onMessageComplete: OnMessageCompleteParser;
  
  // Utility methods
  parseHeader(line: string, headers: string[]): void;
  shouldKeepAlive(): boolean;
  userCall<T>(): (ret?: T) => T;
  nextRequest(): void;
  consumeLine(): string | void;
  
  // Internal properties
  _compatMode0_11: boolean;
  
  // Stub methods
  reinitialize(type: ParserType): void;
  close(): void;
  pause(): void;
  resume(): void;
  remove(): void;
  free(): void;
  consume(): void;
  unconsume(): void;
  getCurrentBuffer(): void;
  getAsyncId(): number;
}

Usage Examples

Parsing HTTP Request

const { HTTPParser } = require('http-parser-js');

function parseRequest(input) {
  const parser = new HTTPParser(HTTPParser.REQUEST);
  let complete = false;
  let shouldKeepAlive, method, url, headers = [], bodyChunks = [];

  parser[HTTPParser.kOnHeadersComplete] = function(req) {
    shouldKeepAlive = req.shouldKeepAlive;
    method = HTTPParser.methods[req.method];
    url = req.url;
    headers = req.headers;
  };

  parser[HTTPParser.kOnBody] = function(chunk, offset, length) {
    bodyChunks.push(chunk.slice(offset, offset + length));
  };

  parser[HTTPParser.kOnMessageComplete] = function() {
    complete = true;
  };

  parser.execute(input);
  parser.finish();

  if (!complete) {
    throw new Error('Could not parse request');
  }

  return {
    shouldKeepAlive,
    method,
    url,
    headers,
    body: Buffer.concat(bodyChunks)
  };
}

// Usage
const request = Buffer.from('GET /path HTTP/1.1\\r\\nHost: example.com\\r\\n\\r\\n');
const parsed = parseRequest(request);
console.log(parsed.method); // 'GET'
console.log(parsed.url);    // '/path'

Parsing HTTP Response

function parseResponse(input) {
  const parser = new HTTPParser(HTTPParser.RESPONSE);
  let complete = false;
  let statusCode, statusMessage, headers = [], bodyChunks = [];

  parser[HTTPParser.kOnHeadersComplete] = function(res) {
    statusCode = res.statusCode;
    statusMessage = res.statusMessage;
    headers = res.headers;
  };

  parser[HTTPParser.kOnBody] = function(chunk, offset, length) {
    bodyChunks.push(chunk.slice(offset, offset + length));
  };

  parser[HTTPParser.kOnMessageComplete] = function() {
    complete = true;
  };

  parser.execute(input);
  parser.finish();

  return {
    statusCode,
    statusMessage,
    headers,
    body: Buffer.concat(bodyChunks)
  };
}

// Usage
const response = Buffer.from('HTTP/1.1 200 OK\\r\\nContent-Length: 5\\r\\n\\r\\nHello');
const parsed = parseResponse(response);
console.log(parsed.statusCode);    // 200
console.log(parsed.statusMessage); // 'OK'
console.log(parsed.body.toString()); // 'Hello'

Error Handling

The parser returns Error objects for various parsing failures:

const result = parser.execute(malformedData);
if (result instanceof Error) {
  console.error('Parse error:', result.message);
  if (result.code) {
    console.error('Error code:', result.code);
  }
}

// Common error codes
// HPE_LF_EXPECTED - Line feed expected
// HPE_INVALID_CONSTANT - Invalid HTTP constant
// HPE_UNEXPECTED_CONTENT_LENGTH - Duplicate/conflicting Content-Length headers

Compatibility Notes

  • Node.js Support: Works with Node.js v6-v11, v13-v14 via monkey-patching
  • Node.js v12: Requires --http-parser=legacy flag for monkey-patching
  • Tolerant Parsing: More lenient than Node's strict parser for malformed HTTP data
  • Header Size Limits: Configurable via maxHeaderSize property (default 80KB)
  • Chunked Transfer Encoding: Full support including trailer headers
  • Connection Management: Automatic keep-alive detection based on HTTP version and headers
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/http-parser-js@0.5.x
Publish Source
CLI
Badge
tessl/npm-http-parser-js badge