webtube 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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>.
|