Skip to content
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

http_parser takes one byte to much, upgrade websockets #17789

Closed
quazzie opened this issue Dec 20, 2017 · 9 comments
Closed

http_parser takes one byte to much, upgrade websockets #17789

quazzie opened this issue Dec 20, 2017 · 9 comments
Labels
http Issues or PRs related to the http subsystem.

Comments

@quazzie
Copy link

quazzie commented Dec 20, 2017

  • Version: v9.2.0
  • Platform: Windows 64bit
  • Subsystem: http_parser

http_parser takes one byte to much from this:
`HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade
Transfer-Encoding: chunked
Sec-Websocket-Accept: aFYFO80e6Cf2ijYLvl+mWNmnXtg=
Sec-Websocket-Extensions: permessage-deflate
Content-Type: application/octet-stream
Date: Wed, 20 Dec 2017 14:17:57 GMT
Server: Python/3.6 aiohttp/2.3.5
EndTime: 15:17:58.104
ReceivedBytes: 0
SentBytes: 0

Á+ªV*©,HU²RPJ,-É�ÏÏVÒQPÊH�/K-*ÎÌÏ�I�è�Zê�)Õ� `

Base64 of data:
SFRUUC8xLjEgMTAxIFN3aXRjaGluZyBQcm90b2NvbHMNClVwZ3JhZGU6IHdlYnNvY2tldA0KQ29ubmVjdGlvbjogdXBncmFkZQ0KVHJhbnNmZXItRW5jb2Rpbmc6IGNodW5rZWQNClNlYy1XZWJzb2NrZXQtQWNjZXB0OiBhRllGTzgwZTZDZjJpallMdmwrbVdObW5YdGc9DQpTZWMtV2Vic29ja2V0LUV4dGVuc2lvbnM6IHBlcm1lc3NhZ2UtZGVmbGF0ZQ0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0NCkRhdGU6IFdlZCwgMjAgRGVjIDIwMTcgMTQ6MTc6NTcgR01UDQpTZXJ2ZXI6IFB5dGhvbi8zLjYgYWlvaHR0cC8yLjMuNQ0KRW5kVGltZTogMTU6MTc6NTguMTA0DQpSZWNlaXZlZEJ5dGVzOiAwDQpTZW50Qnl0ZXM6IDANCg0KwSuqViqpLEhVslJQSiwtyYjPz1bSUVDKSIwvSy0qzszPA0kY6Jla6hkp1QIA

The upgraded socket connection is missing Á in its buffer.
Works if i use npm: http-parser-js.

@bnoordhuis bnoordhuis added the http Issues or PRs related to the http subsystem. label Dec 20, 2017
@bnoordhuis
Copy link
Member

Can you post steps to reproduce?

@quazzie
Copy link
Author

quazzie commented Dec 20, 2017

Hmm not really without setting up a whole system..

