Переопределение Node.js парсера HTTP - PullRequest
8 голосов
/ 27 марта 2012

Я использую базовую функцию Node http.request() без проблем на обычных HTTP-серверах. Мне нужно использовать http.request() (или подобное) с серверами SHOUTcast. «Протокол» SHOUTcast полностью совместим с HTTP, за исключением одной детали ... первая строка ответа.

Обычные HTTP-серверы отвечают:

HTTP/1.1 200 OK

Серверы SHOUTcast отвечают:

ICY 200 OK

Опять же, остальная часть протокола такая же. Единственная разница - HTTP/1.x против ICY.

Я хотел бы расширить, создать подкласс или как-то изменить функцию Node http.request(), чтобы она могла работать с серверами SHOUTcast. Подключение к SHOUTcast с узлом было сделано до , но только путем переизобретения всего колеса. Я бы предпочел не делать этого за небольшую разницу в протоколе.

Мой вопрос: есть ли способ сделать одно из следующих действий?

  1. Расширение или переопределение соответствующих частей синтаксического анализатора HTTP узла. (Я сомневаюсь, что это возможно, так как кажется, синтаксический анализатор является собственным кодом .)

  2. Создать свой собственный бит кода, который анализирует соответствующие части HTTP, но использует как можно больше существующих компонентов Node для HTTP.

  3. Создайте простой внутренний прокси (или как-то ретранслируйте данные), чтобы я мог изменить эту первую строку ответа сервера до того, как она достигнет парсера HTTP узла.

  4. Что-то еще?

Я также рассмотрел использование Shred , но он не предлагает возможность потоковой передачи ответа. (Он ожидает завершения полного ответа сервера, прежде чем запустить событие, которое не будет работать для потоковых серверов, на которых данные могут работать бесконечно.) В этих же строках я попытался Запрос , но он использует Собственный HTTP-парсер Node, поэтому я получаю те же ошибки синтаксического анализа, что и с собственным HTTP-клиентом.

Ответы [ 2 ]

5 голосов
/ 25 августа 2012

Я придумал другой способ сделать это, похожий на внутренний прокси, но без дополнительного подключения.Похоже, что можно переопределить внутренний сокет для HTTP-клиента.Когда это сделано, легко подключить и изменить данные, прежде чем передать их в исходную функцию внутреннего гнезда ondata.

Использование

var httpicy = new HttpIcyClient();
httpicy.request(/* your normal request parameters here */);

Источник

var http = require('http');

var HttpIcyClient = function () {};
HttpIcyClient.prototype.request = function (options, callback) {
    var req = http.request(options, callback),
        originalOnDataFunction,
        receiveBuffer = new Buffer(0);

    req.on('socket', function (socket) {
        originalOnDataFunction = socket.ondata;
        socket.ondata = function (d, start, end) {
            receiveBuffer = Buffer.concat([receiveBuffer, d.slice(start, end)]);
            if (receiveBuffer.length >= 4) {
                socket.ondata = originalOnDataFunction;
                if (receiveBuffer.toString('ascii', 0, 4) === 'ICY ') {
                    receiveBuffer = Buffer.concat([new Buffer('HTTP/1.0 ', 'ascii'), receiveBuffer.slice(4)]);
                }
                socket.ondata.apply(this, [receiveBuffer, 0, receiveBuffer.length]);
            }
        };
    });
    return req;
}
1 голос
/ 27 марта 2012

3.Создайте простой внутренний прокси

Bang. Вы получили его.

Используйте Node.js net объект для созданияTCP-сервер, который фактически находится между пользователем и http-сервером.Замените первую строку всех запросов и ответов, как вы описали, и вы можете продолжать использовать http-сервер практически как есть.(Вы создаете внутренний http-сервер на нестандартном порту, сетевой сервер на другом порту, а затем объединяете потоки между ними с небольшим количеством кода для перехвата первой порции данных запрашивающего пользователя и первой порцииданных с отвечающего сервера.)

Весь ваш код в Javascript, и он весь потоковый (почти) без буфера обмена.

РЕДАКТИРОВАТЬ, кажется, я немного неправильно прочитал ваш пост.Я вижу, что вы не пытаетесь реализовать сервер shoutcast для Node.js, а пытаетесь получить доступ к данным с него.Объект net должен все еще работать, но не совсем так.

Вам нужно будет использовать net.connect для связи с указанным сервером shoutcast и использовать новый сервер net, который знаето потоке net.connect на прокси между ним и вашим http.request().Итак, это будет работать примерно так:

+---------------+    +----------+    +-----------+    +----------------+
| http.request()|--->|net.Server|--->|net.connect|--->|SHOUTcast Server|
|               |<---|          |<---|           |<---|                |
+---------------+    +----------+    +-----------+    +----------------+
                  TCP             JS               TCP

Вот как я бы это структурировал.

...