mirror of
https://github.com/bitinflow/server.git
synced 2026-03-13 13:35:53 +00:00
refactor to use http agent interface for tunnels
This commit is contained in:
158
lib/Client.test.js
Normal file
158
lib/Client.test.js
Normal file
@@ -0,0 +1,158 @@
|
||||
import assert from 'assert';
|
||||
import http from 'http';
|
||||
import { Duplex } from 'stream';
|
||||
import EventEmitter from 'events';
|
||||
import WebSocket from 'ws';
|
||||
import net from 'net';
|
||||
|
||||
import Client from './Client';
|
||||
|
||||
class DummySocket extends Duplex {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
_write(chunk, encoding, callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
_read(size) {
|
||||
this.push('HTTP/1.1 304 Not Modified\r\nX-Powered-By: dummy\r\n\r\n\r\n');
|
||||
this.push(null);
|
||||
}
|
||||
}
|
||||
|
||||
class DummyWebsocket extends Duplex {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this.sentHeader = false;
|
||||
}
|
||||
|
||||
_write(chunk, encoding, callback) {
|
||||
const str = chunk.toString();
|
||||
// if chunk contains `GET / HTTP/1.1` -> queue headers
|
||||
// otherwise echo back received data
|
||||
if (str.indexOf('GET / HTTP/1.1') === 0) {
|
||||
const arr = [
|
||||
'HTTP/1.1 101 Switching Protocols',
|
||||
'Upgrade: websocket',
|
||||
'Connection: Upgrade',
|
||||
];
|
||||
this.push(arr.join('\r\n'));
|
||||
this.push('\r\n\r\n');
|
||||
}
|
||||
else {
|
||||
this.push(str);
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
_read(size) {
|
||||
// nothing to implement
|
||||
}
|
||||
}
|
||||
|
||||
class DummyAgent extends http.Agent {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
createConnection(options, cb) {
|
||||
cb(null, new DummySocket());
|
||||
}
|
||||
}
|
||||
|
||||
describe('Client', () => {
|
||||
it('should handle request', async () => {
|
||||
const agent = new DummyAgent();
|
||||
const client = new Client({ agent });
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
client.handleRequest(req, res);
|
||||
});
|
||||
|
||||
await new Promise(resolve => server.listen(resolve));
|
||||
|
||||
const address = server.address();
|
||||
const opt = {
|
||||
host: 'localhost',
|
||||
port: address.port,
|
||||
path: '/',
|
||||
};
|
||||
|
||||
const res = await new Promise((resolve) => {
|
||||
const req = http.get(opt, (res) => {
|
||||
resolve(res);
|
||||
});
|
||||
req.end();
|
||||
});
|
||||
assert.equal(res.headers['x-powered-by'], 'dummy');
|
||||
server.close();
|
||||
});
|
||||
|
||||
it('should handle upgrade', async () => {
|
||||
// need a websocket server and a socket for it
|
||||
class DummyWebsocketAgent extends http.Agent {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
createConnection(options, cb) {
|
||||
cb(null, new DummyWebsocket());
|
||||
}
|
||||
}
|
||||
|
||||
const agent = new DummyWebsocketAgent();
|
||||
const client = new Client({ agent });
|
||||
|
||||
const server = http.createServer();
|
||||
server.on('upgrade', (req, socket, head) => {
|
||||
client.handleUpgrade(req, socket);
|
||||
});
|
||||
|
||||
await new Promise(resolve => server.listen(resolve));
|
||||
|
||||
const address = server.address();
|
||||
|
||||
const netClient = await new Promise((resolve) => {
|
||||
const newClient = net.createConnection({ port: address.port }, () => {
|
||||
resolve(newClient);
|
||||
});
|
||||
});
|
||||
|
||||
const out = [
|
||||
'GET / HTTP/1.1',
|
||||
'Connection: Upgrade',
|
||||
'Upgrade: websocket'
|
||||
];
|
||||
|
||||
netClient.write(out.join('\r\n') + '\r\n\r\n');
|
||||
|
||||
{
|
||||
const data = await new Promise((resolve) => {
|
||||
netClient.once('data', (chunk) => {
|
||||
resolve(chunk.toString());
|
||||
});
|
||||
});
|
||||
const exp = [
|
||||
'HTTP/1.1 101 Switching Protocols',
|
||||
'Upgrade: websocket',
|
||||
'Connection: Upgrade',
|
||||
];
|
||||
assert.equal(exp.join('\r\n') + '\r\n\r\n', data);
|
||||
}
|
||||
|
||||
{
|
||||
netClient.write('foobar');
|
||||
const data = await new Promise((resolve) => {
|
||||
netClient.once('data', (chunk) => {
|
||||
resolve(chunk.toString());
|
||||
});
|
||||
});
|
||||
assert.equal('foobar', data);
|
||||
}
|
||||
|
||||
netClient.destroy();
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user