webtube 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README +715 -560
- data/bin/wsc +53 -34
- data/lib/webtube.rb +510 -257
- data/lib/webtube/vital-statistics.rb +31 -24
- data/lib/webtube/webrick.rb +79 -59
- data/sample-server.rb +4 -4
- data/webtube.gemspec +6 -6
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b448e7b4b7219de788008716f089c4582312203
|
4
|
+
data.tar.gz: 17b42da8e523eebaf496404bf0ec43c4d2f22264
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8412f80b2f0590b876658b695dbc23a4932c66e433efc30636275d32a499e53c5d0fa3f6f45df0d4dd56db5fc3fff537da255e229a8215df54552124203611a
|
7
|
+
data.tar.gz: ab3e133faf0b9957832e4bad28937e7bac16158aa6b31a9a3b3f29ea7d5b66ec1e2b8e8dafd717837a435ee3600775fe59165d3d5aa65d59d6152e17d82f0df2
|
data/README
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
This is Webtube, a Ruby implementation of the WebSocket protocol
|
2
|
-
RFC 6455.
|
1
|
+
This is Webtube, a Ruby implementation of the WebSocket protocol
|
2
|
+
defined in RFC 6455.
|
3
3
|
|
4
4
|
|
5
5
|
== Sample client
|
6
6
|
|
7
|
-
(Also see [[wsc]], a basic command line utility for talking to
|
8
|
-
servers and included with the Webtube distribution.)
|
7
|
+
(Also see [[wsc]], a basic command line utility for talking to
|
8
|
+
WebSocket servers and included with the Webtube distribution.)
|
9
9
|
|
10
10
|
require 'webtube'
|
11
11
|
|
@@ -25,14 +25,15 @@ servers and included with the Webtube distribution.)
|
|
25
25
|
|
26
26
|
== Sample server
|
27
27
|
|
28
|
-
(This code is also available as a separate file; see
|
28
|
+
(This code is also available as a separate file; see
|
29
|
+
[[sample-server.rb]].)
|
29
30
|
|
30
31
|
#! /usr/bin/ruby
|
31
32
|
|
32
|
-
# A sample WEBrick server using the Webtube API. It listens
|
33
|
-
# provides two services: [[/diag]], which
|
34
|
-
# [[Webtube#run]] and remains silent
|
35
|
-
#
|
33
|
+
# A sample WEBrick server using the Webtube API. It listens
|
34
|
+
# on port 8888 and provides two services: [[/diag]], which
|
35
|
+
# logs all the events from [[Webtube#run]] and remains silent
|
36
|
+
# towards the client, and [[/echo]], which echos.
|
36
37
|
|
37
38
|
require 'webrick'
|
38
39
|
require 'webtube/webrick'
|
@@ -78,17 +79,24 @@ servers and included with the Webtube distribution.)
|
|
78
79
|
|
79
80
|
== WebSocketCat's commands
|
80
81
|
|
81
|
-
Webtube comes with [[wsc]], a command line utility for talking
|
82
|
-
server. A session might look like this:
|
82
|
+
Webtube comes with [[wsc]], a command line utility for talking
|
83
|
+
to WebSocket server. A session might look like this:
|
83
84
|
|
84
85
|
$ wsc ws://echo.websocket.org/
|
85
86
|
Connecting to ws://echo.websocket.org/ ...
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
87
|
+
> GET / HTTP/1.1
|
88
|
+
> Host: echo.websocket.org
|
89
|
+
> Upgrade: websocket
|
90
|
+
> Connection: upgrade
|
91
|
+
> Sec-websocket-key: HSJFpBo1mtbAS3h/7593Cw==
|
92
|
+
> Sec-websocket-version: 13
|
93
|
+
|
94
|
+
< 101 Web Socket Protocol Handshake
|
95
|
+
< connection: Upgrade
|
96
|
+
< date: Thu, 26 Apr 2018 19:25:11 GMT
|
97
|
+
< sec-websocket-accept: CN9MPzM4nmqeRGsR0YFDsipOXzQ=
|
98
|
+
< server: Kaazing Gateway
|
99
|
+
< upgrade: websocket
|
92
100
|
|
93
101
|
*** open
|
94
102
|
Hello, server!
|
@@ -99,155 +107,231 @@ server. A session might look like this:
|
|
99
107
|
/close 1001
|
100
108
|
*** close
|
101
109
|
|
102
|
-
Prefixed with [[
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
110
|
+
Prefixed with [[>]] is the HTTP request to initiate a WebSocket
|
111
|
+
connection, with [[<]] is the HTTP response header from the
|
112
|
+
server, with [[<<<]] are incoming text messages (non-text
|
113
|
+
messages are prefixed with [[<N<]] where N is the message
|
114
|
+
opcode), and with [[***]] are miscellaneous other events. Lines
|
115
|
+
entered by user are sent to the server as text messages. The
|
116
|
+
user can invoke some special commands using the slash prefix:
|
107
117
|
|
108
118
|
- [[/ping [message]]] sends a ping frame to the server.
|
109
119
|
|
110
|
-
- [[/close [status [explanation]]]] sends a close frame to the
|
111
|
-
status code is specified as an unsigned decimal
|
120
|
+
- [[/close [status [explanation]]]] sends a close frame to the
|
121
|
+
server. The status code is specified as an unsigned decimal
|
122
|
+
number.
|
112
123
|
|
113
|
-
- [[/N [payload]]] sends a message or control frame of opcode
|
114
|
-
single hex digit, to the server. Per
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
124
|
+
- [[/N [payload]]] sends a message or control frame of opcode
|
125
|
+
[[N]], given as a single hex digit, to the server. Per
|
126
|
+
protocol specification, [[/1]] is text message, [[/2]] is
|
127
|
+
binary message, [[/8]] is close, [[/9]] is ping, [[/A]] is
|
128
|
+
pong. Other opcodes can have application-specific meaning.
|
129
|
+
Note that the specification requires kicking clients (or
|
130
|
+
servers) who send messages so cryptic that the server (or
|
131
|
+
client) can't understand them.
|
119
132
|
|
120
133
|
- [[/help]] shows online help.
|
121
134
|
|
122
|
-
If you need to start a text message with a slash, you can double
|
123
|
-
or you can use the explicit [[/1]] command. EOF
|
124
|
-
[[/close 1000]].
|
135
|
+
If you need to start a text message with a slash, you can double
|
136
|
+
it for escape, or you can use the explicit [[/1]] command. EOF
|
137
|
+
from stdin is equivalent to [[/close 1000]].
|
125
138
|
|
126
139
|
|
127
140
|
== API overview
|
128
141
|
|
129
142
|
=== The [[Webtube]] class
|
130
143
|
|
131
|
-
(Direct) instances of the [[Webtube]] class are hashed and
|
132
|
-
identity, thus behaving in an intuitive
|
133
|
-
or elements of a [[Set]].
|
144
|
+
(Direct) instances of the [[Webtube]] class are hashed and
|
145
|
+
[[eql?]]-compared by identity, thus behaving in an intuitive
|
146
|
+
manner when used as keys of a [[Hash]] or elements of a [[Set]].
|
134
147
|
|
135
|
-
In addition to the methods described below, each [[Webtube]]
|
136
|
-
the readable and writable attributes
|
137
|
-
[[Webtube]] does not
|
138
|
-
|
148
|
+
In addition to the methods described below, each [[Webtube]]
|
149
|
+
instance will have the readable and writable attributes
|
150
|
+
[[header]], [[session]], and [[context]]. [[Webtube]] does not
|
151
|
+
care about them; they are intended to facilitate user code
|
152
|
+
associating contextual or environmental data with the
|
153
|
+
[[Webtube]].
|
139
154
|
|
140
155
|
The [[Webtube]]-[[WEBrick]] integration (in particular,
|
141
|
-
[[WEBrick::HTTPServer#accept_webtube]]) sets the [[header]]
|
142
|
-
created [[Webtube]] instances to the
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
156
|
+
[[WEBrick::HTTPServer#accept_webtube]]) sets the [[header]]
|
157
|
+
attribute of newly created [[Webtube]] instances to the
|
158
|
+
[[WEBrick::HTTPRequest]] used to establish the WebSocket
|
159
|
+
connection; this may facilitate extracting HTTP header fields,
|
160
|
+
URL query parameters or cookies from the request at a later
|
161
|
+
time. (Note that because the upgrade request is necessary
|
162
|
+
delivered using the HTTP [[GET]] method, the HTTP file upload
|
163
|
+
protocol, which requires [[POST]] is not available for WebSocket
|
164
|
+
connections. Also note that the WebDAV extensions are mutually
|
165
|
+
incompatible with the WebSocket protocol, within the bounds of a
|
166
|
+
single HTTP request, for the same reason.)
|
150
167
|
|
151
168
|
|
152
169
|
==== [[Webtube::connect]]: connect to a remote server
|
153
170
|
|
154
|
-
A WebSocket connection to a remote server can be set up by
|
155
|
-
[[Webtube::connect]]. The calling interface goes like
|
171
|
+
A WebSocket connection to a remote server can be set up by
|
172
|
+
calling [[Webtube::connect]]. The calling interface goes like
|
173
|
+
this:
|
156
174
|
|
157
175
|
Webtube::connect(url,
|
158
|
-
header_fields: {},
|
159
|
-
ssl_verify_mode: nil,
|
160
|
-
on_http_response: nil,
|
161
176
|
allow_rsv_bits: 0,
|
162
|
-
allow_opcodes: [Webtube::OPCODE_TEXT
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
[[
|
177
|
+
allow_opcodes: [Webtube::OPCODE_TEXT],
|
178
|
+
http_header: {},
|
179
|
+
ssl_verify_mode: OpenSSL::SSL::VERIFY_PEER,
|
180
|
+
ssl_cert_store: nil,
|
181
|
+
tcp_connect_timeout: nil,
|
182
|
+
tcp_nodelay: true,
|
183
|
+
close_socket: true,
|
184
|
+
on_http_request: nil,
|
185
|
+
on_http_response: nil,
|
186
|
+
on_ssl_handshake: nil,
|
187
|
+
on_tcp_connect: nil)
|
188
|
+
|
189
|
+
Only [[url]] is mandatory, and in most contexts, setting [[url]]
|
190
|
+
and [[allow_opcodes]] is enough. [[http_header]] is notable as
|
191
|
+
a way to pass HTTP cookies along with the WebSocket connection
|
192
|
+
request.
|
193
|
+
|
194
|
+
- [[url]] is a [[String]] representing the target of the
|
195
|
+
connection in the URL form, using either the [[ws:]] or
|
196
|
+
[[wss:]] protocol prefix. A convenient public server for
|
197
|
+
basic testing is available on [[ws://echo.websocket.org/]].
|
198
|
+
|
199
|
+
- [[http_header]] is a [[Hash]] for specifying HTTP header
|
200
|
+
fields for the request. [[Webtube]] will consider entries
|
201
|
+
specified here to have a priority over automatically created
|
202
|
+
header fields even for the fields defined by the WebSocket
|
203
|
+
standard such as [[Upgrade]] and [[Sec-WebSocket-Key]];
|
204
|
+
caution should be exercised when using this feature.
|
205
|
+
|
206
|
+
- [[ssl_verify_mode]] will specify OpenSSL's mode of verifying
|
207
|
+
the certificate at the end of the SSL handshake. Supported
|
208
|
+
values are [[OpenSSL::SSL::VERIFY_PEER]] (the default, and the
|
209
|
+
recommended value) and [[OpenSSL::SSL::VERIFY_NONE]] (to be
|
210
|
+
used with great caution). Not applicable if the connection is
|
211
|
+
not encrypted (that is, the [[url]] parameter has a [[ws:]]
|
212
|
+
rather than [[wss:]] prefix).
|
213
|
+
|
214
|
+
- [[ssl_cert_store]], if given, should be a prepared
|
215
|
+
[[OpenSSL::X509::Store]] instance containing the trusted root
|
216
|
+
certificates. If not given, the system's defaults are used.
|
217
|
+
Not applicable if the connection is not encrypted (that is,
|
218
|
+
the [[url]] parameter has a [[ws:]] rather than [[wss:]]
|
219
|
+
prefix).
|
220
|
+
|
221
|
+
- [[tcp_connect_timeout]], if given, specifies the number of
|
222
|
+
seconds allotted for establishing the TCP connection. The
|
223
|
+
[[Net::OpenTimeout]] exception will be raised if the TCP
|
224
|
+
handshake can not be completed within the given time.
|
225
|
+
|
226
|
+
- [[tcp_nodelay]] specifies whether the [[TCP_NODELAY]] socket
|
227
|
+
option should be turned on, requesting that the Nagle's
|
228
|
+
algorithm not be used. The default is [[true]], which may
|
229
|
+
slightly reduce latency at the expense of bulk throughput.
|
230
|
+
Turning [[tcp_nodelay]] off will re-enable the Nagle's
|
231
|
+
algorithm, which may slightly improve bulk throughput at the
|
232
|
+
expense of latency.
|
233
|
+
|
234
|
+
- [[on_http_request]], if supplied, will be called with the
|
235
|
+
HTTP-level request to initiate a WebSocket connection, as a
|
236
|
+
[[String]]. This allows the client code, for an example, to
|
237
|
+
display the request to the user.
|
182
238
|
|
183
239
|
- [[on_http_response]], if supplied, will be called with the
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
[[
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
[[
|
232
|
-
|
233
|
-
|
234
|
-
the
|
235
|
-
|
236
|
-
|
237
|
-
|
240
|
+
header of the HTTP-level response to the request to initiate a
|
241
|
+
WebSocket connection, as a [[String]]. (In version 1.1.0, the
|
242
|
+
string is reconstituted from a parsed [[Net::HTTPResponse]],
|
243
|
+
and may differ from the actual response in details that
|
244
|
+
usually do not matter, such as capitalisation of header
|
245
|
+
fields' names. In a future version, the string may be a copy
|
246
|
+
of the actual response.) This allows the client code, for an
|
247
|
+
example, to display the response header to the user.
|
248
|
+
|
249
|
+
- [[on_ssl_handshake]], if supplied, will be called with the
|
250
|
+
[[OpenSSL::SSL::SSLSocket]] instance upon completion of the
|
251
|
+
SSL handshake. Not applicable if the connection is not
|
252
|
+
encrypted (that is, the [[url]] parameter has a [[ws:]] rather
|
253
|
+
than [[wss:]] prefix).
|
254
|
+
|
255
|
+
- [[on_tcp_connect]], if supplied, will be called with the
|
256
|
+
[[TCPSocket]] instance upon completion of the TCP handshake.
|
257
|
+
|
258
|
+
|
259
|
+
The following fields will be passed on to [[Webtube::new]]
|
260
|
+
intact:
|
261
|
+
|
262
|
+
- [[allow_rsv_bits]] is an [[Integer]], a bitmap of the reserved
|
263
|
+
bits (4 for RSV1, 2 for RSV2, 1 for RSV3) that, when appearing
|
264
|
+
on inbound frames, should be considered 'known'. The
|
265
|
+
WebSocket protocol specification mandates failing the
|
266
|
+
connection if a frame with unknown reserved bits should
|
267
|
+
arrive, and [[Webtube]] complies. Note that the current
|
268
|
+
version of [[Webtube]] does not offer a convenient way for the
|
269
|
+
client code to access the reserved bits of data messages, only
|
270
|
+
of control frames.
|
271
|
+
|
272
|
+
- [[allow_opcodes]] specifies the opcodes of messages and
|
273
|
+
control frames that should be considered 'known'. The
|
274
|
+
WebSocket protocol specification mandates failing the
|
275
|
+
connection if a frame with an unknown opcode should arrive,
|
276
|
+
and [[Webtube]] complies. The [[Webtube]] instance will store
|
277
|
+
this object and use its [[include?]] method for the test, thus
|
278
|
+
allowing either [[Array]], [[Set]] or [[Range]] instances to
|
279
|
+
work. The opcodes subject to this kind of filtering are the
|
280
|
+
data message opcodes 1-7 and the control frame opcodes 8-15;
|
281
|
+
note, however, that the control frame opcodes 8
|
282
|
+
([[OPCODE_CLOSE]]), 9 ([[OPCODE_PING]]), and 10
|
283
|
+
([[OPCODE_PONG]]) are essential infrastructural opcodes
|
284
|
+
defined by the standard, so [[Webtube]] will always consider
|
285
|
+
them 'known'. However, control frames of these opcodes will
|
286
|
+
be passed to the [[oncontrolframe]] event handler (if any)
|
287
|
+
only if [[allow_opcodes]] approves such opcodes.
|
288
|
+
|
289
|
+
- [[close_socket]] specifies whether the [[Webtube]] instance
|
290
|
+
should close the [[Socket]] when the connection is terminated.
|
291
|
+
The default is [[true]]; it may need to be set to [[false]] in
|
292
|
+
order to suppress [[Webtube]]'s closure of its socket in
|
293
|
+
contexts sockets are managed by other means, such as the
|
294
|
+
WEBrick server.
|
295
|
+
|
296
|
+
Upon success, [[Webtube::connect]] will return the [[Webtube]]
|
297
|
+
instance representing the client endpoint. Upon WebSocket-level
|
298
|
+
failure with lower layers intact, a
|
299
|
+
[[Webtube::WebSocketUpgradeFailed]] exception will be thrown
|
300
|
+
instead. This exception derives from [[StandardError]] as most
|
301
|
+
run-time errors. In the the current version of [[Webtube]], the
|
302
|
+
specific known subclasses are:
|
303
|
+
|
304
|
+
- [[Webtube::WebSocketDeclined]] for when the server is not
|
305
|
+
responding to the WebSocket connection initiation request
|
306
|
+
affirmatively (which can, by design of the protocol, mean that
|
307
|
+
the server wants to speak plain old HTTP);
|
308
|
+
|
309
|
+
- [[Webtube::WebSocketVersionMismatch]] for when the server
|
310
|
+
requests usage of a WebSocket protocol version that
|
311
|
+
[[Webtube]] does not know. At the time of [[Webtube]]'s
|
312
|
+
creation, only one WebSocket protocol version -- namely, 13 --
|
313
|
+
has been defined (by RFC 6455]), but this may change in the
|
314
|
+
future, and it is possible that a hypothetical future server
|
315
|
+
will not be backwards compatible to the original WebSocket
|
316
|
+
protocol.
|
317
|
+
|
318
|
+
Other exceptions representing TCP-level, HTTP-level, or
|
319
|
+
infrastructure failures can also occur.
|
238
320
|
|
239
321
|
|
240
322
|
==== [[Webtube::new]]: wrap a [[Socket]] into a [[Webtube]]
|
241
323
|
|
242
|
-
An instance of [[Webtube]] represents an endpoint of a WebSocket
|
243
|
-
Because the protocol's core is symmetric, both ends
|
244
|
-
instances of the same class. Note that
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
324
|
+
An instance of [[Webtube]] represents an endpoint of a WebSocket
|
325
|
+
connection. Because the protocol's core is symmetric, both ends
|
326
|
+
can be represented by instances of the same class. Note that
|
327
|
+
the constructor assumes the opening handshake and initial
|
328
|
+
negotiation is complete. Code needing to connect to a remote
|
329
|
+
WebSocket server should usually call [[Webtube::connect]]
|
330
|
+
instead of invoking the constructor directly. Code needing to
|
331
|
+
accept incoming WebSocket connections should usually call the
|
332
|
+
server-specific glue code such as
|
333
|
+
[[WEBrick::HTTPServer#accept_webtube]] (available after
|
334
|
+
[[require 'webtube/webrick']]).
|
251
335
|
|
252
336
|
The constructor's calling interface goes like this:
|
253
337
|
|
@@ -256,292 +340,335 @@ The constructor's calling interface goes like this:
|
|
256
340
|
allow_opcodes: [Webtube::OPCODE_TEXT],
|
257
341
|
close_socket: true)
|
258
342
|
|
259
|
-
- [[socket]] is the underlying [[Socket]] instance for sending
|
260
|
-
data.
|
261
|
-
|
262
|
-
- [[serverp]] is a Boolean indicating whether this socket represents the server
|
263
|
-
(as contrary to the client) side of the connection. While the WebSocket
|
264
|
-
protocol is largely symmetric, it requires a special masking procedure on
|
265
|
-
frames transmitted by the client to the server, and prohibits it on frames
|
266
|
-
transmitted by the server to the client. Along with masking itself, this is
|
267
|
-
reflected in a header flag of each frame.
|
268
|
-
|
269
|
-
- [[allow_rsv_bits]] is an [[Integer]], a bitmap of the reserved bits (4 for
|
270
|
-
RSV1, 2 for RSV2, 1 for RSV3) that, when appearing on inbound frames, should
|
271
|
-
be considered 'known'. The WebSocket protocol specification mandates failing
|
272
|
-
the connection if a frame with unknown reserved bits should arrive, and
|
273
|
-
[[Webtube]] complies. Note that the current version of [[Webtube]] does not
|
274
|
-
offer a convenient way for the client code to access the reserved bits of data
|
275
|
-
messages, only of control frames.
|
276
|
-
|
277
|
-
- [[allow_opcodes]] specifies the opcodes of messages and control frames that
|
278
|
-
should be considered 'known'. The WebSocket protocol specification mandates
|
279
|
-
failing the connection if a frame with an unknown opcode should arrive, and
|
280
|
-
[[Webtube]] complies. The [[Webtube]] instance will store this object and use
|
281
|
-
its [[include?]] method for the test, thus allowing either [[Array]], [[Set]]
|
282
|
-
or [[Range]] instances to work. The opcodes subject to this kind of filtering
|
283
|
-
are the data message opcodes 1-7 and the control frame opcodes 8-15; note,
|
284
|
-
however, that the control frame opcodes 8 ([[OPCODE_CLOSE]]), 9
|
285
|
-
([[OPCODE_PING]]), and 10 ([[OPCODE_PONG]]) are essential infrastructural
|
286
|
-
opcodes defined by the standard, so [[Webtube]] will always consider them
|
287
|
-
'known'. However, control frames of these opcodes will be passed to the
|
288
|
-
[[oncontrolframe]] event handler (if any) only if [[allow_opcodes]] approves
|
289
|
-
such opcodes.
|
290
|
-
|
291
|
-
- [[close_socket]] specifies whether the [[Webtube]] instance should close the
|
292
|
-
[[Socket]] when the connection is terminated. The default is [[true]]; it
|
293
|
-
may need to be set to [[false]] in order to suppress [[Webtube]]'s closure of
|
294
|
-
its socket in contexts sockets are managed by other means, such as the WEBrick
|
295
|
-
server.
|
296
|
-
|
297
|
-
|
298
|
-
==== [[Webtube#run]]: the loop for incoming events
|
299
|
-
|
300
|
-
run(listener)
|
301
|
-
|
302
|
-
This method runs a loop to read all the messages and control frames coming in
|
303
|
-
via this WebSocket, and hands events to the given [[listener]]. The listener
|
304
|
-
can implement the following methods:
|
305
|
-
|
306
|
-
- [[onopen(webtube)]] will be called as soon as the channel is set up.
|
307
|
-
|
308
|
-
- [[onmessage(webtube, message_body, opcode)]] will be called with each
|
309
|
-
arriving data message once it has been defragmented. The data will be passed
|
310
|
-
to it as a [[String]], encoded in [[UTF-8]] for [[OPCODE_TEXT]] messages and
|
311
|
-
in [[ASCII-8BIT]] for all the other message opcodes.
|
343
|
+
- [[socket]] is the underlying [[Socket]] instance for sending
|
344
|
+
and receiving data.
|
312
345
|
|
313
|
-
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
frame. [[Webtube]] will take care of ponging all the pings, but the
|
321
|
-
listener may want to process such an event for statistical information.
|
322
|
-
|
323
|
-
- [[onpong(webtube, frame)]] will be called upon receipt of an [[OPCODE_PONG]]
|
346
|
+
- [[serverp]] is a Boolean indicating whether this socket
|
347
|
+
represents the server (as contrary to the client) side of the
|
348
|
+
connection. While the WebSocket protocol is largely
|
349
|
+
symmetric, it requires a special masking procedure on frames
|
350
|
+
transmitted by the client to the server, and prohibits it on
|
351
|
+
frames transmitted by the server to the client. Along with
|
352
|
+
masking itself, this is reflected in a header flag of each
|
324
353
|
frame.
|
325
354
|
|
326
|
-
- [[
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
lifetime, it will need to either handle this work inside calls to the
|
360
|
-
[[listener]] or set up separate [[Thread]]s for the [[Webtube#run]] and for the
|
361
|
-
other work.
|
362
|
-
|
363
|
-
[[Webtube#run]] will raise instances of [[Webtube::ProtocolError]] if events
|
364
|
-
that the WebSocket protocol does not permit should happen. In the current
|
365
|
-
version of [[Webtube]], the specific known subclasses are:
|
366
|
-
|
367
|
-
- [[Webtube::BrokenFrame]] indicates that a complete frame could not be read
|
368
|
-
from the underlying TCP connection. The [[partial_frame]] attribute holds as
|
369
|
-
much data, as a [[String]] of [[ASCII-8BIT]] encoding, as was available.
|
370
|
-
|
371
|
-
- [[Webtube::UnknownReservedBit]] indicates that a frame with an RSV bit not
|
372
|
-
specifically permitted by the [[allow_rsv_bits]] parameter was received. The
|
373
|
-
[[frame]] attribute holds the frame as a [[Webtube::Frame]] instance.
|
374
|
-
|
375
|
-
- [[Webtube::UnknownOpcode]] indicates that a frame with an opcode not
|
376
|
-
specifically permitted by the [[allow_opcodes]] parameter, or by the standard,
|
377
|
-
was received. The [[frame]] attribute holds the frame as a [[Webtube::Frame]]
|
378
|
-
instance. Note that if the opcode indicates a data message (as contrary to a
|
379
|
-
control frame), the [[frame]] will hold only its first fragment, as WebSocket
|
380
|
-
data messages are subject to fragmentation and the message's opcode is stored
|
381
|
-
in the first fragment.
|
382
|
-
|
383
|
-
- [[Webtube::UnmaskedFrameToServer]] indicates that a [[Webtube]] running in
|
384
|
-
server mode received a frame without masking. As per the WebSocket standard,
|
385
|
-
[[Webtube]] considers this a fatal protocol failure. The [[frame]] attribute
|
386
|
-
holds the frame as a [[Webtube::Frame]] instance.
|
387
|
-
|
388
|
-
- [[Webtube::MaskedFrameToClient]] indicates that a [[Webtube]] running in
|
389
|
-
client mode received a frame with masking. As per the WebSocket standard,
|
390
|
-
[[Webtube]] considers this a fatal protocol failure. The [[frame]] attribute
|
391
|
-
holds the frame as a [[Webtube::Frame]] instance.
|
392
|
-
|
393
|
-
- [[Webtube::MissingContinuationFrame]] indicates receipt of a new data message
|
394
|
-
initial frame while the [[Webtube]] was expecting a continuation frame of a
|
395
|
-
fragmented data message. Note that control frames are permitted to arrive
|
396
|
-
interleaved with fragments of a data message.
|
397
|
-
|
398
|
-
- [[Webtube::UnexpectedContinuationFrame]] indicates receipt of a data message
|
399
|
-
continuation frame while the [[Webtube]] was not expecting one. The [[frame]]
|
400
|
-
attribute holds the frame as a [[Webtube::Frame]] instance.
|
401
|
-
|
402
|
-
- [[Webtube::BadlyEncodedText]] indicates receipt of a text message
|
403
|
-
([[OPCODE_TEXT]]) whose content is not a valid UTF-8 string. As per the
|
404
|
-
WebSocket standard, [[Webtube]] considers this a fatal protocol failure. The
|
405
|
-
[[data]] attribute holds the payload as a [[String]] instance of the
|
406
|
-
[[ASCII-8BIT]] encoding.
|
355
|
+
- [[allow_rsv_bits]] is an [[Integer]], a bitmap of the reserved
|
356
|
+
bits (4 for RSV1, 2 for RSV2, 1 for RSV3) that, when appearing
|
357
|
+
on inbound frames, should be considered 'known'. The
|
358
|
+
WebSocket protocol specification mandates failing the
|
359
|
+
connection if a frame with unknown reserved bits should
|
360
|
+
arrive, and [[Webtube]] complies. Note that the current
|
361
|
+
version of [[Webtube]] does not offer a convenient way for the
|
362
|
+
client code to access the reserved bits of data messages, only
|
363
|
+
of control frames.
|
364
|
+
|
365
|
+
- [[allow_opcodes]] specifies the opcodes of messages and
|
366
|
+
control frames that should be considered 'known'. The
|
367
|
+
WebSocket protocol specification mandates failing the
|
368
|
+
connection if a frame with an unknown opcode should arrive,
|
369
|
+
and [[Webtube]] complies. The [[Webtube]] instance will store
|
370
|
+
this object and use its [[include?]] method for the test, thus
|
371
|
+
allowing either [[Array]], [[Set]] or [[Range]] instances to
|
372
|
+
work. The opcodes subject to this kind of filtering are the
|
373
|
+
data message opcodes 1-7 and the control frame opcodes 8-15;
|
374
|
+
note, however, that the control frame opcodes 8
|
375
|
+
([[OPCODE_CLOSE]]), 9 ([[OPCODE_PING]]), and 10
|
376
|
+
([[OPCODE_PONG]]) are essential infrastructural opcodes
|
377
|
+
defined by the standard, so [[Webtube]] will always consider
|
378
|
+
them 'known'. However, control frames of these opcodes will
|
379
|
+
be passed to the [[oncontrolframe]] event handler (if any)
|
380
|
+
only if [[allow_opcodes]] approves such opcodes.
|
381
|
+
|
382
|
+
- [[close_socket]] specifies whether the [[Webtube]] instance
|
383
|
+
should close the [[Socket]] when the connection is terminated.
|
384
|
+
The default is [[true]]; it may need to be set to [[false]] in
|
385
|
+
order to suppress [[Webtube]]'s closure of its socket in
|
386
|
+
contexts sockets are managed by other means, such as the
|
387
|
+
WEBrick server.
|
407
388
|
|
408
|
-
- [[Webtube::FragmenedControlFrame]] indicates receipt of a control frame whose
|
409
|
-
[[FIN]] flag is not set.
|
410
389
|
|
411
|
-
|
412
|
-
can also occur.
|
390
|
+
==== [[Webtube#run]]: the loop for incoming events
|
413
391
|
|
392
|
+
run(listener)
|
414
393
|
|
415
|
-
|
394
|
+
This method runs a loop to read all the messages and control
|
395
|
+
frames coming in via this WebSocket, and hands events to the
|
396
|
+
given [[listener]]. The listener can implement the following
|
397
|
+
methods:
|
398
|
+
|
399
|
+
- [[onopen(webtube)]] will be called as soon as the channel is
|
400
|
+
set up.
|
401
|
+
|
402
|
+
- [[onmessage(webtube, message_body, opcode)]] will be called
|
403
|
+
with each arriving data message once it has been defragmented.
|
404
|
+
The data will be passed to it as a [[String]], encoded in
|
405
|
+
[[UTF-8]] for [[OPCODE_TEXT]] messages and in [[ASCII-8BIT]]
|
406
|
+
for all the other message opcodes.
|
407
|
+
|
408
|
+
- [[oncontrolframe(webtube, frame)]] will be called upon receipt
|
409
|
+
of a control frame whose opcode is listed in the
|
410
|
+
[[allow_opcodes]] parameter of this [[Webtube]] instance. The
|
411
|
+
frame is repreented by an instance of [[Webtube::Frame]].
|
412
|
+
Note that [[Webtube]] handles connection closures
|
413
|
+
([[OPCODE_CLOSE]]) and ponging all the pings ([[OPCODE_PING]])
|
414
|
+
automatically.
|
415
|
+
|
416
|
+
- [[onping(webtube, frame)]] will be called upon receipt of an
|
417
|
+
[[OPCODE_PING]] frame. [[Webtube]] will take care of ponging
|
418
|
+
all the pings, but the listener may want to process such an
|
419
|
+
event for statistical information.
|
420
|
+
|
421
|
+
- [[onpong(webtube, frame)]] will be called upon receipt of an
|
422
|
+
[[OPCODE_PONG]] frame.
|
423
|
+
|
424
|
+
- [[onclose(webtube)]] will be called upon closure of the
|
425
|
+
connection, for any reason.
|
426
|
+
|
427
|
+
- [[onannoyedclose(webtube, frame)]] will be called upon receipt
|
428
|
+
of an [[OPCODE_CLOSE]] frame with an explicit status code
|
429
|
+
other than 1000. This typically indicates that the other side
|
430
|
+
is annoyed, so the listener may want to log the condition for
|
431
|
+
debugging or further analysis. Normally, once the handler
|
432
|
+
returns, [[Webtube]] will respond with a close frame of the
|
433
|
+
same status code and close the connection, but the handler may
|
434
|
+
call [[Webtube#close]] to request a closure with a different
|
435
|
+
status code or without one.
|
436
|
+
|
437
|
+
- [[onexception(webtube, exception)]] will be called if an
|
438
|
+
unhandled [[Exception]] is raised during the [[Webtube]]'s
|
439
|
+
lifecycle, including all of the listener event handlers. The
|
440
|
+
handler may log the exception but should return normally so
|
441
|
+
that the [[Webtube]] can issue a proper close frame for the
|
442
|
+
other end and invoke the [[onclose]] handler, after which the
|
443
|
+
exception will be raised again so the caller of
|
444
|
+
[[Webtube#run]] will have a chance of handling the exception.
|
445
|
+
|
446
|
+
Before calling any of the handlers, [[respond_to?]] will be used
|
447
|
+
to check implementedness.
|
448
|
+
|
449
|
+
If an exception occurs during processing, it may implement a
|
450
|
+
specific status code to be passed to the other end via the
|
451
|
+
[[OPCODE_CLOSE]] frame by implementing the
|
452
|
+
[[websocket_close_status_code]] method returning the code as an
|
453
|
+
integer. The default code, used if the exception does not
|
454
|
+
specify one, is 1011 'unexpected condition'. An exception may
|
455
|
+
explicitly suppress sending any code by having
|
456
|
+
[[websocket_close_status_code]] return [[nil]] instead of an
|
457
|
+
integer.
|
458
|
+
|
459
|
+
Note that [[Webtube#run]] will not return until the connection
|
460
|
+
will have been closed. If the caller needs to get other work
|
461
|
+
done in the connection's lifetime, it will need to either handle
|
462
|
+
this work inside calls to the [[listener]] or set up separate
|
463
|
+
[[Thread]]s for the [[Webtube#run]] and for the other work.
|
464
|
+
|
465
|
+
[[Webtube#run]] will raise instances of
|
466
|
+
[[Webtube::ProtocolError]] if events that the WebSocket protocol
|
467
|
+
does not permit should happen. In the current version of
|
468
|
+
[[Webtube]], the specific known subclasses are:
|
469
|
+
|
470
|
+
- [[Webtube::BrokenFrame]] indicates that a complete frame could
|
471
|
+
not be read from the underlying TCP connection. The
|
472
|
+
[[partial_frame]] attribute holds as much data, as a
|
473
|
+
[[String]] of [[ASCII-8BIT]] encoding, as was available.
|
474
|
+
|
475
|
+
- [[Webtube::UnknownReservedBit]] indicates that a frame with an
|
476
|
+
RSV bit not specifically permitted by the [[allow_rsv_bits]]
|
477
|
+
parameter was received. The [[frame]] attribute holds the
|
478
|
+
frame as a [[Webtube::Frame]] instance.
|
479
|
+
|
480
|
+
- [[Webtube::UnknownOpcode]] indicates that a frame with an
|
481
|
+
opcode not specifically permitted by the [[allow_opcodes]]
|
482
|
+
parameter, or by the standard, was received. The [[frame]]
|
483
|
+
attribute holds the frame as a [[Webtube::Frame]] instance.
|
484
|
+
Note that if the opcode indicates a data message (as contrary
|
485
|
+
to a control frame), the [[frame]] will hold only its first
|
486
|
+
fragment, as WebSocket data messages are subject to
|
487
|
+
fragmentation and the message's opcode is stored in the first
|
488
|
+
fragment.
|
489
|
+
|
490
|
+
- [[Webtube::UnmaskedFrameToServer]] indicates that a
|
491
|
+
[[Webtube]] running in server mode received a frame without
|
492
|
+
masking. As per the WebSocket standard, [[Webtube]] considers
|
493
|
+
this a fatal protocol failure. The [[frame]] attribute holds
|
494
|
+
the frame as a [[Webtube::Frame]] instance.
|
495
|
+
|
496
|
+
- [[Webtube::MaskedFrameToClient]] indicates that a [[Webtube]]
|
497
|
+
running in client mode received a frame with masking. As per
|
498
|
+
the WebSocket standard, [[Webtube]] considers this a fatal
|
499
|
+
protocol failure. The [[frame]] attribute holds the frame as
|
500
|
+
a [[Webtube::Frame]] instance.
|
501
|
+
|
502
|
+
- [[Webtube::MissingContinuationFrame]] indicates receipt of a
|
503
|
+
new data message initial frame while the [[Webtube]] was
|
504
|
+
expecting a continuation frame of a fragmented data message.
|
505
|
+
Note that control frames are permitted to arrive interleaved
|
506
|
+
with fragments of a data message.
|
507
|
+
|
508
|
+
- [[Webtube::UnexpectedContinuationFrame]] indicates receipt of
|
509
|
+
a data message continuation frame while the [[Webtube]] was
|
510
|
+
not expecting one. The [[frame]] attribute holds the frame as
|
511
|
+
a [[Webtube::Frame]] instance.
|
512
|
+
|
513
|
+
- [[Webtube::BadlyEncodedText]] indicates receipt of a text
|
514
|
+
message ([[OPCODE_TEXT]]) whose content is not a valid UTF-8
|
515
|
+
string. As per the WebSocket standard, [[Webtube]] considers
|
516
|
+
this a fatal protocol failure. The [[data]] attribute holds
|
517
|
+
the payload as a [[String]] instance of the [[ASCII-8BIT]]
|
518
|
+
encoding.
|
519
|
+
|
520
|
+
- [[Webtube::FragmentedControlFrame]] indicates receipt of a
|
521
|
+
control frame whose [[FIN]] flag is not set.
|
522
|
+
|
523
|
+
Other exceptions representing TCP-level, HTTP-level, or
|
524
|
+
infrastructure failures can also occur.
|
525
|
+
|
526
|
+
|
527
|
+
==== [[Webtube#send_message]]: send a message or control frame
|
416
528
|
|
417
529
|
send_message(payload, opcode = Webtube::OPCODE_TEXT)
|
418
530
|
|
419
|
-
This method transmits the given [[payload]], a [[String]], over
|
420
|
-
connection to its other end using the given
|
421
|
-
[[
|
422
|
-
|
531
|
+
This method transmits the given [[payload]], a [[String]], over
|
532
|
+
this WebSocket connection to its other end using the given
|
533
|
+
[[opcode]]. If [[opcode]] is [[Webtube::OPCODE_TEXT]] and
|
534
|
+
[[payload]] is not encoded in [[UTF-8]], it will recode the
|
535
|
+
payload to [[UTF-8]] first, as required by the WebSocket
|
536
|
+
standard.
|
423
537
|
|
424
|
-
It is safe to call [[send_message]] from multiple threads
|
425
|
-
[[Webtube]] uses an internal lock to make
|
426
|
-
|
538
|
+
It is safe to call [[send_message]] from multiple threads
|
539
|
+
concurrently; each [[Webtube]] uses an internal lock to make
|
540
|
+
sure that two data messages, despite possible fragmentation,
|
541
|
+
will not be interleaved.
|
427
542
|
|
428
|
-
An exception will be raised if [[send_message]] is called after
|
429
|
-
[[Webtube]]. The exception's class and ancestry
|
430
|
-
except that it will derive, directly
|
431
|
-
|
543
|
+
An exception will be raised if [[send_message]] is called after
|
544
|
+
closure of the [[Webtube]]. The exception's class and ancestry
|
545
|
+
is currently not defined, except that it will derive, directly
|
546
|
+
or indirectly, from [[StandardError]]. It may derive from
|
547
|
+
[[RuntimeError]] but this is not guaranteed.
|
432
548
|
|
433
549
|
|
434
550
|
==== [[Webtube#close]]: close a WebSocket connection
|
435
551
|
|
436
552
|
close(status_code = 1000, explanation = "")
|
437
553
|
|
438
|
-
This method transmits an [[OPCODE_CLOSE]] control frame of the
|
439
|
-
[[status_code]] and [[explanation]], aborts a pending
|
440
|
-
any), and marks the [[Webtube]] dead,
|
441
|
-
|
442
|
-
the
|
554
|
+
This method transmits an [[OPCODE_CLOSE]] control frame of the
|
555
|
+
specified [[status_code]] and [[explanation]], aborts a pending
|
556
|
+
wait to receive frame (if any), and marks the [[Webtube]] dead,
|
557
|
+
thus blocking further transmissions. If the [[close_socket]]
|
558
|
+
parameter of the [[Webtube]] is set, it will also close the
|
559
|
+
underlying socket.
|
443
560
|
|
444
|
-
The [[status_code]] can be explicitly set to [[nil]], thus
|
445
|
-
transmitted close frame to not contain a payload
|
446
|
-
code nor the explanation). The
|
561
|
+
The [[status_code]] can be explicitly set to [[nil]], thus
|
562
|
+
causing the transmitted close frame to not contain a payload
|
563
|
+
(that is, neither the status code nor the explanation). The
|
564
|
+
default is 1000, indicating normal closure.
|
447
565
|
|
448
|
-
If [[explanation]] is not encoded in UTF-8, it will be recoded,
|
449
|
-
the WebSocket protocol specification.
|
566
|
+
If [[explanation]] is not encoded in UTF-8, it will be recoded,
|
567
|
+
as required by the WebSocket protocol specification.
|
450
568
|
|
451
|
-
Attempting to close a [[Webtube]] that has already been closed
|
452
|
-
exception as attempting to transmit via a closed
|
453
|
-
[[Webtube#send_message]].
|
569
|
+
Attempting to close a [[Webtube]] that has already been closed
|
570
|
+
will cause an exception as attempting to transmit via a closed
|
571
|
+
[[Webtube]]; see [[Webtube#send_message]].
|
454
572
|
|
455
573
|
|
456
574
|
=== The [[Webtube::Frame]] class
|
457
575
|
|
458
|
-
Instances of this class represent individual WebSocket frames.
|
459
|
-
exposed to user code via the [[oncontrolframe]],
|
460
|
-
events and some exceptions inheriting
|
576
|
+
Instances of this class represent individual WebSocket frames.
|
577
|
+
They are exposed to user code via the [[oncontrolframe]],
|
578
|
+
[[onping]], and [[onpong]] events and some exceptions inheriting
|
579
|
+
from [[ProtocolError]].
|
461
580
|
|
462
|
-
There is currently no convenient interface for user code to
|
463
|
-
[[Webtube::Frame]] instances by hand, but manipulating
|
464
|
-
function as expected. (Manipulating the
|
465
|
-
|
581
|
+
There is currently no convenient interface for user code to
|
582
|
+
build [[Webtube::Frame]] instances by hand, but manipulating
|
583
|
+
some header fields may function as expected. (Manipulating the
|
584
|
+
payload will usually not, due to this interfering with the
|
585
|
+
length- and masking-related header fields.)
|
466
586
|
|
467
587
|
The following methods are user-serviceable:
|
468
588
|
|
469
|
-
- [[Webtube::Frame#header]] returns the header as a [[String]]
|
470
|
-
[[ASCII-8BIT]].
|
589
|
+
- [[Webtube::Frame#header]] returns the header as a [[String]]
|
590
|
+
encoded in [[ASCII-8BIT]].
|
471
591
|
|
472
|
-
- [[Webtube::Frame#header=]] replaces the header. There is no
|
473
|
-
with caution.
|
592
|
+
- [[Webtube::Frame#header=]] replaces the header. There is no
|
593
|
+
validation; use with caution.
|
474
594
|
|
475
|
-
- [[Webtube::Frame#body]] returns the body as a [[String]]
|
476
|
-
[[ASCII-8BIT]].
|
595
|
+
- [[Webtube::Frame#body]] returns the body as a [[String]]
|
596
|
+
encoded in [[ASCII-8BIT]].
|
477
597
|
|
478
|
-
- [[Webtube::Frame#body=]] replaces the body. There is no
|
479
|
-
masking; use with extreme caution.
|
598
|
+
- [[Webtube::Frame#body=]] replaces the body. There is no
|
599
|
+
validation or masking; use with extreme caution.
|
480
600
|
|
481
|
-
- [[Webtube::Frame#fin?]] extracts and returns (as [[Boolean]])
|
482
|
-
flag of this frame.
|
601
|
+
- [[Webtube::Frame#fin?]] extracts and returns (as [[Boolean]])
|
602
|
+
the [[FIN]] flag of this frame.
|
483
603
|
|
484
|
-
- [[Webtube::Frame#fin=]] replaces the [[FIN]] flag of this
|
604
|
+
- [[Webtube::Frame#fin=]] replaces the [[FIN]] flag of this
|
605
|
+
frame.
|
485
606
|
|
486
|
-
- [[Webtube::Frame#rsv1]], [[Webtube::Frame#rsv2]], and
|
487
|
-
extract the RSV1, RSV2, and RSV3 flags
|
488
|
-
instances, correspondingly.
|
607
|
+
- [[Webtube::Frame#rsv1]], [[Webtube::Frame#rsv2]], and
|
608
|
+
[[Webtube::Frame#rsv3]] extract the RSV1, RSV2, and RSV3 flags
|
609
|
+
of this frame, as [[Boolean]] instances, correspondingly.
|
489
610
|
|
490
|
-
- [[Webtube::Frame#rsv]] extracts the RSV1, RSV2, and RSV3
|
491
|
-
integer in the range of [[0 .. 7]].
|
611
|
+
- [[Webtube::Frame#rsv]] extracts the RSV1, RSV2, and RSV3
|
612
|
+
bitfield as an integer in the range of [[0 .. 7]].
|
492
613
|
|
493
|
-
- [[Webtube::Frame#opcode]] extracts the opcode of this frame as
|
494
|
-
the range of [[0 .. 15]].
|
614
|
+
- [[Webtube::Frame#opcode]] extracts the opcode of this frame as
|
615
|
+
an integer in the range of [[0 .. 15]].
|
495
616
|
|
496
617
|
- [[Webtube::Frame#opcode=]] replaces the opcode.
|
497
618
|
|
498
|
-
- [[Webtube::Frame#control_frame?]] checks whether this frame is
|
499
|
-
control frame, defined as having an opcode of 8
|
619
|
+
- [[Webtube::Frame#control_frame?]] checks whether this frame is
|
620
|
+
considered a control frame, defined as having an opcode of 8
|
621
|
+
or greater.
|
500
622
|
|
501
|
-
- [[Webtube::Frame#masked?]] extracts the [[MSK]] flag of this
|
623
|
+
- [[Webtube::Frame#masked?]] extracts the [[MSK]] flag of this
|
624
|
+
frame.
|
502
625
|
|
503
|
-
- [[Webtube::Frame#payload_length]] extracts the payload length,
|
504
|
-
of the three ways defined by the protocol
|
505
|
-
the frame's header.
|
626
|
+
- [[Webtube::Frame#payload_length]] extracts the payload length,
|
627
|
+
in whichever of the three ways defined by the protocol
|
628
|
+
specification it is encoded, from the frame's header.
|
506
629
|
|
507
|
-
- [[Webtube::Frame#mask]] extracts the mask of this frame, as
|
508
|
-
|
509
|
-
|
630
|
+
- [[Webtube::Frame#mask]] extracts the mask of this frame, as an
|
631
|
+
integer, if the [[MSK]] flag is set. If it is not set, this
|
632
|
+
method returns [[nil]].
|
510
633
|
|
511
|
-
- [[Webtube::Frame#payload]] retrieves the payload of this
|
512
|
-
frame's body if necessary.
|
634
|
+
- [[Webtube::Frame#payload]] retrieves the payload of this
|
635
|
+
frame, demasking the frame's body if necessary.
|
513
636
|
|
514
|
-
- [[Webtube::Frame::read_from_socket(socket)]] reads all the
|
515
|
-
WebSocket frame from the given [[IO]] instance
|
516
|
-
the plain [[ASCII-8BIT]] encoding,
|
517
|
-
and
|
518
|
-
[[Webtube::
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
637
|
+
- [[Webtube::Frame::read_from_socket(socket)]] reads all the
|
638
|
+
bytes of one WebSocket frame from the given [[IO]] instance
|
639
|
+
(which must provide data in the plain [[ASCII-8BIT]] encoding,
|
640
|
+
and emphatically not a multibyte encoding) and returns a
|
641
|
+
[[Webtube::Frame]] instance representing the frame, or raises
|
642
|
+
[[Webtube::BrokenFrame]] if the inbound traffic ends before
|
643
|
+
the whole frame will have been read. Note that this will
|
644
|
+
involve calling [[IO#read]] twice or thrice, and is therefore
|
645
|
+
unsafe to be called in multithreaded code unless external
|
646
|
+
locking or synchronisation measures are used. (This method is
|
647
|
+
mainly intended for internal use by [[Webtube#run]], but it
|
648
|
+
may be of use in other contexts, such as parsing stored
|
649
|
+
sequences of WebSocket frames.)
|
524
650
|
|
525
651
|
|
526
652
|
=== WEBrick integration
|
527
653
|
|
528
654
|
These classes and methods are defined in the separately loadable
|
529
|
-
[['webtube/webrick']]. Note that this file will, in addition to
|
530
|
-
classes and methods, replace the [[initialize]] and
|
531
|
-
[[
|
532
|
-
|
533
|
-
shutdown.
|
655
|
+
[['webtube/webrick']]. Note that this file will, in addition to
|
656
|
+
defining new classes and methods, replace the [[initialize]] and
|
657
|
+
[[shutdown]] methods of the [[WEBrick::HTTPServer]] class to
|
658
|
+
make sure all the [[Webtube]] instances associated with this
|
659
|
+
server will be properly shut down upon the server's shutdown.
|
534
660
|
|
535
661
|
|
536
662
|
==== [[WEBrick::HTTPRequest#websocket_upgrade_request?]]
|
537
663
|
|
538
|
-
This method checks whether this HTTP request is a valid request
|
539
|
-
WebSocket connection.
|
664
|
+
This method checks whether this HTTP request is a valid request
|
665
|
+
to establish a WebSocket connection.
|
540
666
|
|
541
667
|
|
542
668
|
==== [[WEBrick::HTTPServer#webtubes]]
|
543
669
|
|
544
|
-
Retrieve the [[Webtube::Vital_Statistics]] instance for this
|
670
|
+
Retrieve the [[Webtube::Vital_Statistics]] instance for this
|
671
|
+
server.
|
545
672
|
|
546
673
|
==== [[WEBrick::HTTPServer#accept_webtube]]
|
547
674
|
|
@@ -550,230 +677,258 @@ Retrieve the [[Webtube::Vital_Statistics]] instance for this server.
|
|
550
677
|
context: nil)
|
551
678
|
|
552
679
|
Given a [[request]] and a [[response]] object, as prepared by a
|
553
|
-
[[WEBrick::HTTPServer]] for processing in a portlet, this method
|
554
|
-
accept the client's request to establish a WebSocket
|
555
|
-
[[request]] must actually contain such a
|
556
|
-
[[websocket_upgrade_request?]].
|
557
|
-
|
558
|
-
The attempt will fail in the theoretical case the client and the
|
559
|
-
agree on the protocol version to use. In such a
|
560
|
-
prepare a 426 'Upgrade required'
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
will be
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
680
|
+
[[WEBrick::HTTPServer]] for processing in a portlet, this method
|
681
|
+
attempts to accept the client's request to establish a WebSocket
|
682
|
+
connection. The [[request]] must actually contain such a
|
683
|
+
request; see [[websocket_upgrade_request?]].
|
684
|
+
|
685
|
+
The attempt will fail in the theoretical case the client and the
|
686
|
+
server can't agree on the protocol version to use. In such a
|
687
|
+
case, [[accept_webtube]] will prepare a 426 'Upgrade required'
|
688
|
+
response, explaining in plain text what the problem is and
|
689
|
+
advertising, using the [[Sec-WebSocket-Version]] header field,
|
690
|
+
the protocol version (specifically, 13) it is prepared to speak.
|
691
|
+
When this happens, the WebSocket session will never be set up
|
692
|
+
and no [[listener]] events will be called.
|
693
|
+
|
694
|
+
Note that [[accept_webtube]] will manipulate [[response]] and
|
695
|
+
return immediately. The actual WebSocket session will begin
|
696
|
+
once WEBrick attempts to deliver the [[response]], and this will
|
697
|
+
be signalled by the newly constructed [[Webtube]] instance
|
698
|
+
delivering an [[onopen]] event to [[listener]].
|
699
|
+
|
700
|
+
Also note that the loop to process incoming WebSocket frames
|
701
|
+
will hog the whole thread; in order to deliver asynchronous
|
702
|
+
messages over the WebSocket, [[Webtube#send_message]] needs to
|
703
|
+
be called from another thread. (For synchronous messages, it
|
704
|
+
can safely be called from the handlers inside [[listener]].)
|
576
705
|
|
577
706
|
See [[Webtube#run]] for a list of the supported methods for the
|
578
707
|
[[listener]].
|
579
708
|
|
580
|
-
The [[session]] and [[context]] parameters, if given, will be
|
581
|
-
[[Webtube]] instance as attributes. The
|
582
|
-
|
583
|
-
|
584
|
-
|
709
|
+
The [[session]] and [[context]] parameters, if given, will be
|
710
|
+
stored in the [[Webtube]] instance as attributes. The
|
711
|
+
[[Webtube]] itself will not care about them, but this mechanism
|
712
|
+
may be of use for the user code. [[accept_webtube]] stores the
|
713
|
+
[[request]] in the [[Webtube]] instance's [[header]] attribute;
|
714
|
+
for this reason, it does not accept [[header]] as a parameter.
|
585
715
|
|
586
716
|
==== [[WEBrick::HTTPServer#mount_webtube]]
|
587
717
|
|
588
718
|
mount_webtube(dir, listener)
|
589
719
|
|
590
|
-
This method mounts at the specified virtual directory a WEBrick
|
591
|
-
implementing a WebSocket-only service, using the given
|
592
|
-
backend. (Note that there is only one
|
593
|
-
|
594
|
-
first
|
720
|
+
This method mounts at the specified virtual directory a WEBrick
|
721
|
+
portlet implementing a WebSocket-only service, using the given
|
722
|
+
[[listener]] as its backend. (Note that there is only one
|
723
|
+
listener for the whole service but each event passed to the
|
724
|
+
listener will have a specific [[Webtube]] instance as its first
|
725
|
+
parameter.)
|
595
726
|
|
596
727
|
The portlet itself is implemented by the class
|
597
|
-
[[WEBrick::HTTPServlet::WebtubeHandler]]. The implementation
|
598
|
-
deliberately left undocumented in the current
|
599
|
-
may change radically in the
|
600
|
-
opaque.
|
728
|
+
[[WEBrick::HTTPServlet::WebtubeHandler]]. The implementation
|
729
|
+
details are deliberately left undocumented in the current
|
730
|
+
version of [[Webtube]], and they may change radically in the
|
731
|
+
future. For now, the class should be considered opaque.
|
601
732
|
|
602
733
|
|
603
734
|
== Limitations and possible future work
|
604
735
|
|
605
|
-
- The WebSocket specification permits interleaving control
|
606
|
-
fragments of a data message. The current
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
reserved bits
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
736
|
+
- The WebSocket specification permits interleaving control
|
737
|
+
frames with fragments of a data message. The current
|
738
|
+
[[Webtube]] implementation engages an internal lock
|
739
|
+
serialising all calls of [[send_message]]. A future version
|
740
|
+
may ignore this lock if [[send_message]] is called to transmit
|
741
|
+
a control frame that fits into the [[PIPE_BUF]] limit and is
|
742
|
+
thus not subject to the risk of the OS kernel's [[write()]]
|
743
|
+
syscall handling it partially and causing a WebSocket frame
|
744
|
+
structure breakage.
|
745
|
+
|
746
|
+
- Such ignoring may, in a future version, be configurable on a
|
747
|
+
per-opcode basis.
|
748
|
+
|
749
|
+
- The WebSocket specification provides for handling the content
|
750
|
+
of fragmented data messages even before the reception of the
|
751
|
+
final frame. The current [[Webtube]] implementation sponges
|
752
|
+
up all the fragments before triggering [[onmessage]].
|
753
|
+
|
754
|
+
- Some approaches worth considering involve delivering
|
755
|
+
fragments of data messages to the listener as they arrive or
|
756
|
+
extracting parts -- such as text lines, sequences of
|
757
|
+
complete UTF-8 code points, or fixed-length data blocks --
|
758
|
+
from the fragment sponge as soon as they can be wholly
|
759
|
+
extracted.
|
760
|
+
|
761
|
+
- The WebSocket specification provides for extensions defining
|
762
|
+
semantics for the reserved bits of both data and control
|
763
|
+
frames, and for extra header fields between the WebSocket
|
764
|
+
header and the ultimate payload. [[Webtube]] only provides
|
765
|
+
for handling reserved bits of incoming control frames but not
|
766
|
+
data frames, and does not provide for a convenient way to
|
767
|
+
transmit frames with reserved bits or extra header fields set.
|
768
|
+
|
769
|
+
- In particular, work is currently underway to define a
|
770
|
+
WebSocket protocol extension for transparent compression of
|
771
|
+
frames and/or messages. At this time, there are multiple
|
772
|
+
competing proposals, and IETF has not released a final
|
773
|
+
specification, but a future version of [[Webtube]] may
|
774
|
+
implement one or more such extension. The most promising
|
775
|
+
one, at this time, seems [[permessage-deflate]].
|
776
|
+
|
777
|
+
- The WebSocket specification provides for explicit negotiation
|
778
|
+
of a subprotocol between the client and the server. While
|
779
|
+
[[Webtube]] exposes the relevant HTTP header field
|
780
|
+
([[Sec-WebSocket-Protocol]]) to client-side user code, it does
|
781
|
+
not provide any sort of direct support, and explicitly
|
782
|
+
supporting subprotocols on the server side may be cumbersome.
|
783
|
+
A future version of [[Webtube]] may provide a declarative way
|
784
|
+
for configuring the subprotocol negotiation: more explicitly
|
785
|
+
expose the subprotocol field on the client-side API, and
|
786
|
+
providing parameters for declaring the supported subprotocols
|
787
|
+
and their order of precedence, or alternatively a hook to a
|
788
|
+
more complex subprotocol choie mechanism, on the server-side
|
789
|
+
API.
|
790
|
+
|
791
|
+
- On the server side, [[Webtube]] currently only actively
|
792
|
+
integrates with WEBrick. A future version may also provide
|
793
|
+
support for integration with Thin, Puma, Sinatra, and/or
|
794
|
+
EventMachine.
|
795
|
+
|
796
|
+
- A future version of [[Webtube]] may provide an interface for
|
797
|
+
explicitly specifying the fragmentation strategy for outbound
|
798
|
+
data messages instead of relying on a one-size-fits-all
|
799
|
+
[[PIPE_BUF]] based approach.
|
800
|
+
|
801
|
+
- In particular, on systems exposing the results of Path MTU
|
802
|
+
Discovery of connected TCP sockets to userspace code, a
|
803
|
+
future version of [[Webtube]] may use these results to
|
804
|
+
choose a message fragment size according to the path's MTU.
|
805
|
+
(This will become nontrivial once compression and SSL get
|
663
806
|
involved.)
|
664
807
|
|
665
|
-
- Currently, [[Webtube#run]] necessarily hogs its whole thread
|
666
|
-
connection closes. A future version may, as an
|
667
|
-
incremental approach. Some of the
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
- A future version of [[Webtube]] may
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
808
|
+
- Currently, [[Webtube#run]] necessarily hogs its whole thread
|
809
|
+
until the connection closes. A future version may, as an
|
810
|
+
alternative, provide a more incremental approach. Some of the
|
811
|
+
partially overlapping and partially alternative approaches
|
812
|
+
worth considering include:
|
813
|
+
|
814
|
+
- a [[receive_message]] method that would hang until a message
|
815
|
+
arrives (buth how would it interact with control frames?
|
816
|
+
Particularly, control frames not defined by the standard?);
|
817
|
+
|
818
|
+
- an option for [[run]] to leave the loop after processing one
|
819
|
+
incoming frame or message;
|
820
|
+
|
821
|
+
- an option for [[run]] to leave the loop after passage of a
|
822
|
+
given timeout;
|
823
|
+
|
824
|
+
- a non-blocking [[has_data?]] method that would check whether
|
825
|
+
the underlying [[Socket]] has at last one byte of data
|
826
|
+
available;
|
827
|
+
|
828
|
+
- a non-blocking [[has_frame?]] method that would check
|
829
|
+
whether the underlying [[Socket]] has at least on complete
|
830
|
+
WebSocket frame available (if not, this would require
|
831
|
+
storing the partial frame in a slot of [[Webtube]] instead
|
832
|
+
of a local variable of [[run]]).
|
833
|
+
|
834
|
+
- The HTTP specification provides a mechanism for redirecting
|
835
|
+
clients. It is not entirely clear how this should affect
|
836
|
+
WebSocket clients, although there are some obvious approaches.
|
837
|
+
A future version of [[Webtube::connect]] may implement one or
|
838
|
+
more of them.
|
839
|
+
|
840
|
+
- A future version of the client API for [[Webtube]] may support
|
841
|
+
transparent automatic reconnection upon loss of connection
|
842
|
+
while retaining the same instance, subject to restrictions for
|
843
|
+
thrashing and persisting failure. This may need lead to
|
844
|
+
defining new events for the listener.
|
845
|
+
|
846
|
+
- A future version of [[Webtube]] may provide for a higher-level
|
847
|
+
interface, for example, by transparently JSON-encoding and
|
848
|
+
-decoding objects as they are transmitted and received.
|
849
|
+
|
850
|
+
- A future version of [[Webtube]] may implement a 'queue of
|
851
|
+
unhandled messages' inside the [[Webtube]] instance (or more
|
852
|
+
likely, inside an instance of its subclass), define a
|
853
|
+
mechanism (or several) for matching outbound and inbound
|
854
|
+
messages, and provide for a synchronous method that would
|
855
|
+
transmit a message and wait until receipt of a matching
|
856
|
+
response, storing messages arriving in the intervening time
|
857
|
+
for use by a future call of this method, or by concurrent
|
858
|
+
calls of this method from other threads.
|
859
|
+
|
860
|
+
- A future version of [[Webtube]] may define a hook for the
|
861
|
+
caller to manually check the SSL certificate so as to
|
862
|
+
facilitate secure SSL/TLS connections using self-signed
|
863
|
+
certificates validated using a custom procedure instead of
|
712
864
|
relying to a 'trusted third party' CA.
|
713
865
|
|
714
|
-
- Also, or alternatively, it may expose [[OpenSSL]]'s
|
715
|
-
verification hooks.
|
716
|
-
|
717
|
-
- A future version of [[Webtube::connect]] may explicitly support using a
|
718
|
-
client SSL certificate.
|
866
|
+
- Also, or alternatively, it may expose [[OpenSSL]]'s
|
867
|
+
certificate verification hooks.
|
719
868
|
|
720
|
-
- A future version of [[Webtube::connect]] may
|
721
|
-
|
869
|
+
- A future version of [[Webtube::connect]] may explicitly
|
870
|
+
support using a client SSL certificate.
|
722
871
|
|
723
|
-
-
|
724
|
-
|
725
|
-
[[Exception]], to report attempt to transmit data through a dead WebSocket.
|
726
|
-
A future version of [[Webtube]] is likely to provide such an explicit
|
727
|
-
subclass of defined ancestry. It is not currently clear whether this should
|
728
|
-
inherit from [[Webtube::ProtocolError]]; arguments both ways are conceivable.
|
872
|
+
- A future version of [[Webtube::connect]] may provide support
|
873
|
+
for web proxies.
|
729
874
|
|
730
|
-
-
|
731
|
-
|
875
|
+
- The current implementation of [[Webtube#send_message]] uses a
|
876
|
+
string (and thus, implicitly, [[RuntimeError]]), rather than
|
877
|
+
an explicit subclass of [[Exception]], to report attempt to
|
878
|
+
transmit data through a dead WebSocket. A future version of
|
879
|
+
[[Webtube]] is likely to provide such an explicit subclass of
|
880
|
+
defined ancestry. It is not currently clear whether this
|
881
|
+
should inherit from [[Webtube::ProtocolError]]; arguments both
|
882
|
+
ways are conceivable.
|
732
883
|
|
733
|
-
- A future version of [[Webtube]] may
|
734
|
-
|
884
|
+
- A future version of [[Webtube]] may offer a better
|
885
|
+
differentiation between reasons of a WebSocket's closure.
|
735
886
|
|
736
|
-
- A future version of [[Webtube]] may define
|
737
|
-
|
887
|
+
- A future version of [[Webtube]] may perhaps define listener
|
888
|
+
event(s) for outbound messages as well as inbound ones.
|
738
889
|
|
739
|
-
-
|
740
|
-
|
741
|
-
in the /connecting/ state. [[Webtube]] is currently not implementing or
|
742
|
-
enforcing this. A future version may provide a serialisation mechanism.
|
890
|
+
- A future version of [[Webtube]] may define parameters for
|
891
|
+
setting the [[IP_TOS]] and [[IP_TTL]] socket options.
|
743
892
|
|
744
|
-
-
|
745
|
-
|
893
|
+
- The WebSocket protocol specification has a strict rule against
|
894
|
+
multiple WebSocket connections between the same pair of
|
895
|
+
endpoints being simultaneously in the /connecting/ state.
|
896
|
+
[[Webtube]] is currently not implementing or enforcing this.
|
897
|
+
A future version may provide a serialisation mechanism.
|
746
898
|
|
747
|
-
|
899
|
+
- A future version of [[Webtube]] may provide an explicit
|
900
|
+
mechanism for transmitting hand-crafted [[Frame]] instances.
|
748
901
|
|
749
|
-
-
|
750
|
-
|
751
|
-
|
752
|
-
- This will need a mechanism for [[Webtube]] to validate the [[Origin]]
|
753
|
-
header field in the request. This is currently not implemented (but may be
|
754
|
-
implemented in a future version.)
|
902
|
+
- This will probably need a better abstraction for frame
|
903
|
+
masking.
|
755
904
|
|
756
905
|
|
757
906
|
== Copyright and licensing
|
758
907
|
|
759
|
-
Webtube is copyright (c) 2014 by Andres Soolo and Knitten
|
760
|
-
Webtube is published as free software under the
|
761
|
-
GNU General Public License version
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
908
|
+
Webtube is copyright (c) 2014-2018 by Andres Soolo and Knitten
|
909
|
+
Development OÜ. Webtube is published as free software under the
|
910
|
+
terms and conditions of the GNU General Public License version
|
911
|
+
3.
|
912
|
+
|
913
|
+
It is the default policy of us at Knitten Development to release
|
914
|
+
our free software under the GPL v3, which we believe provides a
|
915
|
+
reasonable and well-considered, if somewhat conservative,
|
916
|
+
balance between the interests and concerns of producers,
|
917
|
+
consumers, and prosumers of free software. However, we realise
|
918
|
+
that some users of our free software may be better served by
|
919
|
+
other balances. For this reason, Knitten Development would like
|
920
|
+
it be known that:
|
921
|
+
|
922
|
+
- we are willing to consider, on a case-by-case basis, offering
|
923
|
+
packages of our free software optionally also under certain
|
924
|
+
other open source software licenses, as certified by the Open
|
925
|
+
Source Initiative(tm), provided that this furthers the
|
926
|
+
creation or advancement of specific free software projects
|
927
|
+
that Knitten Development may find worthwile, at our
|
928
|
+
discretion; and
|
929
|
+
|
930
|
+
- we are available to negotiate standard non-exclusive
|
931
|
+
commercial licenses for free software that we have released,
|
932
|
+
in exchange for a reasonable fee.
|
933
|
+
|
934
|
+
For any enquiries, please write to <dig@mirky.net>.
|