Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cd8f337278 | |||
| 76ffac630c | |||
| d2abdb1870 | |||
| f14a49b6eb | |||
| 73284c858c | |||
| ec5838e27e | |||
| 2627293613 | |||
| 4f1eced5e0 | |||
| ca0544fa6a | |||
| 091d98ef0c | |||
| 8d1f652056 | |||
| b779876f07 | |||
| 243e39b7b7 | |||
| 04eda7bc4f | |||
| 43ac090594 | |||
| 1120828003 | |||
| 59911312ac | |||
| 98298acb36 | |||
| 89a9b0d9b8 | |||
| 0e00ea5107 | |||
| d471a6a707 | |||
| 5dc1d7f682 | |||
| dfe361a18b | |||
| 140171307e | |||
| 6c5ef1c884 | |||
| 7ffe738208 | |||
| 2db4ef20ff | |||
| 54cd6f5831 | |||
| 35d9e6998e | |||
| e649b62396 | |||
| d0ec17d6a3 | |||
| 1d3878e3ed | |||
| 97dfaf71cf | |||
| 723f4ce6a7 | |||
| 97b7342538 | |||
| 9d8e5384b7 | |||
| 42ea7fb0a5 | |||
| 03acb154e2 | |||
| b40fc25444 | |||
| 05cc735582 | |||
| 29d07c5002 | |||
| 2118283941 | |||
| 4db640660d | |||
| 4353dd8c36 | |||
| 308f930160 | |||
| 5d7e9ef9a3 | |||
| 07217fe317 | |||
| 29ef6b04a5 | |||
| 1030d38093 | |||
| fa7dcf365c | |||
| 018ef183bf | |||
| b545e8b80f | |||
| 07f5ef6f95 |
@@ -1,8 +1,6 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "0.6"
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
- "0.11"
|
||||
|
||||
|
||||
+36
-1
@@ -1,3 +1,39 @@
|
||||
### 0.9.2 / 2014-12-21
|
||||
|
||||
* Only emit `error` once, and don't emit it after `close`
|
||||
|
||||
|
||||
### 0.9.1 / 2014-12-18
|
||||
|
||||
* Check that all options to the WebSocket constructor are recognized
|
||||
|
||||
|
||||
### 0.9.0 / 2014-12-13
|
||||
|
||||
* Allow protocol extensions to be passed into websocket-extensions
|
||||
|
||||
|
||||
### 0.8.1 / 2014-11-12
|
||||
|
||||
* Send the correct hostname when upgrading a connection to TLS
|
||||
|
||||
|
||||
### 0.8.0 / 2014-11-08
|
||||
|
||||
* Support connections via HTTP proxies
|
||||
* Close the connection cleanly if we're still waiting for a handshake response
|
||||
|
||||
|
||||
### 0.7.3 / 2014-10-04
|
||||
|
||||
* Allow sockets to be closed when they are in any state other than `CLOSED`
|
||||
|
||||
|
||||
### 0.7.2 / 2013-12-29
|
||||
|
||||
* Make sure the `close` event is emitted by clients on Node v0.10
|
||||
|
||||
|
||||
### 0.7.1 / 2013-12-03
|
||||
|
||||
* Support the `maxLength` websocket-driver option
|
||||
@@ -87,4 +123,3 @@
|
||||
### 0.1.0 / 2011-11-27
|
||||
|
||||
* Initial release, based on WebSocket components from Faye
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# faye-websocket
|
||||
|
||||
* Travis CI build: [](http://travis-ci.org/faye/faye-websocket-node)
|
||||
status](https://secure.travis-ci.org/faye/faye-websocket-node.svg)](http://travis-ci.org/faye/faye-websocket-node)
|
||||
* Autobahn tests: [server](http://faye.jcoglan.com/autobahn/servers/),
|
||||
[client](http://faye.jcoglan.com/autobahn/clients/)
|
||||
|
||||
@@ -117,6 +117,23 @@ ws.on('close', function(event) {
|
||||
The WebSocket client also lets you inspect the status and headers of the
|
||||
handshake response via its `statusCode` and `headers` properties.
|
||||
|
||||
To connect via a proxy, set the `proxy` option to the HTTP origin of the proxy,
|
||||
including any authorization information, custom headers and TLS config you
|
||||
require. Only the `origin` setting is required.
|
||||
|
||||
```js
|
||||
var ws = new WebSocket.Client('ws://www.example.com/', null, {
|
||||
proxy: {
|
||||
origin: 'http://username:password@proxy.example.com',
|
||||
headers: {'User-Agent': 'node'},
|
||||
tls: {cert: fs.readFileSync('client.crt')}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
The `tls` value is a Node 'TLS options' object that will be passed to
|
||||
[`tls.connect()`](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback).
|
||||
|
||||
|
||||
## Subprotocol negotiation
|
||||
|
||||
@@ -140,6 +157,22 @@ If the client and server agree on a protocol, both the client- and server-side
|
||||
socket objects expose the selected protocol through the `ws.protocol` property.
|
||||
|
||||
|
||||
## Protocol extensions
|
||||
|
||||
faye-websocket is based on the
|
||||
[websocket-extensions](https://github.com/faye/websocket-extensions-node)
|
||||
framework that allows extensions to be negotiated via the
|
||||
`Sec-WebSocket-Extensions` header. To add extensions to a connection, pass an
|
||||
array of extensions to the `:extensions` option. For example, to add
|
||||
[permessage-deflate](https://github.com/faye/permessage-deflate-node):
|
||||
|
||||
```js
|
||||
var deflate = require('permessage-deflate');
|
||||
|
||||
var ws = new WebSocket(request, null, {extensions: [deflate]});
|
||||
```
|
||||
|
||||
|
||||
## Initialization options
|
||||
|
||||
Both the server- and client-side classes allow an options object to be passed
|
||||
@@ -153,13 +186,24 @@ var ws = new WebSocket.Client(url, protocols, options);
|
||||
`protocols` is an array of subprotocols as described above, or `null`.
|
||||
`options` is an optional object containing any of these fields:
|
||||
|
||||
* `extensions` - an array of
|
||||
[websocket-extensions](https://github.com/faye/websocket-extensions-node)
|
||||
compatible extensions, as described above
|
||||
* `headers` - an object containing key-value pairs representing HTTP headers to
|
||||
be sent during the handshake process
|
||||
* `maxLength` - the maximum allowed size of incoming message frames, in bytes.
|
||||
The default value is `2^30 - 1`, or 1 byte short of 1 GiB.
|
||||
The default value is `2^26 - 1`, or 1 byte short of 64 MiB.
|
||||
* `ping` - an integer that sets how often the WebSocket should send ping
|
||||
frames, measured in seconds
|
||||
|
||||
The client accepts some additional options:
|
||||
|
||||
* `proxy` - settings for a proxy as described above
|
||||
* `tls` - a Node 'TLS options' object containing TLS settings for the origin
|
||||
server, this will be passed to
|
||||
[`tls.connect()`](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback)
|
||||
* `ca` - (legacy) a shorthand for passing `{tls: {ca: value}}`
|
||||
|
||||
|
||||
## WebSocket API
|
||||
|
||||
@@ -273,7 +317,7 @@ some data over the wire to keep the connection alive.
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2010-2013 James Coglan
|
||||
Copyright (c) 2010-2014 James Coglan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the 'Software'), to deal in
|
||||
@@ -292,4 +336,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
+24
-23
@@ -1,13 +1,14 @@
|
||||
var WebSocket = require('../lib/faye/websocket'),
|
||||
deflate = require('permessage-deflate'),
|
||||
pace = require('pace');
|
||||
|
||||
var host = 'ws://localhost:9001',
|
||||
agent = 'Node ' + process.version,
|
||||
cases = 0,
|
||||
skip = [];
|
||||
var host = 'ws://localhost:9001',
|
||||
agent = encodeURIComponent('node-' + process.version),
|
||||
cases = 0,
|
||||
options = {extensions: [deflate]};
|
||||
|
||||
var socket = new WebSocket.Client(host + '/getCaseCount'),
|
||||
progress;
|
||||
url, progress;
|
||||
|
||||
socket.onmessage = function(event) {
|
||||
console.log('Total cases to run: ' + event.data);
|
||||
@@ -15,24 +16,24 @@ socket.onmessage = function(event) {
|
||||
progress = pace(cases);
|
||||
};
|
||||
|
||||
socket.onclose = function() {
|
||||
var runCase = function(n) {
|
||||
var runCase = function(n) {
|
||||
if (n > cases) {
|
||||
url = host + '/updateReports?agent=' + agent;
|
||||
socket = new WebSocket.Client(url);
|
||||
socket.onclose = process.exit;
|
||||
return;
|
||||
}
|
||||
|
||||
url = host + '/runCase?case=' + n + '&agent=' + agent;
|
||||
socket = new WebSocket.Client(url, null, options);
|
||||
socket.pipe(socket);
|
||||
|
||||
socket.on('close', function() {
|
||||
progress.op();
|
||||
|
||||
if (n > cases) {
|
||||
socket = new WebSocket.Client(host + '/updateReports?agent=' + encodeURIComponent(agent));
|
||||
socket.onclose = process.exit;
|
||||
|
||||
} else if (skip.indexOf(n) >= 0) {
|
||||
runCase(n + 1);
|
||||
|
||||
} else {
|
||||
socket = new WebSocket.Client(host + '/runCase?case=' + n + '&agent=' + encodeURIComponent(agent));
|
||||
socket.pipe(socket);
|
||||
socket.on('close', function() { runCase(n + 1) });
|
||||
}
|
||||
};
|
||||
|
||||
runCase(1);
|
||||
runCase(n + 1);
|
||||
});
|
||||
};
|
||||
|
||||
socket.onclose = function() {
|
||||
runCase(1);
|
||||
};
|
||||
|
||||
+16
-15
@@ -1,24 +1,25 @@
|
||||
var WebSocket = require('../lib/faye/websocket'),
|
||||
port = process.argv[2] || 7000,
|
||||
secure = process.argv[3] === 'ssl',
|
||||
scheme = secure ? 'wss' : 'ws',
|
||||
url = scheme + '://localhost:' + port + '/',
|
||||
headers = {Origin: 'http://faye.jcoglan.com'},
|
||||
ws = new WebSocket.Client(url, null, {headers: headers});
|
||||
fs = require('fs');
|
||||
|
||||
console.log('Connecting to ' + ws.url);
|
||||
var url = process.argv[2],
|
||||
headers = {Origin: 'http://faye.jcoglan.com'},
|
||||
ca = fs.readFileSync(__dirname + '/../spec/server.crt'),
|
||||
proxy = {origin: process.argv[3], headers: {'User-Agent': 'Echo'}, tls: {ca: ca}},
|
||||
ws = new WebSocket.Client(url, null, {headers: headers, proxy: proxy, tls: {ca: ca}});
|
||||
|
||||
ws.onopen = function(event) {
|
||||
console.log('open');
|
||||
ws.send('Hello, WebSocket!');
|
||||
ws.onopen = function() {
|
||||
console.log('[open]', ws.headers);
|
||||
ws.send('mic check');
|
||||
};
|
||||
|
||||
ws.onmessage = function(event) {
|
||||
console.log('message', event.data);
|
||||
// ws.close(1002, 'Going away');
|
||||
ws.onclose = function(close) {
|
||||
console.log('[close]', close.code, close.reason);
|
||||
};
|
||||
|
||||
ws.onclose = function(event) {
|
||||
console.log('close', event.code, event.reason);
|
||||
ws.onerror = function(error) {
|
||||
console.log('[error]', error.message);
|
||||
};
|
||||
|
||||
ws.onmessage = function(message) {
|
||||
console.log('[message]', message.data);
|
||||
};
|
||||
|
||||
@@ -18,4 +18,3 @@ backend sockets
|
||||
balance uri depth 2
|
||||
timeout server 120s
|
||||
server socket1 127.0.0.1:7000
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
var ProxyServer = require('../spec/proxy_server');
|
||||
|
||||
var port = process.argv[2],
|
||||
secure = process.argv[3] === 'tls',
|
||||
proxy = new ProxyServer({debug: true, tls: secure});
|
||||
|
||||
proxy.listen(port);
|
||||
+9
-8
@@ -1,19 +1,21 @@
|
||||
var WebSocket = require('../lib/faye/websocket'),
|
||||
deflate = require('permessage-deflate'),
|
||||
fs = require('fs'),
|
||||
http = require('http'),
|
||||
https = require('https');
|
||||
|
||||
var port = process.argv[2] || 7000,
|
||||
secure = process.argv[3] === 'ssl';
|
||||
var port = process.argv[2] || 7000,
|
||||
secure = process.argv[3] === 'tls',
|
||||
options = {extensions: [deflate], ping: 5};
|
||||
|
||||
var upgradeHandler = function(request, socket, head) {
|
||||
var ws = new WebSocket(request, socket, head, ['irc', 'xmpp'], {ping: 5});
|
||||
console.log('open', ws.url, ws.version, ws.protocol);
|
||||
var ws = new WebSocket(request, socket, head, ['irc', 'xmpp'], options);
|
||||
console.log('[open]', ws.url, ws.version, ws.protocol, request.headers);
|
||||
|
||||
ws.pipe(ws);
|
||||
|
||||
ws.onclose = function(event) {
|
||||
console.log('close', event.code, event.reason);
|
||||
console.log('[close]', event.code, event.reason);
|
||||
ws = null;
|
||||
};
|
||||
};
|
||||
@@ -25,7 +27,7 @@ var requestHandler = function(request, response) {
|
||||
var es = new WebSocket.EventSource(request, response),
|
||||
time = parseInt(es.lastEventId, 10) || 0;
|
||||
|
||||
console.log('open', es.url, es.lastEventId);
|
||||
console.log('[open]', es.url, es.lastEventId);
|
||||
|
||||
var loop = setInterval(function() {
|
||||
time += 1;
|
||||
@@ -39,7 +41,7 @@ var requestHandler = function(request, response) {
|
||||
|
||||
es.onclose = function() {
|
||||
clearInterval(loop);
|
||||
console.log('close', es.url);
|
||||
console.log('[close]', es.url);
|
||||
es = null;
|
||||
};
|
||||
};
|
||||
@@ -65,4 +67,3 @@ var server = secure
|
||||
server.on('request', requestHandler);
|
||||
server.on('upgrade', upgradeHandler);
|
||||
server.listen(port);
|
||||
|
||||
|
||||
@@ -36,4 +36,3 @@
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -41,4 +41,3 @@
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -129,4 +129,3 @@ for (var method in instance) EventSource.prototype[method] = instance[method];
|
||||
for (var key in EventTarget) EventSource.prototype[key] = EventTarget[key];
|
||||
|
||||
module.exports = EventSource;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// API references:
|
||||
//
|
||||
//
|
||||
// * http://dev.w3.org/html5/websockets/
|
||||
// * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#interface-eventtarget
|
||||
// * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#interface-event
|
||||
@@ -16,20 +16,14 @@ var WebSocket = function(request, socket, body, protocols, options) {
|
||||
|
||||
var self = this;
|
||||
if (!this._stream || !this._stream.writable) return;
|
||||
if (!this._stream.readable) return this._stream.end();
|
||||
|
||||
var catchup = function() { self._stream.removeListener('data', catchup) };
|
||||
this._stream.on('data', catchup);
|
||||
|
||||
this._stream.setTimeout(0);
|
||||
this._stream.setNoDelay(true);
|
||||
|
||||
this._driver.io.write(body);
|
||||
API.call(this, options);
|
||||
|
||||
['error', 'end'].forEach(function(event) {
|
||||
this._stream.on(event, function() { self._finalize('', 1006) });
|
||||
}, this);
|
||||
|
||||
process.nextTick(function() {
|
||||
self._driver.start();
|
||||
});
|
||||
@@ -40,9 +34,12 @@ WebSocket.isWebSocket = function(request) {
|
||||
return driver.isWebSocket(request);
|
||||
};
|
||||
|
||||
WebSocket.validateOptions = function(options, validKeys) {
|
||||
driver.validateOptions(options, validKeys);
|
||||
};
|
||||
|
||||
WebSocket.WebSocket = WebSocket;
|
||||
WebSocket.Client = require('./websocket/client');
|
||||
WebSocket.EventSource = require('./eventsource');
|
||||
|
||||
module.exports = WebSocket;
|
||||
|
||||
|
||||
+57
-13
@@ -1,10 +1,12 @@
|
||||
var Stream = require('stream').Stream,
|
||||
util = require('util'),
|
||||
driver = require('websocket-driver'),
|
||||
EventTarget = require('./api/event_target'),
|
||||
Event = require('./api/event');
|
||||
|
||||
var API = function(options) {
|
||||
options = options || {};
|
||||
driver.validateOptions(options, ['headers', 'extensions', 'maxLength', 'ping', 'proxy', 'tls', 'ca']);
|
||||
|
||||
this.readable = this.writable = true;
|
||||
|
||||
@@ -13,6 +15,11 @@ var API = function(options) {
|
||||
for (var name in headers) this._driver.setHeader(name, headers[name]);
|
||||
}
|
||||
|
||||
var extensions = options.extensions;
|
||||
if (extensions) {
|
||||
[].concat(extensions).forEach(this._driver.addExtension, this._driver);
|
||||
}
|
||||
|
||||
this._ping = options.ping;
|
||||
this._pingId = 0;
|
||||
this.readyState = API.CONNECTING;
|
||||
@@ -25,12 +32,10 @@ var API = function(options) {
|
||||
|
||||
this._driver.on('open', function(e) { self._open() });
|
||||
this._driver.on('message', function(e) { self._receiveMessage(e.data) });
|
||||
this._driver.on('close', function(e) { self._finalize(e.reason, e.code) });
|
||||
this._driver.on('close', function(e) { self._beginClose(e.reason, e.code) });
|
||||
|
||||
this._driver.on('error', function(error) {
|
||||
var event = new Event('error', {message: error.message});
|
||||
event.initEvent('error', false, false);
|
||||
self.dispatchEvent(event);
|
||||
self._emitError(error.message);
|
||||
});
|
||||
this.on('error', function() {});
|
||||
|
||||
@@ -44,8 +49,12 @@ var API = function(options) {
|
||||
self.ping(self._pingId.toString());
|
||||
}, this._ping * 1000);
|
||||
|
||||
this._stream.pipe(this._driver.io);
|
||||
this._driver.io.pipe(this._stream);
|
||||
this._configureStream();
|
||||
|
||||
if (!this._proxy) {
|
||||
this._stream.pipe(this._driver.io);
|
||||
this._driver.io.pipe(this._stream);
|
||||
}
|
||||
};
|
||||
util.inherits(API, Stream);
|
||||
|
||||
@@ -84,10 +93,26 @@ var instance = {
|
||||
},
|
||||
|
||||
close: function() {
|
||||
if (this.readyState === API.OPEN) this.readyState = API.CLOSING;
|
||||
if (this.readyState !== API.CLOSED) this.readyState = API.CLOSING;
|
||||
this._driver.close();
|
||||
},
|
||||
|
||||
_configureStream: function() {
|
||||
var self = this;
|
||||
|
||||
this._stream.setTimeout(0);
|
||||
this._stream.setNoDelay(true);
|
||||
|
||||
['close', 'end'].forEach(function(event) {
|
||||
this._stream.on(event, function() { self._finalizeClose() });
|
||||
}, this);
|
||||
|
||||
this._stream.on('error', function(error) {
|
||||
self._emitError('Network error: ' + self.url + ': ' + error.message);
|
||||
self._finalizeClose();
|
||||
});
|
||||
},
|
||||
|
||||
_open: function() {
|
||||
if (this.readyState !== API.CONNECTING) return;
|
||||
|
||||
@@ -109,17 +134,37 @@ var instance = {
|
||||
this.dispatchEvent(event);
|
||||
},
|
||||
|
||||
_finalize: function(reason, code) {
|
||||
_emitError: function(message) {
|
||||
if (this.readyState >= API.CLOSING) return;
|
||||
|
||||
var event = new Event('error', {message: message});
|
||||
event.initEvent('error', false, false);
|
||||
this.dispatchEvent(event);
|
||||
},
|
||||
|
||||
_beginClose: function(reason, code) {
|
||||
if (this.readyState === API.CLOSED) return;
|
||||
this.readyState = API.CLOSING;
|
||||
|
||||
if (this._stream) {
|
||||
this._stream.end();
|
||||
if (!this._stream.readable) this._finalizeClose();
|
||||
}
|
||||
this._closeParams = [reason, code];
|
||||
},
|
||||
|
||||
_finalizeClose: function() {
|
||||
if (this.readyState === API.CLOSED) return;
|
||||
this.readyState = API.CLOSED;
|
||||
|
||||
if (this._pingTimer) clearInterval(this._pingTimer);
|
||||
if (this._stream) this._stream.end();
|
||||
|
||||
if (this.readable) this.emit('end');
|
||||
this.readable = this.writable = false;
|
||||
|
||||
this.readyState = API.CLOSED;
|
||||
var event = new Event('close', {code: code || 1000, reason: reason || ''});
|
||||
var reason = this._closeParams ? this._closeParams[0] : '',
|
||||
code = this._closeParams ? this._closeParams[1] : 1006;
|
||||
|
||||
var event = new Event('close', {code: code, reason: reason});
|
||||
event.initEvent('close', false, false);
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
@@ -129,4 +174,3 @@ for (var method in instance) API.prototype[method] = instance[method];
|
||||
for (var key in EventTarget) API.prototype[key] = EventTarget[key];
|
||||
|
||||
module.exports = API;
|
||||
|
||||
|
||||
@@ -18,4 +18,3 @@ Event.AT_TARGET = 2;
|
||||
Event.BUBBLING_PHASE = 3;
|
||||
|
||||
module.exports = Event;
|
||||
|
||||
|
||||
@@ -26,4 +26,3 @@ var EventTarget = {
|
||||
};
|
||||
|
||||
module.exports = EventTarget;
|
||||
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
var util = require('util'),
|
||||
net = require('net'),
|
||||
tls = require('tls'),
|
||||
crypto = require('crypto'),
|
||||
url = require('url'),
|
||||
driver = require('websocket-driver'),
|
||||
API = require('./api'),
|
||||
Event = require('./api/event');
|
||||
|
||||
var Client = function(url, protocols, options) {
|
||||
var DEFAULT_PORTS = {'http:': 80, 'https:': 443, 'ws:':80, 'wss:': 443},
|
||||
SECURE_PROTOCOLS = ['https:', 'wss:'];
|
||||
|
||||
var Client = function(_url, protocols, options) {
|
||||
options = options || {};
|
||||
|
||||
this.url = url;
|
||||
this._uri = require('url').parse(url);
|
||||
this._driver = driver.client(url, {maxLength: options.maxLength, protocols: protocols});
|
||||
this.url = _url;
|
||||
this._driver = driver.client(this.url, {maxLength: options.maxLength, protocols: protocols});
|
||||
|
||||
['open', 'error'].forEach(function(event) {
|
||||
this._driver.on(event, function() {
|
||||
@@ -19,35 +23,62 @@ var Client = function(url, protocols, options) {
|
||||
});
|
||||
}, this);
|
||||
|
||||
var secure = (this._uri.protocol === 'wss:'),
|
||||
onConnect = function() { self._driver.start() },
|
||||
tlsOptions = {},
|
||||
self = this;
|
||||
var proxy = options.proxy || {},
|
||||
endpoint = url.parse(proxy.origin || this.url),
|
||||
port = endpoint.port || DEFAULT_PORTS[endpoint.protocol],
|
||||
secure = SECURE_PROTOCOLS.indexOf(endpoint.protocol) >= 0,
|
||||
onConnect = function() { self._onConnect() },
|
||||
originTLS = options.tls || {},
|
||||
socketTLS = proxy.origin ? (proxy.tls || {}) : originTLS,
|
||||
self = this;
|
||||
|
||||
if (options.ca) tlsOptions.ca = options.ca;
|
||||
originTLS.ca = originTLS.ca || options.ca;
|
||||
|
||||
var connection = secure
|
||||
? tls.connect(this._uri.port || 443, this._uri.hostname, tlsOptions, onConnect)
|
||||
: net.createConnection(this._uri.port || 80, this._uri.hostname);
|
||||
this._stream = secure
|
||||
? tls.connect(port, endpoint.hostname, socketTLS, onConnect)
|
||||
: net.connect(port, endpoint.hostname, onConnect);
|
||||
|
||||
this._stream = connection;
|
||||
this._stream.setTimeout(0);
|
||||
this._stream.setNoDelay(true);
|
||||
|
||||
if (!secure) this._stream.on('connect', onConnect);
|
||||
if (proxy.origin) this._configureProxy(proxy, originTLS);
|
||||
|
||||
API.call(this, options);
|
||||
|
||||
this._stream.on('end', function() { self._finalize('', 1006) });
|
||||
|
||||
this._stream.on('error', function(error) {
|
||||
var event = new Event('error', {message: 'Network error: ' + url + ': ' + error.message});
|
||||
event.initEvent('error', false, false);
|
||||
self.dispatchEvent(event);
|
||||
self._finalize('', 1006);
|
||||
});
|
||||
};
|
||||
util.inherits(Client, API);
|
||||
|
||||
module.exports = Client;
|
||||
Client.prototype._onConnect = function() {
|
||||
var worker = this._proxy || this._driver;
|
||||
worker.start();
|
||||
};
|
||||
|
||||
Client.prototype._configureProxy = function(proxy, originTLS) {
|
||||
var uri = url.parse(this.url),
|
||||
secure = SECURE_PROTOCOLS.indexOf(uri.protocol) >= 0,
|
||||
self = this,
|
||||
name;
|
||||
|
||||
this._proxy = this._driver.proxy(proxy.origin);
|
||||
|
||||
if (proxy.headers) {
|
||||
for (name in proxy.headers) this._proxy.setHeader(name, proxy.headers[name]);
|
||||
}
|
||||
|
||||
this._proxy.pipe(this._stream, {end: false});
|
||||
this._stream.pipe(this._proxy);
|
||||
|
||||
this._proxy.on('connect', function() {
|
||||
if (secure) {
|
||||
var options = {socket: self._stream, servername: uri.hostname};
|
||||
for (name in originTLS) options[name] = originTLS[name];
|
||||
self._stream = tls.connect(options);
|
||||
self._configureStream();
|
||||
}
|
||||
self._driver.io.pipe(self._stream);
|
||||
self._stream.pipe(self._driver.io);
|
||||
self._driver.start();
|
||||
});
|
||||
|
||||
this._proxy.on('error', function(error) {
|
||||
self._driver.emit('error', error);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Client;
|
||||
|
||||
+3
-4
@@ -5,11 +5,11 @@
|
||||
, "keywords" : ["websocket", "eventsource"]
|
||||
, "license" : "MIT"
|
||||
|
||||
, "version" : "0.7.1"
|
||||
, "version" : "0.9.2"
|
||||
, "engines" : {"node": ">=0.4.0"}
|
||||
, "main" : "./lib/faye/websocket"
|
||||
, "dependencies" : {"websocket-driver": ">=0.3.1"}
|
||||
, "devDependencies" : {"jstest": "", "pace": ""}
|
||||
, "dependencies" : {"websocket-driver": ">=0.5.1"}
|
||||
, "devDependencies" : {"jstest": "", "pace": "", "permessage-deflate": ""}
|
||||
|
||||
, "scripts" : {"test": "jstest spec/runner.js"}
|
||||
|
||||
@@ -19,4 +19,3 @@
|
||||
|
||||
, "bugs" : "http://github.com/faye/faye-websocket-node/issues"
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
var fs = require('fs'),
|
||||
http = require('http'),
|
||||
https = require('https');
|
||||
|
||||
var WebSocket = require('../lib/faye/websocket');
|
||||
|
||||
var EchoServer = function(secure) {
|
||||
var server = secure
|
||||
? https.createServer({
|
||||
key: fs.readFileSync(__dirname + '/server.key'),
|
||||
cert: fs.readFileSync(__dirname + '/server.crt')
|
||||
})
|
||||
: http.createServer();
|
||||
|
||||
server.on('upgrade', function(request, socket, head) {
|
||||
var ws = new WebSocket(request, socket, head, ["echo"]);
|
||||
ws.pipe(ws);
|
||||
});
|
||||
|
||||
this._httpServer = server;
|
||||
};
|
||||
|
||||
EchoServer.prototype.listen = function(port) {
|
||||
this._httpServer.listen(port);
|
||||
};
|
||||
|
||||
EchoServer.prototype.stop = function() {
|
||||
this._httpServer.close();
|
||||
};
|
||||
|
||||
module.exports = EchoServer;
|
||||
@@ -1,17 +1,29 @@
|
||||
var Client = require('../../../lib/faye/websocket/client'),
|
||||
test = require('jstest').Test,
|
||||
fs = require('fs')
|
||||
var Client = require('../../../lib/faye/websocket/client'),
|
||||
EchoServer = require('../../echo_server'),
|
||||
ProxyServer = require('../../proxy_server'),
|
||||
test = require('jstest').Test,
|
||||
fs = require('fs')
|
||||
|
||||
var WebSocketSteps = test.asyncSteps({
|
||||
server: function(port, secure, callback) {
|
||||
this._adapter = new EchoServer()
|
||||
this._adapter.listen(port, secure)
|
||||
this._port = port
|
||||
this._echoServer = new EchoServer(secure)
|
||||
this._echoServer.listen(port)
|
||||
process.nextTick(callback)
|
||||
},
|
||||
|
||||
stop: function(callback) {
|
||||
this._adapter.stop()
|
||||
this._echoServer.stop()
|
||||
process.nextTick(callback)
|
||||
},
|
||||
|
||||
proxy: function(port, secure, callback) {
|
||||
this._proxyServer = new ProxyServer({tls: secure})
|
||||
this._proxyServer.listen(port)
|
||||
process.nextTick(callback)
|
||||
},
|
||||
|
||||
stop_proxy: function(callback) {
|
||||
this._proxyServer.stop()
|
||||
process.nextTick(callback)
|
||||
},
|
||||
|
||||
@@ -19,6 +31,8 @@ var WebSocketSteps = test.asyncSteps({
|
||||
var done = false,
|
||||
self = this,
|
||||
|
||||
tlsOptions = { ca: fs.readFileSync(__dirname + '/../../server.crt') },
|
||||
|
||||
resume = function(open) {
|
||||
if (done) return
|
||||
done = true
|
||||
@@ -27,13 +41,29 @@ var WebSocketSteps = test.asyncSteps({
|
||||
}
|
||||
|
||||
this._ws = new Client(url, protocols, {
|
||||
ca: fs.readFileSync(__dirname + '/../../server.crt')
|
||||
proxy: { origin: this.proxy_url, tls: tlsOptions },
|
||||
tls: tlsOptions
|
||||
})
|
||||
|
||||
this._ws.onopen = function() { resume(true) }
|
||||
this._ws.onclose = function() { resume(false) }
|
||||
},
|
||||
|
||||
open_socket_and_close_it_fast: function(url, protocols, callback) {
|
||||
var self = this
|
||||
|
||||
this._ws = new Client(url, protocols, {
|
||||
ca: fs.readFileSync(__dirname + '/../../server.crt')
|
||||
})
|
||||
|
||||
this._ws.onopen = function() { self._open = self._ever_opened = true }
|
||||
this._ws.onclose = function() { self._open = false }
|
||||
|
||||
this._ws.close()
|
||||
|
||||
callback()
|
||||
},
|
||||
|
||||
close_socket: function(callback) {
|
||||
var self = this
|
||||
this._ws.onclose = function() {
|
||||
@@ -53,6 +83,21 @@ var WebSocketSteps = test.asyncSteps({
|
||||
callback()
|
||||
},
|
||||
|
||||
check_never_opened: function(callback) {
|
||||
this.assert( !this._ever_opened )
|
||||
callback()
|
||||
},
|
||||
|
||||
check_readable: function(callback) {
|
||||
this.assert( this._ws.readable )
|
||||
callback()
|
||||
},
|
||||
|
||||
check_not_readable: function(callback) {
|
||||
this.assert( ! this._ws.readable )
|
||||
callback()
|
||||
},
|
||||
|
||||
check_protocol: function(protocol, callback) {
|
||||
this.assertEqual( protocol, this._ws.protocol )
|
||||
callback()
|
||||
@@ -83,6 +128,10 @@ var WebSocketSteps = test.asyncSteps({
|
||||
check_no_response: function(callback) {
|
||||
this.assert( !this._message )
|
||||
callback()
|
||||
},
|
||||
|
||||
wait: function (ms, callback) {
|
||||
setTimeout(callback, ms)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -91,10 +140,15 @@ test.describe("Client", function() { with(this) {
|
||||
include(WebSocketSteps)
|
||||
|
||||
before(function() {
|
||||
this.protocols = ["foo", "echo"]
|
||||
this.plain_text_url = "ws://localhost:4180/bayeux"
|
||||
this.secure_url = "wss://localhost:4180/bayeux"
|
||||
this.port = 4180
|
||||
this.protocols = ["foo", "echo"]
|
||||
|
||||
this.plain_text_url = "ws://localhost:4180/bayeux"
|
||||
this.secure_url = "wss://localhost:4180/bayeux"
|
||||
this.port = 4180
|
||||
|
||||
this.plain_text_proxy_url = "http://localhost:4181"
|
||||
this.secure_text_proxy_url = "https://localhost:4181"
|
||||
this.proxy_port = 4181
|
||||
})
|
||||
|
||||
sharedBehavior("socket client", function() { with(this) {
|
||||
@@ -106,8 +160,10 @@ test.describe("Client", function() { with(this) {
|
||||
|
||||
it("can close the connection", function() { with(this) {
|
||||
open_socket(socket_url, protocols)
|
||||
check_readable()
|
||||
close_socket()
|
||||
check_closed()
|
||||
check_not_readable()
|
||||
}})
|
||||
|
||||
describe("in the OPEN state", function() { with(this) {
|
||||
@@ -152,30 +208,65 @@ test.describe("Client", function() { with(this) {
|
||||
check_no_response()
|
||||
}})
|
||||
}})
|
||||
|
||||
it("can be closed before connecting", function() { with(this) {
|
||||
open_socket_and_close_it_fast(socket_url, protocols)
|
||||
wait(10)
|
||||
check_closed()
|
||||
check_never_opened()
|
||||
check_not_readable()
|
||||
}})
|
||||
}})
|
||||
|
||||
describe("with a plain-text server", function() { with(this) {
|
||||
before(function() {
|
||||
this.socket_url = this.plain_text_url
|
||||
this.blocked_url = this.secure_url
|
||||
})
|
||||
sharedBehavior("socket server", function() { with(this) {
|
||||
describe("with a plain-text server", function() { with(this) {
|
||||
before(function() {
|
||||
this.socket_url = this.plain_text_url
|
||||
this.blocked_url = this.secure_url
|
||||
})
|
||||
|
||||
before(function() { this.server(4180, false) })
|
||||
after (function() { this.stop() })
|
||||
before(function() { this.server(this.port, false) })
|
||||
after (function() { this.stop() })
|
||||
|
||||
behavesLike("socket client")
|
||||
behavesLike("socket client")
|
||||
}})
|
||||
|
||||
describe("with a secure server", function() { with(this) {
|
||||
before(function() {
|
||||
this.socket_url = this.secure_url
|
||||
this.blocked_url = this.plain_text_url
|
||||
})
|
||||
|
||||
before(function() { this.server(this.port, true) })
|
||||
after (function() { this.stop() })
|
||||
|
||||
behavesLike("socket client")
|
||||
}})
|
||||
}})
|
||||
|
||||
describe("with a secure server", function() { with(this) {
|
||||
describe("with no proxy", function() { with(this) {
|
||||
behavesLike("socket server")
|
||||
}})
|
||||
|
||||
describe("with a proxy", function() { with(this) {
|
||||
before(function() {
|
||||
this.socket_url = this.secure_url
|
||||
this.blocked_url = this.plain_text_url
|
||||
this.proxy_url = this.plain_text_proxy_url
|
||||
})
|
||||
|
||||
before(function() { this.server(4180, true) })
|
||||
after (function() { this.stop() })
|
||||
before(function() { this.proxy(this.proxy_port, false) })
|
||||
after (function() { this.stop_proxy() })
|
||||
|
||||
behavesLike("socket client")
|
||||
behavesLike("socket server")
|
||||
}})
|
||||
|
||||
describe("with a secure proxy", function() { with(this) {
|
||||
before(function() {
|
||||
this.proxy_url = this.secure_text_proxy_url
|
||||
})
|
||||
|
||||
before(function() { this.proxy(this.proxy_port, true) })
|
||||
after (function() { this.stop_proxy() })
|
||||
|
||||
behavesLike("socket server")
|
||||
}})
|
||||
}})
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
var fs = require('fs'),
|
||||
http = require('http'),
|
||||
https = require('https'),
|
||||
net = require('net'),
|
||||
url = require('url');
|
||||
|
||||
var AGENTS = {'http:': http, 'https:': https},
|
||||
PORTS = {'http:': 80, 'https:': 443};
|
||||
|
||||
var ProxyServer = function(options) {
|
||||
var proxy = options.tls
|
||||
? https.createServer({
|
||||
key: fs.readFileSync(__dirname + '/server.key'),
|
||||
cert: fs.readFileSync(__dirname + '/server.crt')
|
||||
})
|
||||
: http.createServer();
|
||||
|
||||
options = options || {};
|
||||
|
||||
var onRequest = function(request, response) {
|
||||
if (options.debug) console.log(request.method, request.url, request.headers);
|
||||
|
||||
var uri = url.parse(request.url),
|
||||
agent = AGENTS[uri.protocol],
|
||||
headers = {};
|
||||
|
||||
for (var key in request.headers) {
|
||||
if (key.split('-')[0] !== 'proxy') headers[key] = request.headers[key];
|
||||
}
|
||||
|
||||
var backend = agent.request({
|
||||
method: request.method,
|
||||
host: uri.hostname,
|
||||
port: uri.port || PORTS[uri.protocol],
|
||||
path: uri.path,
|
||||
headers: headers,
|
||||
rejectUnauthorized: false
|
||||
});
|
||||
|
||||
request.pipe(backend);
|
||||
|
||||
backend.on('response', function(resp) {
|
||||
if (options.debug) console.log(resp.statusCode, resp.headers);
|
||||
response.writeHead(resp.statusCode, resp.headers);
|
||||
resp.pipe(response);
|
||||
});
|
||||
};
|
||||
|
||||
var onConnect = function(request, frontend, body) {
|
||||
var parts = request.url.split(':'),
|
||||
backend = net.connect(parts[1], parts[0]);
|
||||
|
||||
frontend.pipe(backend);
|
||||
backend.pipe(frontend);
|
||||
|
||||
backend.on('connect', function() {
|
||||
frontend.write('HTTP/1.1 200 OK\r\n\r\n');
|
||||
});
|
||||
|
||||
if (!options.debug) return;
|
||||
console.log(request.method, request.url, request.headers);
|
||||
|
||||
frontend.on('data', function(data) { console.log('I', data) });
|
||||
backend.on( 'data', function(data) { console.log('O', data) });
|
||||
};
|
||||
|
||||
proxy.on('request', onRequest);
|
||||
proxy.on('connect', onConnect);
|
||||
proxy.on('upgrade', onConnect);
|
||||
|
||||
this._proxy = proxy;
|
||||
};
|
||||
|
||||
ProxyServer.prototype.listen = function(port) {
|
||||
this._proxy.listen(port);
|
||||
};
|
||||
|
||||
ProxyServer.prototype.stop = function() {
|
||||
this._proxy.close();
|
||||
};
|
||||
|
||||
module.exports = ProxyServer;
|
||||
@@ -1,33 +1 @@
|
||||
var WebSocket = require('../lib/faye/websocket'),
|
||||
fs = require('fs'),
|
||||
http = require('http'),
|
||||
https = require('https'),
|
||||
test = require('jstest').Test
|
||||
|
||||
|
||||
EchoServer = function() {}
|
||||
EchoServer.prototype.listen = function(port, ssl) {
|
||||
var server = ssl
|
||||
? https.createServer({
|
||||
key: fs.readFileSync(__dirname + '/server.key'),
|
||||
cert: fs.readFileSync(__dirname + '/server.crt')
|
||||
})
|
||||
: http.createServer()
|
||||
|
||||
server.on('upgrade', function(request, socket, head) {
|
||||
var ws = new WebSocket(request, socket, head, ["echo"])
|
||||
ws.pipe(ws)
|
||||
})
|
||||
this._httpServer = server
|
||||
server.listen(port)
|
||||
}
|
||||
EchoServer.prototype.stop = function(callback, scope) {
|
||||
this._httpServer.on('close', function() {
|
||||
if (callback) callback.call(scope);
|
||||
});
|
||||
this._httpServer.close();
|
||||
}
|
||||
|
||||
|
||||
require('./faye/websocket/client_spec')
|
||||
|
||||
|
||||
+12
-12
@@ -1,14 +1,14 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICKTCCAZICCQDtAJo/efrTvjANBgkqhkiG9w0BAQUFADBZMQswCQYDVQQGEwJV
|
||||
SzETMBEGA1UECBMKU29tZS1TdGF0ZTEPMA0GA1UEBxMGTG9uZG9uMRAwDgYDVQQK
|
||||
EwdqY29nbGFuMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTMwNjE5MDcwNzQ1WhcN
|
||||
MTQwNjE5MDcwNzQ1WjBZMQswCQYDVQQGEwJVSzETMBEGA1UECBMKU29tZS1TdGF0
|
||||
ZTEPMA0GA1UEBxMGTG9uZG9uMRAwDgYDVQQKEwdqY29nbGFuMRIwEAYDVQQDEwls
|
||||
b2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALhPVRbctfcjCJEC
|
||||
DsZfgtTMVYMsvV/miLxc7veumuuApe5y3DFuG8Tlz3/0wrvRm3dCSUOfIBK8ktor
|
||||
VoY6QGHwrhYK2MhnJQOUTYC+FCyUp4zAYjRgJWd4uTii+uqRbLCPOF8jEx7VunTT
|
||||
Lj9hu82IdRgT3OtqzPUoTmYXCXSZAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAcARo
|
||||
TO7LTbII0HIsB7PePspFkwiuYQtvFqYm10I+4yuIdfPBdH0/OBhKvNC1O7tc7dmy
|
||||
NPd8e5FXrt6qHDgCVh0kpg37sMJp42jUCn4lguWKN5dZPkzGrRFUfXvcx1qwdF2T
|
||||
0CgyULvKWl9wt3Wp5feG8dNn1UZOGlZBZ+0GNyk=
|
||||
MIICIzCCAYwCCQDZaunNGmqaHjANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJH
|
||||
QjETMBEGA1UECBMKU29tZS1TdGF0ZTEPMA0GA1UEBxMGTG9uZG9uMQ0wCwYDVQQK
|
||||
EwRGYXllMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTQwNjIxMDkzNjAyWhcNMTUw
|
||||
NjIxMDkzNjAyWjBWMQswCQYDVQQGEwJHQjETMBEGA1UECBMKU29tZS1TdGF0ZTEP
|
||||
MA0GA1UEBxMGTG9uZG9uMQ0wCwYDVQQKEwRGYXllMRIwEAYDVQQDEwlsb2NhbGhv
|
||||
c3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANc64/S51F2OVw1IGZql483S
|
||||
sUf7QiuHyHCYxeHB8CeTKXyaH5h3ITmmqjzT5MWgTYuXf39XRf2VqicLWqs0xIAc
|
||||
RKBE1VouLM0sbNzMv1yNG7im0bMywXNlOlOmUhtjYZvEx5I10UiJrVxIpEnNiCuZ
|
||||
dgCuB944l/lQrndkaqWtAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEA1UmNwUA7KVaU
|
||||
jg3iofsr0UgFCNO9sZ6PeEoh6NETrckhYd1TB3S7QAgHMiu4e8cEVnlYyIm6oJnp
|
||||
l5edfaUHh3PGwt5jLzpg/l+OVT5qkixRJdazx+pd/CFYIgot2+7hEao9NC4GV1Tl
|
||||
yR0IxlKRsQO3iZlpe7/Klqjaq/r9tQM=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
+13
-13
@@ -1,15 +1,15 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQC4T1UW3LX3IwiRAg7GX4LUzFWDLL1f5oi8XO73rprrgKXuctwx
|
||||
bhvE5c9/9MK70Zt3QklDnyASvJLaK1aGOkBh8K4WCtjIZyUDlE2AvhQslKeMwGI0
|
||||
YCVneLk4ovrqkWywjzhfIxMe1bp00y4/YbvNiHUYE9zrasz1KE5mFwl0mQIDAQAB
|
||||
AoGAfcTc6oHnxeHpKZJ+5I0uaOmafK2d+IAG1IqSIv/KBWQ/VoyYhz58woqTYtxx
|
||||
udqZvPLFrdg6+a4mg6vJGkVLwp/PFi7r57/vqUR/P8SnuV0iTJZ7BczZHSffdzgT
|
||||
9v2XUDFZ3ZSjIi+XkCMirHc7G8BVYImqjCGy80NX3YB5RRECQQDuX+udSSZi2I0C
|
||||
gT/LnoVsb8JkanNALZH/U/XQog50I9aNf2GAAboUVsGuETL3I9f12Ku0A+xK5biv
|
||||
s4P4g01FAkEAxfALp1Yzud+ooNmbbtSTE6hrUwjFeG1skEW4GvocB5ZiQqXwv59v
|
||||
AmWedup7St2kamb5vNtcpewHGd2kUpatRQJARDwg7f0qh9EFTFpDML5H4yp6stPl
|
||||
+dERoc0e6IH7MTOxDwAPoNzdr0TGXFWACU6xWyaSwAz/btEjdOgmNtUfIQJAFrWO
|
||||
sLksIBQwBZxRv+p1oVi+T31/Imzzeq31DGtLkfdH+LuPHn0NQGomPyBx2soJFggQ
|
||||
eQF15LdqrSYHt04APQJBAO2SPMC7MxDKdhryf6PDcaL/lTKSxRttQ72jZmDU9ujp
|
||||
dcvFPgrQTa3iNLm4SWvARFXXZrrGEeDgKX7jVJygfI4=
|
||||
MIICXQIBAAKBgQDXOuP0udRdjlcNSBmapePN0rFH+0Irh8hwmMXhwfAnkyl8mh+Y
|
||||
dyE5pqo80+TFoE2Ll39/V0X9laonC1qrNMSAHESgRNVaLizNLGzczL9cjRu4ptGz
|
||||
MsFzZTpTplIbY2GbxMeSNdFIia1cSKRJzYgrmXYArgfeOJf5UK53ZGqlrQIDAQAB
|
||||
AoGBAK8U+NrbUCXK5IWpYSqsR+PmwNANVIaUrjjqDg7X9MQ8skLqHUmpnx2GtnVE
|
||||
6ZTaEjq7wruUAxuF5CRe2CLtieouaLvF/gcAsff2Q4kL8taDrM54ECC69JFfijE4
|
||||
jJfEkoJRi1B0nq2QxJke3Sm3vrW2zLDqAZ4EUIh3uxXIYgcBAkEA+imv190S+bCM
|
||||
3H/3L5LHeTRwL58HWcYYjx+/K85yaCqf4wrwyYQ1jRho76uqkjq1mvL65nOniIxd
|
||||
NRnLTiQ+jwJBANxAiY4ww16fUkBGBh2np0FfDUhWgk5G5aZWHsK+5SJZXvlV0kmn
|
||||
kf2R+8hEzAAaOh3Y4d4UBXzOZCKh0nxYdgMCQQCNsQ7oNU+KHXWrbs+TIo/ZFtp0
|
||||
Hp8LOiiu6Exfg49JcNsevhOkED5ErI7DMXhrWtWB7h4uaVN7BAXHDdUZbW4BAkAp
|
||||
Yys1/+3GaxPOphniGq3wN8dML41e3i2rOwWevLZb5QVWvwy78HQbfQIeGOdooYUI
|
||||
NMgErih10ma4p0XhPdI3AkBFp830jNItVGZtVvNRmtx2AR370qMs+AwFTK76mcMW
|
||||
xysAGnAUv7h6Qx+M6b3He8OcWVMNqMiv8yI/o2PnsvUS
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
||||
Reference in New Issue
Block a user