简体   繁体   English

覆盖Node.js HTTP解析器

[英]Overriding Node.js HTTP parser

I am using Node's basic http.request() function without problem on normal HTTP servers. 我在正常的HTTP服务器上使用Node的基本http.request()函数没有问题。 I need to use http.request() (or similar) with SHOUTcast servers. 我需要在SHOUTcast服务器上使用http.request() (或类似的)。 The SHOUTcast "protocol" is fully compatible with HTTP, except for one detail... the first response line. SHOUTcast“协议”与HTTP完全兼容,除了一个细节......第一个响应行。

Normal HTTP servers respond with: 普通HTTP服务器响应:

HTTP/1.1 200 OK

SHOUTcast servers respond with: SHOUTcast服务器响应:

ICY 200 OK

Again, the rest of the protocol is the same. 同样,协议的其余部分是相同的。 The only difference is HTTP/1.x vs. ICY . 唯一的区别是HTTP/1.xICY

I would like to extend, subclass, or somehow modify Node's http.request() function so that I can make it work with SHOUTcast servers. 我想扩展,子类或以某种方式修改Node的http.request()函数,以便我可以使它与SHOUTcast服务器一起使用。 Connecting to SHOUTcast with Node has been done before , but only by re-inventing the entire wheel. 之前已经完成了与节点连接到SHOUTcast,但只能通过重新发明整个轮子。 I'd rather not do that for what amounts to be a minor protocol difference. 我宁愿不这样做,因为它只是一个小的协议差异。

My Question: Is there a way to do one of the following? 我的问题:有没有办法做到以下其中一种?

  1. Extend or override the relevant parts of Node's HTTP parser. 扩展或覆盖 Node的HTTP解析器的相关部分。 (I doubt this is possible, as it seems the parser is native code .) (我怀疑这是可能的,因为解析器似乎是本机代码 。)

  2. Create my own bit of code that parses the relevant parts of HTTP, but reuses as many existing Node components for HTTP as possible. 创建我自己的代码来解析HTTP的相关部分,但尽可能多地重用HTTP的现有Node组件。

  3. Create a simple internal proxy (or somehow relay data) so that I can modify that first server response line prior to it reaching Node's HTTP parser. 创建一个简单的内部代理 (或以某种方式中继数据),以便我可以在它到达Node的HTTP解析器之前修改第一个服务器响应行。

  4. Something else? 别的什么?

I have also considered using Shred , but it does not offer an option to stream the response. 我也考虑过使用Shred ,但它没有提供流式响应的选项。 (It waits for the entire server response to be complete before firing an event, which won't work for streaming servers where the data can run indefinitely.) Along those same lines, I tried Request , but it uses Node's own HTTP parser, so I get the same parse errors as I would with the native HTTP client. (它等待整个服务器响应在触发事件之前完成,这对于数据无限期运行的流服务器不起作用。)沿着同样的路线,我尝试了Request ,但它使用了Node自己的HTTP解析器,所以我得到与原生HTTP客户端相同的解析错误。

I've come up with another way to do this, similar to the internal proxy, but without the extra connection. 我想出了另一种方法,类似于内部代理,但没有额外的连接。 It seems that it is possible to override the internally used socket for the HTTP client. 似乎可以覆盖HTTP客户端的内部使用的套接字。 When this is done, it is easy to hook in and modify data before passing it off to the original internal socket ondata function. 完成此操作后,在将数据传递给原始内部套接字ondata函数之前,很容易挂钩并修改数据。

Usage 用法

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

Source 资源

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 . 3。 Create a simple internal proxy 创建一个简单的内部代理

Bang. 砰。 You got it. 你说对了。

Use the Node.js net object to create a TCP server that actually sits between the user and the http server. 使用Node.js net对象创建实际位于用户和http服务器之间的TCP服务器。 Replace the first line of all requests and responses as you've described, and you can continue to use http server essentially as-is. 如您所述,替换所有请求和响应的第一行,您可以继续按原样继续使用http服务器。 (You create an internal http server on a non-standard port, the net server on another port, then chain up streams between the two, with a bit of code to intercept the first chunk of data from the requesting user, and the first chunk of data from the responding server.) (您在非标准端口上创建内部http服务器,在另一个端口上创建网络服务器,然后在两者之间链接流,使用一些代码拦截来自请求用户的第一个数据块,以及第一个块来自响应服务器的数据。)

All of your code in Javascript and it's all streaming with (almost) no bufferbloat. 你在Javascript中的所有代码,它都是(几乎)没有bufferbloat流。

EDIT, it seems I misread your post slightly. 编辑,似乎我误读了你的帖子。 I see that you're not trying to implement a Node.js shoutcast server, but trying to access data from it. 我看到你并没有尝试实现Node.js shoutcast服务器,而是尝试从中访问数据。 The net object should still work, but not quite in the same way. net对象应该仍然可以工作,但不是完全相同。

You'll need to use net.connect to talk to the specified shoutcast server, and use a new net server that knows about the net.connect stream to proxy between it and your http.request() . 您需要使用net.connect与指定的shoutcast服务器通信,并使用一个知道net.connect流的新net服务器来代理它与您的http.request()之间的代理。 So, it would work like: 所以,它会像:

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

That's about how I'd structure it. 那就是我如何构建它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM