Initial commit
[yaffs-website] / node_modules / websocket-driver / README.md
1 # websocket-driver [![Build Status](https://travis-ci.org/faye/websocket-driver-node.svg)](https://travis-ci.org/faye/websocket-driver-node)
2
3 This module provides a complete implementation of the WebSocket protocols that
4 can be hooked up to any I/O stream. It aims to simplify things by decoupling the
5 protocol details from the I/O layer, such that users only need to implement code
6 to stream data in and out of it without needing to know anything about how the
7 protocol actually works. Think of it as a complete WebSocket system with
8 pluggable I/O.
9
10 Due to this design, you get a lot of things for free. In particular, if you hook
11 this module up to some I/O object, it will do all of this for you:
12
13 * Select the correct server-side driver to talk to the client
14 * Generate and send both server- and client-side handshakes
15 * Recognize when the handshake phase completes and the WS protocol begins
16 * Negotiate subprotocol selection based on `Sec-WebSocket-Protocol`
17 * Negotiate and use extensions via the
18   [websocket-extensions](https://github.com/faye/websocket-extensions-node)
19   module
20 * Buffer sent messages until the handshake process is finished
21 * Deal with proxies that defer delivery of the draft-76 handshake body
22 * Notify you when the socket is open and closed and when messages arrive
23 * Recombine fragmented messages
24 * Dispatch text, binary, ping, pong and close frames
25 * Manage the socket-closing handshake process
26 * Automatically reply to ping frames with a matching pong
27 * Apply masking to messages sent by the client
28
29 This library was originally extracted from the [Faye](http://faye.jcoglan.com)
30 project but now aims to provide simple WebSocket support for any Node-based
31 project.
32
33
34 ## Installation
35
36 ```
37 $ npm install websocket-driver
38 ```
39
40
41 ## Usage
42
43 This module provides protocol drivers that have the same interface on the server
44 and on the client. A WebSocket driver is an object with two duplex streams
45 attached; one for incoming/outgoing messages and one for managing the wire
46 protocol over an I/O stream. The full API is described below.
47
48
49 ### Server-side with HTTP
50
51 A Node webserver emits a special event for 'upgrade' requests, and this is where
52 you should handle WebSockets. You first check whether the request is a
53 WebSocket, and if so you can create a driver and attach the request's I/O stream
54 to it.
55
56 ```js
57 var http = require('http'),
58     websocket = require('websocket-driver');
59
60 var server = http.createServer();
61
62 server.on('upgrade', function(request, socket, body) {
63   if (!websocket.isWebSocket(request)) return;
64
65   var driver = websocket.http(request);
66
67   driver.io.write(body);
68   socket.pipe(driver.io).pipe(socket);
69
70   driver.messages.on('data', function(message) {
71     console.log('Got a message', message);
72   });
73
74   driver.start();
75 });
76 ```
77
78 Note the line `driver.io.write(body)` - you must pass the `body` buffer to the
79 socket driver in order to make certain versions of the protocol work.
80
81
82 ### Server-side with TCP
83
84 You can also handle WebSocket connections in a bare TCP server, if you're not
85 using an HTTP server and don't want to implement HTTP parsing yourself.
86
87 The driver will emit a `connect` event when a request is received, and at this
88 point you can detect whether it's a WebSocket and handle it as such. Here's an
89 example using the Node `net` module:
90
91 ```js
92 var net = require('net'),
93     websocket = require('websocket-driver');
94
95 var server = net.createServer(function(connection) {
96   var driver = websocket.server();
97
98   driver.on('connect', function() {
99     if (websocket.isWebSocket(driver)) {
100       driver.start();
101     } else {
102       // handle other HTTP requests
103     }
104   });
105
106   driver.on('close', function() { connection.end() });
107   connection.on('error', function() {});
108
109   connection.pipe(driver.io).pipe(connection);
110
111   driver.messages.pipe(driver.messages);
112 });
113
114 server.listen(4180);
115 ```
116
117 In the `connect` event, the driver gains several properties to describe the
118 request, similar to a Node request object, such as `method`, `url` and
119 `headers`. However you should remember it's not a real request object; you
120 cannot write data to it, it only tells you what request data we parsed from the
121 input.
122
123 If the request has a body, it will be in the `driver.body` buffer, but only as
124 much of the body as has been piped into the driver when the `connect` event
125 fires.
126
127
128 ### Client-side
129
130 Similarly, to implement a WebSocket client you just need to make a driver by
131 passing in a URL. After this you use the driver API as described below to
132 process incoming data and send outgoing data.
133
134
135 ```js
136 var net = require('net'),
137     websocket = require('websocket-driver');
138
139 var driver = websocket.client('ws://www.example.com/socket'),
140     tcp = net.connect(80, 'www.example.com');
141
142 tcp.pipe(driver.io).pipe(tcp);
143
144 tcp.on('connect', function() {
145   driver.start();
146 });
147
148 driver.messages.on('data', function(message) {
149   console.log('Got a message', message);
150 });
151 ```
152
153 Client drivers have two additional properties for reading the HTTP data that was
154 sent back by the server:
155
156 * `driver.statusCode` - the integer value of the HTTP status code
157 * `driver.headers` - an object containing the response headers
158
159
160 ### HTTP Proxies
161
162 The client driver supports connections via HTTP proxies using the `CONNECT`
163 method. Instead of sending the WebSocket handshake immediately, it will send a
164 `CONNECT` request, wait for a `200` response, and then proceed as normal.
165
166 To use this feature, call `driver.proxy(url)` where `url` is the origin of the
167 proxy, including a username and password if required. This produces a duplex
168 stream that you should pipe in and out of your TCP connection to the proxy
169 server. When the proxy emits `connect`, you can then pipe `driver.io` to your
170 TCP stream and call `driver.start()`.
171
172 ```js
173 var net = require('net'),
174     websocket = require('websocket-driver');
175
176 var driver = websocket.client('ws://www.example.com/socket'),
177     proxy  = driver.proxy('http://username:password@proxy.example.com'),
178     tcp    = net.connect(80, 'proxy.example.com');
179
180 tcp.pipe(proxy).pipe(tcp, {end: false});
181
182 tcp.on('connect', function() {
183   proxy.start();
184 });
185
186 proxy.on('connect', function() {
187   driver.io.pipe(tcp).pipe(driver.io);
188   driver.start();
189 });
190
191 driver.messages.on('data', function(message) {
192   console.log('Got a message', message);
193 });
194 ```
195
196 The proxy's `connect` event is also where you should perform a TLS handshake on
197 your TCP stream, if you are connecting to a `wss:` endpoint.
198
199 In the event that proxy connection fails, `proxy` will emit an `error`. You can
200 inspect the proxy's response via `proxy.statusCode` and `proxy.headers`.
201
202 ```js
203 proxy.on('error', function(error) {
204   console.error(error.message);
205   console.log(proxy.statusCode);
206   console.log(proxy.headers);
207 });
208 ```
209
210 Before calling `proxy.start()` you can set custom headers using
211 `proxy.setHeader()`:
212
213 ```js
214 proxy.setHeader('User-Agent', 'node');
215 proxy.start();
216 ```
217
218
219 ### Driver API
220
221 Drivers are created using one of the following methods:
222
223 ```js
224 driver = websocket.http(request, options)
225 driver = websocket.server(options)
226 driver = websocket.client(url, options)
227 ```
228
229 The `http` method returns a driver chosen using the headers from a Node HTTP
230 request object. The `server` method returns a driver that will parse an HTTP
231 request and then decide which driver to use for it using the `http` method. The
232 `client` method always returns a driver for the RFC version of the protocol with
233 masking enabled on outgoing frames.
234
235 The `options` argument is optional, and is an object. It may contain the
236 following fields:
237
238 * `maxLength` - the maximum allowed size of incoming message frames, in bytes.
239   The default value is `2^26 - 1`, or 1 byte short of 64 MiB.
240 * `protocols` - an array of strings representing acceptable subprotocols for use
241   over the socket. The driver will negotiate one of these to use via the
242   `Sec-WebSocket-Protocol` header if supported by the other peer.
243
244 A driver has two duplex streams attached to it:
245
246 * <b>`driver.io`</b> - this stream should be attached to an I/O socket like a
247   TCP stream. Pipe incoming TCP chunks to this stream for them to be parsed, and
248   pipe this stream back into TCP to send outgoing frames.
249 * <b>`driver.messages`</b> - this stream emits messages received over the
250   WebSocket.  Writing to it sends messages to the other peer by emitting frames
251   via the `driver.io` stream.
252
253 All drivers respond to the following API methods, but some of them are no-ops
254 depending on whether the client supports the behaviour.
255
256 Note that most of these methods are commands: if they produce data that should
257 be sent over the socket, they will give this to you by emitting `data` events on
258 the `driver.io` stream.
259
260 #### `driver.on('open', function(event) {})`
261
262 Adds a callback to execute when the socket becomes open.
263
264 #### `driver.on('message', function(event) {})`
265
266 Adds a callback to execute when a message is received. `event` will have a
267 `data` attribute containing either a string in the case of a text message or a
268 `Buffer` in the case of a binary message.
269
270 You can also listen for messages using the `driver.messages.on('data')` event,
271 which emits strings for text messages and buffers for binary messages.
272
273 #### `driver.on('error', function(event) {})`
274
275 Adds a callback to execute when a protocol error occurs due to the other peer
276 sending an invalid byte sequence. `event` will have a `message` attribute
277 describing the error.
278
279 #### `driver.on('close', function(event) {})`
280
281 Adds a callback to execute when the socket becomes closed. The `event` object
282 has `code` and `reason` attributes.
283
284 #### `driver.addExtension(extension)`
285
286 Registers a protocol extension whose operation will be negotiated via the
287 `Sec-WebSocket-Extensions` header. `extension` is any extension compatible with
288 the [websocket-extensions](https://github.com/faye/websocket-extensions-node)
289 framework.
290
291 #### `driver.setHeader(name, value)`
292
293 Sets a custom header to be sent as part of the handshake response, either from
294 the server or from the client. Must be called before `start()`, since this is
295 when the headers are serialized and sent.
296
297 #### `driver.start()`
298
299 Initiates the protocol by sending the handshake - either the response for a
300 server-side driver or the request for a client-side one. This should be the
301 first method you invoke.  Returns `true` if and only if a handshake was sent.
302
303 #### `driver.parse(string)`
304
305 Takes a string and parses it, potentially resulting in message events being
306 emitted (see `on('message')` above) or in data being sent to `driver.io`.  You
307 should send all data you receive via I/O to this method by piping a stream into
308 `driver.io`.
309
310 #### `driver.text(string)`
311
312 Sends a text message over the socket. If the socket handshake is not yet
313 complete, the message will be queued until it is. Returns `true` if the message
314 was sent or queued, and `false` if the socket can no longer send messages.
315
316 This method is equivalent to `driver.messages.write(string)`.
317
318 #### `driver.binary(buffer)`
319
320 Takes a `Buffer` and sends it as a binary message. Will queue and return `true`
321 or `false` the same way as the `text` method. It will also return `false` if the
322 driver does not support binary messages.
323
324 This method is equivalent to `driver.messages.write(buffer)`.
325
326 #### `driver.ping(string = '', function() {})`
327
328 Sends a ping frame over the socket, queueing it if necessary. `string` and the
329 callback are both optional. If a callback is given, it will be invoked when the
330 socket receives a pong frame whose content matches `string`. Returns `false` if
331 frames can no longer be sent, or if the driver does not support ping/pong.
332
333 #### `driver.pong(string = '')`
334
335 Sends a pong frame over the socket, queueing it if necessary. `string` is
336 optional. Returns `false` if frames can no longer be sent, or if the driver does
337 not support ping/pong.
338
339 You don't need to call this when a ping frame is received; pings are replied to
340 automatically by the driver. This method is for sending unsolicited pongs.
341
342 #### `driver.close()`
343
344 Initiates the closing handshake if the socket is still open. For drivers with no
345 closing handshake, this will result in the immediate execution of the
346 `on('close')` driver. For drivers with a closing handshake, this sends a closing
347 frame and `emit('close')` will execute when a response is received or a protocol
348 error occurs.
349
350 #### `driver.version`
351
352 Returns the WebSocket version in use as a string. Will either be `hixie-75`,
353 `hixie-76` or `hybi-$version`.
354
355 #### `driver.protocol`
356
357 Returns a string containing the selected subprotocol, if any was agreed upon
358 using the `Sec-WebSocket-Protocol` mechanism. This value becomes available after
359 `emit('open')` has fired.
360
361
362 ## License
363
364 (The MIT License)
365
366 Copyright (c) 2010-2016 James Coglan
367
368 Permission is hereby granted, free of charge, to any person obtaining a copy of
369 this software and associated documentation files (the 'Software'), to deal in
370 the Software without restriction, including without limitation the rights to
371 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
372 the Software, and to permit persons to whom the Software is furnished to do so,
373 subject to the following conditions:
374
375 The above copyright notice and this permission notice shall be included in all
376 copies or substantial portions of the Software.
377
378 THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
379 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
380 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
381 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
382 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
383 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.