-
Notifications
You must be signed in to change notification settings - Fork 195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pass push stream through Express middleware/route handler stack #323
Comments
Update regarding the first question: this._checkPush(function (err) {
if (err) {
return callback(err)
}
var pairs = {
promise: [],
response: []
}
self._defaultHeaders(frame, pairs.promise)
pairs.response.push({ name: ':status', value: (frame.status || 200) + '' })
compress(frame.headers, pairs.promise, function (promiseChunks) {
sendPromise(promiseChunks)
+ // Don't send push response headers if 'response' was explicitly set to 'false'.
+ if (frame.response === false)
+ return callback(null)
compress(frame.response, pairs.response, function (responseChunks) {
sendResponse(responseChunks, callback)
})
})
}) By also updating my own code as shown below, I was able to get push working (with the correct headers) without the need for an extra "header collection"-pass through the Express stack. let pushPath = "/path/to/file.txt";
let pushStream = res.push(pushPath, {
status: 200, // default 200
method: "GET",
request: { "accept": "*/*" },
- response: { "content-type": mime.lookup(pushPath) }
+ response: false
});
let pushFakeReq = new http.IncomingMessage();
pushFakeReq.url = pushPath;
pushFakeReq.method = pushStream.method;
Object.assign(pushFakeReq.headers, pushStream.headers);
pushFakeReq.headers["host"] = pushStream.host;
let pushFakeRes = new http.ServerResponse({
"method": pushStream.method,
"httpVersionMajor": 1,
"httpVersionMinor": 1
});
// Make the ServerResponse object "inherit" the pushStream's properties.
for ( let k in pushStream ) {
pushFakeRes[k] = pushStream[k];
}
+pushFakeRes.orgWrite = pushFakeRes.write;
+pushFakeRes.write = function (chunk, encoding, cb) {
+ if ( !this._headerSent ) {
+ this.writeHead(this.statusCode);
+ }
+ this.orgWrite(chunk, encoding, cb);
+}
pushFakeRes.writeHead = writeHeadOverride;
pushFakeRes.writeContinue = writeContinueOverride;
pushFakeRes.orgEnd = pushFakeRes.end;
pushFakeRes.end = endOverride;
let pushOutCb = function (err) {
if ( err ) {
console.error("Error for: " + pushPath, err);
} else {
console.log("No error seemed to have occurred for " + pushPath);
}
};
app._router.handle(pushFakeReq, pushFakeRes, pushOutCb); Since the change to framer.js solves my first question, would it be possible to integrate the provided change into the official spdy_transport module? |
Hi,
This is probably more of a (double) question than an issue, but I'm trying to run a push stream (created with
Response.push(path, opts)
through an existing stack of Express middlewares and route handlers. This way I would be able to use the existing stack (which for example handles compression) instead of having to manually create a file stream and pipe it (i.e.fs.createReadStream("somePathToFile").pipe(pushStream);
).But there are two problems that I've encountered in trying to get this to work:
Firstly the
Response.push()
method expects both the request and response headers, and will send both of them out immediately. But this means that I would need to know which headers will be set by the middlewares and route handlers before actually passing the push stream throughapp._router.handle()
. In other words since the http/2 headers frame was already sent byResponse.push()
, the headers set (and sent?) by the Express middlewares and route handlers will no longer be "seen". One way to circumvent this issue is to go through the Express stack twice, once for collecting the headers (without outputting any data), and once to actually send the data. But this is far from optimal, as for example Express's static middleware will read the file from disk twice (resulting in extra delay).So my question here is: Can I somehow tell the
Response.push()
method to not send the response headers, and let them be sent by the Express middlewares and route handlers.Secondly, the
app._router.handle()
expects a request and response object. Constructing a fake request object was fairly straightforward. But what is the proper way to construct aServerResponse
object using the push stream object that is returned by spdy'sResponse.push()
?Currently I try to do this as shown below by making the
ServerResponse
"inherit" the push stream object and overriding some methods. But this approach isn't really "clean"and only partially works (e.g., piping doesn't work yet).Minor edit: Piping etc. did work, but I forgot to disable sending the headers in my
writeHeadOverride()
which caused the headers to be sent twice. The second header frame was interpreted by Chrome as a (malformed, e.g., it doesn't have the END_STREAM flag) trailing header, which caused an HTTP2_STREAM_ERROR (which didn't seem to propagate to my Node code?). My two questions still remain though...The override functions:
Click to expand
Any feedback would be greatly appreciated.
The text was updated successfully, but these errors were encountered: