Node.js создать объект из строки необработанного HTTP-запроса

У меня есть необработанная строка запроса HTTP, из которой мне нужно создать представление объекта.

Вместо того, чтобы изобретать колесо, я думал об использовании внутреннего парсера http, чтобы получить экземпляр http.IncomingMessage

Возможно ли это?

Я так думаю, потому что строка не так сильно отличается от полного потока.

Как это сделать?

Я посмотрел исходный код, и они получили парсер запросов, как следует

var HTTPParser = process.binding('http_parser').HTTPParser;
var parser = new HTTPParser(HTTPParser.REQUEST)

Edit

Некоторый прогресс от node.js test

var request = Buffer(raw);
var parser = new HTTPParser(HTTPParser.REQUEST);

parser.execute(request, 0, request.length);

Изменить 2

Некоторые eventHandlers отсутствовали (все они)

parser.onHeadersComplete = function(res) {
    console.log('onHeadersComplete');
    console.log(res);
};

parser.onBody = function(body) {
    console.log('body done');
    console.log(body.toString());
}

parser.onMessageComplete = function(res) {
    console.log('done');
};

Спасибо

Ответы

Ответ 1

По-видимому, модуль http_parser является низкоуровневым парсером на основе обратного вызова. Он отправит любые части строки, которые он сможет проанализировать, используя эти обратные вызовы, и вам решать сделать IncomingMessage или что-то еще, что вам нужно от них.

Я считаю, что что-то вроде этого может быть тем, что вы ищете:

var HTTPParser = process.binding('http_parser').HTTPParser;

function parseMessage(request) {
    var _message = {};
    var _parser = new HTTPParser(HTTPParser.REQUEST);

    _parser.onHeadersComplete = function(headers) { 
        _message = headers; 
    }

    _parser.onBody = function(body, start, len) {
        _message.data = body.slice(start, start+len);
    }

    var _result = _parser.execute(request, 0, request.length);

    if (_result != request.length) { 
        _message.error = _result; 
    }
    else {
        _message.error = false;
    }
    return _message;
}

var request = Buffer("GET / HTTP/1.1\nHost: localhost\nContent-Length: 2\n\nHi\n\n");
result = parseMessage(request);

Обратите внимание, что конкретный класс IncomingMessage параметризуется socket и обычно строится вокруг идеи его использования на сервере. Код для его синтаксического анализа несколько запутан, чтобы повторно использовать as-is (по моему вкусу).

Ответ 2

Старая тема, но я что-то скажу.

Экспорт HTTPParser в собственные материалы (модуль или приложение) не так прост, потому что http-библиотека использует множество внутренних локальных функций и конструкторов. Кроме того, сам HTTPParser связан с библиотекой C и некоторыми помощниками.

Как я знаю, http.parsers был удален из Node > 4, поэтому единственный способ - импортировать все необходимые вещи из библиотеки http.

Для Node 0.x есть простой способ импорта:

var parser = require("http").parsers.alloc();

parser.onIncoming = function(response) {
  console.log(response);
};

function parse(data) {
    var buffer = new Buffer(data);
    parser.execute(buffer, 0, buffer.length);
}
/**
 * tests
 */
parse("DELETE / HTTP/1.1\r\n");
parse("user-agent: curl\r\n");
parse("x-pingback:");
parse("12023\r\n");
parse("\r\n");

//response
{ _readableState: 
   { highWaterMark: 16384,
     buffer: [],
     length: 0,
     pipes: null,
     pipesCount: 0,
     flowing: false,
     ended: false,
     endEmitted: false,
     reading: false,
     calledRead: false,
     sync: true,
     needReadable: false,
     emittedReadable: false,
     readableListening: false,
     objectMode: false,
     defaultEncoding: 'utf8',
     ranOut: false,
     awaitDrain: 0,
     readingMore: false,
     decoder: null,
     encoding: null },
  readable: true,
  domain: null,
  _events: {},
  _maxListeners: 10,
  socket: undefined,
  connection: undefined,
  httpVersion: '1.1',
  complete: false,
  headers: { 'user-agent': 'curl', 'x-pingback': '12023' },
  trailers: {},
  _pendings: [],
  _pendingIndex: 0,
  url: '/',
  method: 'DELETE',
  statusCode: null,
  client: undefined,
  _consuming: false,
  _dumped: false,
  httpVersionMajor: 1,
  httpVersionMinor: 1,
  upgrade: false }

Подробнее здесь

Кроме того, благодаря @KT для элегантного решения