• 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// connection: Upgrade with listener
82function test_upgrade_with_listener() {
83  const conn = net.createConnection(server.address().port);
84  conn.setEncoding('utf8');
85  let state = 0;
86
87  conn.on('connect', function() {
88    writeReq(conn,
89             'GET / HTTP/1.1\r\n' +
90             'Upgrade: WebSocket\r\n' +
91             'Connection: Upgrade\r\n' +
92             '\r\n' +
93             'WjN}|M(6');
94  });
95
96  conn.on('data', function(data) {
97    state++;
98
99    assert.strictEqual(typeof data, 'string');
100
101    if (state === 1) {
102      assert.strictEqual(data.substr(0, 12), 'HTTP/1.1 101');
103      assert.strictEqual(request_upgradeHead.toString('utf8'), 'WjN}|M(6');
104      conn.write('test', 'utf8');
105    } else if (state === 2) {
106      assert.strictEqual(data, 'test');
107      conn.write('kill', 'utf8');
108    }
109  });
110
111  conn.on('end', function() {
112    assert.strictEqual(state, 2);
113    conn.end();
114    server.removeAllListeners('upgrade');
115    test_upgrade_no_listener();
116  });
117}
118
119// connection: Upgrade, no listener
120function test_upgrade_no_listener() {
121  const conn = net.createConnection(server.address().port);
122  conn.setEncoding('utf8');
123
124  conn.on('connect', function() {
125    writeReq(conn,
126             'GET / HTTP/1.1\r\n' +
127             'Upgrade: WebSocket\r\n' +
128             'Connection: Upgrade\r\n' +
129             '\r\n');
130  });
131
132  conn.once('data', (data) => {
133    assert.strictEqual(typeof data, 'string');
134    assert.strictEqual(data.substr(0, 12), 'HTTP/1.1 200');
135    conn.end();
136  });
137
138  conn.on('close', function() {
139    test_standard_http();
140  });
141}
142
143// connection: normal
144function test_standard_http() {
145  const conn = net.createConnection(server.address().port);
146  conn.setEncoding('utf8');
147
148  conn.on('connect', function() {
149    writeReq(conn, 'GET / HTTP/1.1\r\n\r\n');
150  });
151
152  conn.once('data', function(data) {
153    assert.strictEqual(typeof data, 'string');
154    assert.strictEqual(data.substr(0, 12), 'HTTP/1.1 200');
155    conn.end();
156  });
157
158  conn.on('close', function() {
159    server.close();
160  });
161}
162
163
164const server = createTestServer();
165
166server.listen(0, function() {
167  // All tests get chained after this:
168  test_upgrade_with_listener();
169});
170
171
172// Fin.
173process.on('exit', function() {
174  assert.strictEqual(requests_recv, 3);
175  assert.strictEqual(requests_sent, 3);
176});
177