• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22'use strict';
23
24require('../common');
25const assert = require('assert');
26
27const net = require('net');
28const http = require('http');
29
30
31let requests_recv = 0;
32let requests_sent = 0;
33let request_upgradeHead = null;
34
35function createTestServer() {
36  return new testServer();
37}
38
39function testServer() {
40  http.Server.call(this, () => {});
41
42  this.on('connection', function() {
43    requests_recv++;
44  });
45
46  this.on('request', function(req, res) {
47    res.writeHead(200, { 'Content-Type': 'text/plain' });
48    res.write('okay');
49    res.end();
50  });
51
52  this.on('upgrade', function(req, socket, upgradeHead) {
53    socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
54                 'Upgrade: WebSocket\r\n' +
55                 'Connection: Upgrade\r\n' +
56                 '\r\n\r\n');
57
58    request_upgradeHead = upgradeHead;
59
60    socket.on('data', function(d) {
61      const data = d.toString('utf8');
62      if (data === 'kill') {
63        socket.end();
64      } else {
65        socket.write(data, 'utf8');
66      }
67    });
68  });
69}
70
71Object.setPrototypeOf(testServer.prototype, http.Server.prototype);
72Object.setPrototypeOf(testServer, http.Server);
73
74
75function writeReq(socket, data, encoding) {
76  requests_sent++;
77  socket.write(data);
78}
79
80
81/*-----------------------------------------------
82  connection: Upgrade with listener
83-----------------------------------------------*/
84function test_upgrade_with_listener() {
85  const conn = net.createConnection(server.address().port);
86  conn.setEncoding('utf8');
87  let state = 0;
88
89  conn.on('connect', function() {
90    writeReq(conn,
91             'GET / HTTP/1.1\r\n' +
92             'Upgrade: WebSocket\r\n' +
93             'Connection: Upgrade\r\n' +
94             '\r\n' +
95             'WjN}|M(6');
96  });
97
98  conn.on('data', function(data) {
99    state++;
100
101    assert.strictEqual(typeof data, 'string');
102
103    if (state === 1) {
104      assert.strictEqual(data.substr(0, 12), 'HTTP/1.1 101');
105      assert.strictEqual(request_upgradeHead.toString('utf8'), 'WjN}|M(6');
106      conn.write('test', 'utf8');
107    } else if (state === 2) {
108      assert.strictEqual(data, 'test');
109      conn.write('kill', 'utf8');
110    }
111  });
112
113  conn.on('end', function() {
114    assert.strictEqual(state, 2);
115    conn.end();
116    server.removeAllListeners('upgrade');
117    test_upgrade_no_listener();
118  });
119}
120
121/*-----------------------------------------------
122  connection: Upgrade, no listener
123-----------------------------------------------*/
124function test_upgrade_no_listener() {
125  const conn = net.createConnection(server.address().port);
126  conn.setEncoding('utf8');
127
128  conn.on('connect', function() {
129    writeReq(conn,
130             'GET / HTTP/1.1\r\n' +
131             'Upgrade: WebSocket\r\n' +
132             'Connection: Upgrade\r\n' +
133             '\r\n');
134  });
135
136  conn.once('data', (data) => {
137    assert.strictEqual(typeof data, 'string');
138    assert.strictEqual(data.substr(0, 12), 'HTTP/1.1 200');
139    conn.end();
140  });
141
142  conn.on('close', function() {
143    test_standard_http();
144  });
145}
146
147/*-----------------------------------------------
148  connection: normal
149-----------------------------------------------*/
150function test_standard_http() {
151  const conn = net.createConnection(server.address().port);
152  conn.setEncoding('utf8');
153
154  conn.on('connect', function() {
155    writeReq(conn, 'GET / HTTP/1.1\r\n\r\n');
156  });
157
158  conn.once('data', function(data) {
159    assert.strictEqual(typeof data, 'string');
160    assert.strictEqual(data.substr(0, 12), 'HTTP/1.1 200');
161    conn.end();
162  });
163
164  conn.on('close', function() {
165    server.close();
166  });
167}
168
169
170const server = createTestServer();
171
172server.listen(0, function() {
173  // All tests get chained after this:
174  test_upgrade_with_listener();
175});
176
177
178/*-----------------------------------------------
179  Fin.
180-----------------------------------------------*/
181process.on('exit', function() {
182  assert.strictEqual(requests_recv, 3);
183  assert.strictEqual(requests_sent, 3);
184});
185