Server is homeassistant (http://hass.io).

Code to trigger error in node:

const WebSocket = require('ws');
const conn = new WebSocket('ws://homeassistantip:8123/api/websocket');

Tried to debug the internals of node but only got to socketOnData in _http_client.js
There i saw that parser.execute returned a length that takes an extra byte of the data.

@quazzie
Copy link
Author

quazzie commented Dec 20, 2017

Maybe if one instantiated a http_parser and tried to parse the data i posted it could return the same error.. i'll have to check on that tomorrow.

@bnoordhuis
Copy link
Member

A simple test case that starts a server with http.createServer() and sends a raw request with net.connect() and socket.write() is perfectly acceptable. As long as it fails the same way on your and my machine.

@quazzie
Copy link
Author

quazzie commented Dec 21, 2017

Testcase:
need is the data i was expecting back after the upgrade.
But the data i get is missing the first websocket framing byte (contains FIN and OPCODE).

const http = require('http');

const response = new Buffer("SFRUUC8xLjEgMTAxIFN3aXRjaGluZyBQcm90b2NvbHMNClVwZ3JhZGU6IHdlYnNvY2tldA0KQ29ubmVjdGlvbjogdXBncmFkZQ0KVHJhbnNmZXItRW5jb2Rpbmc6IGNodW5rZWQNClNlYy1XZWJzb2NrZXQtQWNjZXB0OiBQelViSG45N2lFcHcrczZmc1hGcVMvYUlyQjg9DQpDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbQ0KRGF0ZTogV2VkLCAyMCBEZWMgMjAxNyAxMzo1ODo1MyBHTVQNClNlcnZlcjogUHl0aG9uLzMuNiBhaW9odHRwLzIuMy41DQpFbmRUaW1lOiAxNDo1ODo1Ni44NzUNClJlY2VpdmVkQnl0ZXM6IDANClNlbnRCeXRlczogMA0KDQqBK3sidHlwZSI6ICJhdXRoX29rIiwgImhhX3ZlcnNpb24iOiAiMC41OS4yIn0=", "base64");
const need = new Buffer("gSt7InR5cGUiOiAiYXV0aF9vayIsICJoYV92ZXJzaW9uIjogIjAuNTkuMiJ9", "base64");

const server = http.createServer(function(req, res) {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('okay');
});
server.on('upgrade', (req, socket, head) => {
  socket.write(response);
  socket.pipe(socket); // echo back
});
server.listen(7000, () => {
  const req = http.request({ 
    hostname: 'localhost', 
    port: 7000, 
    headers: { 
      'Sec-WebSocket-Version': 13,
      'Sec-WebSocket-Key': '8ABg8JJUAN8w8NtnY1A1XA==',
      'Connection': 'Upgrade',
      'Upgrade': 'websocket',
      'Host': 'localhost:7000'
    } 
  });
  req.end();

  req.on('upgrade', (res, socket, upgradeHead) => {
    console.assert(upgradeHead.length === need.length, 'Length mismatch');
  });
});

@quazzie
Copy link
Author

quazzie commented Dec 21, 2017

Or need can even be a slice of response for better clarity maybe.
const need = response.slice(-45);

@bnoordhuis
Copy link
Member

Thanks, I can reproduce and a fix is on the way.

I'm surprised this bug managed to stay hidden for so long. I thought at first it must be a recent regression but it seems to have been around for some time.

@Fishrock123
Copy link
Contributor

I guess people don't often send body data in upgrade requests? Good catch either way.

@quazzie thanks for coming up with a testcase!

@lpinca
Copy link
Member

lpinca commented Jan 6, 2018

I guess people don't often send body data in upgrade requests? Good catch either way.

This, RFC 6455 (WebSocket) says that data transfer should start only after a successful opening handshake.

bnoordhuis added a commit to bnoordhuis/io.js that referenced this issue Jan 19, 2018
Fix a bug where a connection upgrade response with a Transfer-Encoding
header and a body whose first byte is > 127 causes said byte to be
dropped on the floor when passing the remainder of the message to
the 'upgrade' event listeners.

Fixes: nodejs#17789
evanlucas pushed a commit that referenced this issue Jan 30, 2018
Fix a bug where a connection upgrade response with a Transfer-Encoding
header and a body whose first byte is > 127 causes said byte to be
dropped on the floor when passing the remainder of the message to
the 'upgrade' event listeners.

Fixes: #17789

PR-URL: #17806
Fixes: #17789
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
evanlucas pushed a commit that referenced this issue Jan 30, 2018
Fix a bug where a connection upgrade response with a Transfer-Encoding
header and a body whose first byte is > 127 causes said byte to be
dropped on the floor when passing the remainder of the message to
the 'upgrade' event listeners.

Fixes: #17789

PR-URL: #17806
Fixes: #17789
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
MylesBorins pushed a commit that referenced this issue Apr 11, 2018
Fix a bug where a connection upgrade response with a Transfer-Encoding
header and a body whose first byte is > 127 causes said byte to be
dropped on the floor when passing the remainder of the message to
the 'upgrade' event listeners.

Fixes: #17789

PR-URL: #17806
Fixes: #17789
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
MayaLekova pushed a commit to MayaLekova/node that referenced this issue May 8, 2018
Fix a bug where a connection upgrade response with a Transfer-Encoding
header and a body whose first byte is > 127 causes said byte to be
dropped on the floor when passing the remainder of the message to
the 'upgrade' event listeners.

Fixes: nodejs#17789

PR-URL: nodejs#17806
Fixes: nodejs#17789
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
http Issues or PRs related to the http subsystem.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants