正在重写Node.js HTTP解析器

Overriding Node.js HTTP parser

本文关键字:HTTP js 重写 Node      更新时间:2023-09-26

我在普通HTTP服务器上使用Node的基本http.request()函数没有问题。我需要将http.request()(或类似的)与SHOUTcast服务器一起使用。SHOUTcast"协议"与HTTP完全兼容,除了一个细节。。。第一条响应线。

普通HTTP服务器响应:

HTTP/1.1 200 OK

SHOUTcast服务器响应:

ICY 200 OK

同样,协议的其余部分是相同的。唯一的区别是HTTP/1.xICY

我想扩展、子类化或以某种方式修改Node的http.request()函数,这样我就可以使它与SHOUTcast服务器一起工作。使用Node连接SHOUTcast以前已经完成,但只是通过重新发明整个轮子。我宁愿不这么做,因为这只是一个小小的协议差异。

我的问题:有没有办法做到以下其中一项

  1. 扩展或覆盖Node的HTTP解析器的相关部分。(我怀疑这是否可能,因为解析器似乎是本地代码。)

  2. 创建我自己的代码,解析HTTP的相关部分,但尽可能多地重用HTTP的现有Node组件。

  3. 创建一个简单的内部代理(或者以某种方式中继数据),这样我就可以在第一个服务器响应行到达Node的HTTP解析器之前修改它。

  4. 还有别的吗

我也考虑过使用Shred,但它没有提供流式传输响应的选项。(在触发事件之前,它会等待整个服务器响应完成,这对于数据可以无限期运行的流式服务器来说是不起作用的。)同样,我尝试了Request,但它使用了Node自己的HTTP解析器,所以我会得到与本机HTTP客户端相同的解析错误。

我想出了另一种方法来实现这一点,类似于内部代理,但没有额外的连接。似乎可以覆盖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;
}

3。创建一个简单的内部代理

你明白了。

使用Node.js net对象创建一个TCP服务器,该服务器实际上位于用户和http服务器之间。如前所述,替换所有请求和响应的第一行,就可以继续按原样使用http服务器。(您在一个非标准端口上创建一个内部http服务器,在另一个端口上创建网络服务器,然后在两者之间链接流,并使用一段代码来拦截来自请求用户的第一块数据和来自响应服务器的第一块数据。)

你所有的代码都是用Javascript编写的,而且都是流式的,(几乎)没有缓冲区。

编辑,我似乎有点误读了你的帖子。我看到你并没有试图实现Node.js shoutcast服务器,而是试图从中访问数据。net对象应该仍然可以工作,但方式不太一样。

您需要使用net.connect与指定的shoutcast服务器进行对话,并使用一个知道net.connect流的新net服务器在它和您的http.request()之间进行代理。因此,它的工作方式如下:

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

这就是我的结构。