websocket-driver 0.7.0-java → 0.7.1-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56ae9057b4d473ec55363da2309322999d71f5be9e457d4d94cc6b40c0bbaac5
4
- data.tar.gz: 2cb85005552be8596408bba185073e008734dc0b0240fe7382690212a5818eb6
3
+ metadata.gz: bed08ef47579269780c5c93cae6f3c181297a000c20725b2bb17ccfe6d7c9a92
4
+ data.tar.gz: 54b3292f8e301ab2d8489e144d457dd490e607741607927d23e318c1b53286c7
5
5
  SHA512:
6
- metadata.gz: 90ffb3c5ae767a18488af3c42ce24656a8ac1bf799cb7ed37f6dda09b27f438c25f8db01d8507793007d8940354c9800b2363c4dabf1636136f515af50e6b574
7
- data.tar.gz: 7842519e1eb00bdff05c1dcc5d6b916430c82d9becf54ac21eec4bee482c234642472ee3b624d4d4c59ee48c0d7c930e108a32f33ba281a4a81bab515cd474ed
6
+ metadata.gz: 8b01940d4d8d6d667da9daa0d54e9250cdf4f9d1a78273ab6a58a71b46d8880b19628069d0e54ad9d9daff1590268f8cb7c3b4e55873bce955ed7278d805be61
7
+ data.tar.gz: 886d18cb114222c6a89a6782564624fb1780a3e32b243eb2b560224d1635522f00a6b7515e45b0bb52425b281a3e29ec94379d1be75e198d2c9d03cf9e4e41ce
data/CHANGELOG.md CHANGED
@@ -1,127 +1,136 @@
1
+ ### 0.7.1 / 2019-06-10
2
+
3
+ - Catch any exceptions produced while generating a handshake response and send a
4
+ `400 Bad Request` response to the client
5
+ - Pick the RFC-6455 protocol version if the request contains any of the headers
6
+ used by that version
7
+ - Handle errors encountered while handling malformed draft-76 requests
8
+
1
9
  ### 0.7.0 / 2017-09-11
2
10
 
3
- * Add `ping` and `pong` to the set of events users can listen to
11
+ - Add `ping` and `pong` to the set of events users can listen to
4
12
 
5
13
  ### 0.6.5 / 2017-01-22
6
14
 
7
- * Provide a pure-Ruby fallback for the native unmasking code
15
+ - Provide a pure-Ruby fallback for the native unmasking code
8
16
 
9
17
  ### 0.6.4 / 2016-05-20
10
18
 
11
- * Amend warnings issued when running with -W2
12
- * Make sure message strings passed in by the app are transcoded to UTF-8
13
- * Copy strings if necessary for frozen-string compatibility
19
+ - Amend warnings issued when running with -W2
20
+ - Make sure message strings passed in by the app are transcoded to UTF-8
21
+ - Copy strings if necessary for frozen-string compatibility
14
22
 
15
23
  ### 0.6.3 / 2015-11-06
16
24
 
17
- * Reject draft-76 handshakes if their Sec-WebSocket-Key headers are invalid
18
- * Throw a more helpful error if a client is created with an invalid URL
25
+ - Reject draft-76 handshakes if their Sec-WebSocket-Key headers are invalid
26
+ - Throw a more helpful error if a client is created with an invalid URL
19
27
 
20
28
  ### 0.6.2 / 2015-07-18
21
29
 
22
- * When the peer sends a close frame with no error code, emit 1000
30
+ - When the peer sends a close frame with no error code, emit 1000
23
31
 
24
32
  ### 0.6.1 / 2015-07-13
25
33
 
26
- * Fix how events are stored in `EventEmitter` to fix a backward-compatibility
34
+ - Fix how events are stored in `EventEmitter` to fix a backward-compatibility
27
35
  violation introduced in the last release
28
- * Use the `Array#pack` and `String#unpack` methods for reading/writing numbers
36
+ - Use the `Array#pack` and `String#unpack` methods for reading/writing numbers
29
37
  to buffers rather than including duplicate logic for this
30
38
 
31
39
  ### 0.6.0 / 2015-07-08
32
40
 
33
- * Use `SecureRandom` to generate the `Sec-WebSocket-Key` header
34
- * Allow the parser to recover cleanly if event listeners raise an error
35
- * Let the `on()` method take a lambda as a positional argument rather than a block
36
- * Add a `pong` method for sending unsolicited pong frames
41
+ - Use `SecureRandom` to generate the `Sec-WebSocket-Key` header
42
+ - Allow the parser to recover cleanly if event listeners raise an error
43
+ - Let the `on()` method take a lambda as a positional argument rather than a
44
+ block
45
+ - Add a `pong` method for sending unsolicited pong frames
37
46
 
38
47
  ### 0.5.4 / 2015-03-29
39
48
 
40
- * Don't emit extra close frames if we receive a close frame after we already
49
+ - Don't emit extra close frames if we receive a close frame after we already
41
50
  sent one
42
- * Fail the connection when the driver receives an invalid
51
+ - Fail the connection when the driver receives an invalid
43
52
  `Sec-WebSocket-Extensions` header
44
53
 
45
54
  ### 0.5.3 / 2015-02-22
46
55
 
47
- * Don't treat incoming data as WebSocket frames if a client driver is closed
56
+ - Don't treat incoming data as WebSocket frames if a client driver is closed
48
57
  before receiving the server handshake
49
58
 
50
59
  ### 0.5.2 / 2015-02-19
51
60
 
52
- * Don't emit multiple `error` events
61
+ - Don't emit multiple `error` events
53
62
 
54
63
  ### 0.5.1 / 2014-12-18
55
64
 
56
- * Don't allow drivers to be created with unrecognized options
65
+ - Don't allow drivers to be created with unrecognized options
57
66
 
58
67
  ### 0.5.0 / 2014-12-13
59
68
 
60
- * Support protocol extensions via the websocket-extensions module
69
+ - Support protocol extensions via the websocket-extensions module
61
70
 
62
71
  ### 0.4.0 / 2014-11-08
63
72
 
64
- * Support connection via HTTP proxies using `CONNECT`
73
+ - Support connection via HTTP proxies using `CONNECT`
65
74
 
66
75
  ### 0.3.5 / 2014-10-04
67
76
 
68
- * Fix bug where the `Server` driver doesn't pass `ping` callbacks to its
77
+ - Fix bug where the `Server` driver doesn't pass `ping` callbacks to its
69
78
  delegate
70
- * Fix an arity error when calling `fail_request`
71
- * Allow `close` to be called before `start` to close the driver
79
+ - Fix an arity error when calling `fail_request`
80
+ - Allow `close` to be called before `start` to close the driver
72
81
 
73
82
  ### 0.3.4 / 2014-07-06
74
83
 
75
- * Don't hold references to frame buffers after a message has been emitted
76
- * Make sure that `protocol` and `version` are exposed properly by the TCP driver
77
- * Correct HTTP header parsing based on RFC 7230; header names cannot contain
84
+ - Don't hold references to frame buffers after a message has been emitted
85
+ - Make sure that `protocol` and `version` are exposed properly by the TCP driver
86
+ - Correct HTTP header parsing based on RFC 7230; header names cannot contain
78
87
  backslashes
79
88
 
80
89
  ### 0.3.3 / 2014-04-24
81
90
 
82
- * Fix problems with loading C and Java native extension code
83
- * Correct the acceptable characters used in the HTTP parser
84
- * Correct the draft-76 status line reason phrase
91
+ - Fix problems with loading C and Java native extension code
92
+ - Correct the acceptable characters used in the HTTP parser
93
+ - Correct the draft-76 status line reason phrase
85
94
 
86
95
  ### 0.3.2 / 2013-12-29
87
96
 
88
- * Expand `max_length` to cover sequences of continuation frames and
97
+ - Expand `max_length` to cover sequences of continuation frames and
89
98
  `draft-{75,76}`
90
- * Decrease default maximum frame buffer size to 64MB
91
- * Stop parsing when the protocol enters a failure mode, to save CPU cycles
99
+ - Decrease default maximum frame buffer size to 64MB
100
+ - Stop parsing when the protocol enters a failure mode, to save CPU cycles
92
101
 
93
102
  ### 0.3.1 / 2013-12-03
94
103
 
95
- * Add a `max_length` option to limit allowed frame size
104
+ - Add a `max_length` option to limit allowed frame size
96
105
 
97
106
  ### 0.3.0 / 2013-09-09
98
107
 
99
- * Support client URLs with Basic Auth credentials
108
+ - Support client URLs with Basic Auth credentials
100
109
 
101
110
  ### 0.2.3 / 2013-08-04
102
111
 
103
- * Fix bug in EventEmitter#emit when listeners are removed
112
+ - Fix bug in EventEmitter#emit when listeners are removed
104
113
 
105
114
  ### 0.2.2 / 2013-08-04
106
115
 
107
- * Fix bug in EventEmitter#listener_count for unregistered events
116
+ - Fix bug in EventEmitter#listener_count for unregistered events
108
117
 
109
118
  ### 0.2.1 / 2013-07-05
110
119
 
111
- * Queue sent messages if the client has not begun trying to connect
112
- * Encode all strings sent to I/O as `ASCII-8BIT`
120
+ - Queue sent messages if the client has not begun trying to connect
121
+ - Encode all strings sent to I/O as `ASCII-8BIT`
113
122
 
114
123
  ### 0.2.0 / 2013-05-12
115
124
 
116
- * Add API for setting and reading headers
117
- * Add Driver.server() method for getting a driver for TCP servers
125
+ - Add API for setting and reading headers
126
+ - Add Driver.server() method for getting a driver for TCP servers
118
127
 
119
128
  ### 0.1.0 / 2013-05-04
120
129
 
121
- * First stable release
130
+ - First stable release
122
131
 
123
132
  ### 0.0.0 / 2013-04-22
124
133
 
125
- * First release
126
- * Proof of concept for people to try out
127
- * Might be unstable
134
+ - First release
135
+ - Proof of concept for people to try out
136
+ - Might be unstable
data/LICENSE.md CHANGED
@@ -1,20 +1,12 @@
1
- # The MIT License
1
+ Copyright 2010-2019 James Coglan
2
2
 
3
- Copyright (c) 2010-2017 James Coglan
3
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4
+ this file except in compliance with the License. You may obtain a copy of the
5
+ License at
4
6
 
5
- Permission is hereby granted, free of charge, to any person obtaining a copy of
6
- this software and associated documentation files (the 'Software'), to deal in
7
- the Software without restriction, including without limitation the rights to
8
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
- the Software, and to permit persons to whom the Software is furnished to do so,
10
- subject to the following conditions:
7
+ http://www.apache.org/licenses/LICENSE-2.0
11
8
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ Unless required by applicable law or agreed to in writing, software distributed
10
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
12
+ specific language governing permissions and limitations under the License.
data/README.md CHANGED
@@ -10,21 +10,21 @@ pluggable I/O.
10
10
  Due to this design, you get a lot of things for free. In particular, if you hook
11
11
  this module up to some I/O object, it will do all of this for you:
12
12
 
13
- * Select the correct server-side driver to talk to the client
14
- * Generate and send both server- and client-side handshakes
15
- * Recognize when the handshake phase completes and the WS protocol begins
16
- * Negotiate subprotocol selection based on `Sec-WebSocket-Protocol`
17
- * Negotiate and use extensions via the
13
+ - Select the correct server-side driver to talk to the client
14
+ - Generate and send both server- and client-side handshakes
15
+ - Recognize when the handshake phase completes and the WS protocol begins
16
+ - Negotiate subprotocol selection based on `Sec-WebSocket-Protocol`
17
+ - Negotiate and use extensions via the
18
18
  [websocket-extensions](https://github.com/faye/websocket-extensions-ruby)
19
19
  module
20
- * Buffer sent messages until the handshake process is finished
21
- * Deal with proxies that defer delivery of the draft-76 handshake body
22
- * Notify you when the socket is open and closed and when messages arrive
23
- * Recombine fragmented messages
24
- * Dispatch text, binary, ping, pong and close frames
25
- * Manage the socket-closing handshake process
26
- * Automatically reply to ping frames with a matching pong
27
- * Apply masking to messages sent by the client
20
+ - Buffer sent messages until the handshake process is finished
21
+ - Deal with proxies that defer delivery of the draft-76 handshake body
22
+ - Notify you when the socket is open and closed and when messages arrive
23
+ - Recombine fragmented messages
24
+ - Dispatch text, binary, ping, pong and close frames
25
+ - Manage the socket-closing handshake process
26
+ - Automatically reply to ping frames with a matching pong
27
+ - Apply masking to messages sent by the client
28
28
 
29
29
  This library was originally extracted from the [Faye](http://faye.jcoglan.com)
30
30
  project but now aims to provide simple WebSocket support for any Ruby server or
@@ -43,12 +43,12 @@ $ gem install websocket-driver
43
43
  To build either a server-side or client-side socket, the only requirement is
44
44
  that you supply a `socket` object with these methods:
45
45
 
46
- * `socket.url` - returns the full URL of the socket as a string.
47
- * `socket.write(string)` - writes the given string to a TCP stream.
46
+ - `socket.url` - returns the full URL of the socket as a string.
47
+ - `socket.write(string)` - writes the given string to a TCP stream.
48
48
 
49
49
  Server-side sockets require one additional method:
50
50
 
51
- * `socket.env` - returns a Rack-style env hash that will contain some of the
51
+ - `socket.env` - returns a Rack-style env hash that will contain some of the
52
52
  following fields. Their values are strings containing the value of the named
53
53
  header, unless stated otherwise.
54
54
  * `HTTP_CONNECTION`
@@ -193,8 +193,8 @@ and send outgoing data.
193
193
  Client drivers have two additional methods for reading the HTTP data that was
194
194
  sent back by the server:
195
195
 
196
- * `driver.status` - the integer value of the HTTP status code
197
- * `driver.headers` - a hash-like object containing the response headers
196
+ - `driver.status` - the integer value of the HTTP status code
197
+ - `driver.headers` - a hash-like object containing the response headers
198
198
 
199
199
 
200
200
  ### HTTP Proxies
@@ -261,9 +261,9 @@ frames.
261
261
  The `options` argument is optional, and is a hash. It may contain the following
262
262
  keys:
263
263
 
264
- * `:max_length` - the maximum allowed size of incoming message frames, in bytes.
264
+ - `:max_length` - the maximum allowed size of incoming message frames, in bytes.
265
265
  The default value is `2^26 - 1`, or 1 byte short of 64 MiB.
266
- * `:protocols` - an array of strings representing acceptable subprotocols for
266
+ - `:protocols` - an array of strings representing acceptable subprotocols for
267
267
  use over the socket. The driver will negotiate one of these to use via the
268
268
  `Sec-WebSocket-Protocol` header if supported by the other peer.
269
269
 
@@ -1,8 +1,6 @@
1
1
  package com.jcoglan.websocket;
2
2
 
3
- import java.lang.Long;
4
3
  import java.io.IOException;
5
-
6
4
  import org.jruby.Ruby;
7
5
  import org.jruby.RubyClass;
8
6
  import org.jruby.RubyModule;
@@ -15,41 +13,45 @@ import org.jruby.runtime.builtin.IRubyObject;
15
13
  import org.jruby.runtime.load.BasicLibraryService;
16
14
 
17
15
  public class WebsocketMaskService implements BasicLibraryService {
18
- private Ruby runtime;
16
+ private Ruby runtime;
19
17
 
20
- public boolean basicLoad(Ruby runtime) throws IOException {
21
- this.runtime = runtime;
22
- RubyModule websocket = runtime.defineModule("WebSocket");
18
+ public boolean basicLoad(Ruby runtime) throws IOException {
19
+ this.runtime = runtime;
23
20
 
24
- RubyClass webSocketMask = websocket.defineClassUnder("Mask", runtime.getObject(), new ObjectAllocator() {
25
- public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
26
- return new WebsocketMask(runtime, rubyClass);
27
- }
28
- });
21
+ RubyModule websocket = runtime.defineModule("WebSocket");
22
+ RubyClass webSocketMask = websocket.defineClassUnder("Mask", runtime.getObject(), getAllocator());
29
23
 
30
- webSocketMask.defineAnnotatedMethods(WebsocketMask.class);
31
- return true;
32
- }
24
+ webSocketMask.defineAnnotatedMethods(WebsocketMask.class);
25
+ return true;
26
+ }
33
27
 
34
- public class WebsocketMask extends RubyObject {
35
- public WebsocketMask(final Ruby runtime, RubyClass rubyClass) {
36
- super(runtime, rubyClass);
28
+ ObjectAllocator getAllocator() {
29
+ return new ObjectAllocator() {
30
+ public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
31
+ return new WebsocketMask(runtime, rubyClass);
32
+ }
33
+ };
37
34
  }
38
35
 
39
- @JRubyMethod
40
- public IRubyObject mask(ThreadContext context, IRubyObject payload, IRubyObject mask) {
41
- if (mask.isNil()) return payload;
36
+ public class WebsocketMask extends RubyObject {
37
+ public WebsocketMask(final Ruby runtime, RubyClass rubyClass) {
38
+ super(runtime, rubyClass);
39
+ }
40
+
41
+ @JRubyMethod
42
+ public IRubyObject mask(ThreadContext context, IRubyObject payload, IRubyObject mask) {
43
+ if (mask.isNil()) return payload;
42
44
 
43
- byte[] payload_a = ((RubyString)payload).getBytes();
44
- byte[] mask_a = ((RubyString)mask).getBytes();
45
- int i, n = payload_a.length;
45
+ byte[] payload_a = ((RubyString)payload).getBytes();
46
+ byte[] mask_a = ((RubyString)mask).getBytes();
47
+ int i, n = payload_a.length;
46
48
 
47
- if (n == 0) return payload;
49
+ if (n == 0) return payload;
48
50
 
49
- for (i = 0; i < n; i++) {
50
- payload_a[i] ^= mask_a[i % 4];
51
- }
52
- return RubyString.newStringNoCopy(runtime, payload_a);
51
+ for (i = 0; i < n; i++) {
52
+ payload_a[i] ^= mask_a[i % 4];
53
+ }
54
+ return RubyString.newStringNoCopy(runtime, payload_a);
55
+ }
53
56
  }
54
- }
55
57
  }
@@ -1,41 +1,32 @@
1
1
  #include <ruby.h>
2
2
 
3
- VALUE WebSocket = Qnil;
4
- VALUE WebSocketMask = Qnil;
5
-
6
- void Init_websocket_mask();
7
- VALUE method_websocket_mask(VALUE self, VALUE payload, VALUE mask);
8
-
9
- void
10
- Init_websocket_mask()
3
+ VALUE method_websocket_mask(VALUE self, VALUE payload, VALUE mask)
11
4
  {
12
- WebSocket = rb_define_module("WebSocket");
13
- WebSocketMask = rb_define_module_under(WebSocket, "Mask");
14
- rb_define_singleton_method(WebSocketMask, "mask", method_websocket_mask, 2);
15
- }
5
+ char *payload_s, *mask_s, *unmasked_s;
6
+ long i, n;
7
+ VALUE unmasked;
16
8
 
17
- VALUE
18
- method_websocket_mask(VALUE self,
19
- VALUE payload,
20
- VALUE mask)
21
- {
22
- char *payload_s, *mask_s, *unmasked_s;
23
- long i, n;
24
- VALUE unmasked;
9
+ if (mask == Qnil || RSTRING_LEN(mask) != 4) {
10
+ return payload;
11
+ }
25
12
 
26
- if (mask == Qnil || RSTRING_LEN(mask) != 4) {
27
- return payload;
28
- }
13
+ payload_s = RSTRING_PTR(payload);
14
+ mask_s = RSTRING_PTR(mask);
15
+ n = RSTRING_LEN(payload);
29
16
 
30
- payload_s = RSTRING_PTR(payload);
31
- mask_s = RSTRING_PTR(mask);
32
- n = RSTRING_LEN(payload);
17
+ unmasked = rb_str_new(0, n);
18
+ unmasked_s = RSTRING_PTR(unmasked);
33
19
 
34
- unmasked = rb_str_new(0, n);
35
- unmasked_s = RSTRING_PTR(unmasked);
20
+ for (i = 0; i < n; i++) {
21
+ unmasked_s[i] = payload_s[i] ^ mask_s[i % 4];
22
+ }
23
+ return unmasked;
24
+ }
25
+
26
+ void Init_websocket_mask()
27
+ {
28
+ VALUE WebSocket = rb_define_module("WebSocket");
29
+ VALUE Mask = rb_define_module_under(WebSocket, "Mask");
36
30
 
37
- for (i = 0; i < n; i++) {
38
- unmasked_s[i] = payload_s[i] ^ mask_s[i % 4];
39
- }
40
- return unmasked;
31
+ rb_define_singleton_method(Mask, "mask", method_websocket_mask, 2);
41
32
  }
@@ -101,8 +101,17 @@ module WebSocket
101
101
 
102
102
  def start
103
103
  return false unless @ready_state == 0
104
- response = handshake_response
105
- return false unless response
104
+
105
+ unless Driver.websocket?(@socket.env)
106
+ return fail_handshake(ProtocolError.new('Not a WebSocket request'))
107
+ end
108
+
109
+ begin
110
+ response = handshake_response
111
+ rescue => error
112
+ return fail_handshake(error)
113
+ end
114
+
106
115
  @socket.write(response)
107
116
  open unless @stage == -1
108
117
  true
@@ -134,6 +143,24 @@ module WebSocket
134
143
 
135
144
  private
136
145
 
146
+ def fail_handshake(error)
147
+ headers = Headers.new
148
+ headers['Content-Type'] = 'text/plain'
149
+ headers['Content-Length'] = error.message.bytesize
150
+
151
+ headers = ['HTTP/1.1 400 Bad Request', headers.to_s, error.message]
152
+ @socket.write(headers.join("\r\n"))
153
+ fail(:protocol_error, error.message)
154
+
155
+ false
156
+ end
157
+
158
+ def fail(type, message)
159
+ @ready_state = 2
160
+ emit(:error, ProtocolError.new(message))
161
+ close
162
+ end
163
+
137
164
  def open
138
165
  @ready_state = 1
139
166
  @queue.each { |message| frame(*message) }
@@ -155,10 +182,15 @@ module WebSocket
155
182
  end
156
183
 
157
184
  def self.rack(socket, options = {})
158
- env = socket.env
159
- if env['HTTP_SEC_WEBSOCKET_VERSION']
185
+ env = socket.env
186
+ version = env['HTTP_SEC_WEBSOCKET_VERSION']
187
+ key = env['HTTP_SEC_WEBSOCKET_KEY']
188
+ key1 = env['HTTP_SEC_WEBSOCKET_KEY1']
189
+ key2 = env['HTTP_SEC_WEBSOCKET_KEY2']
190
+
191
+ if version or key
160
192
  Hybi.new(socket, options.merge(:require_masking => true))
161
- elsif env['HTTP_SEC_WEBSOCKET_KEY1']
193
+ elsif key1 or key2
162
194
  Draft76.new(socket, options)
163
195
  else
164
196
  Draft75.new(socket, options)
@@ -31,7 +31,7 @@ module WebSocket
31
31
  @headers['Upgrade'] = 'websocket'
32
32
  @headers['Connection'] = 'Upgrade'
33
33
  @headers['Sec-WebSocket-Key'] = @key
34
- @headers['Sec-WebSocket-Version'] = '13'
34
+ @headers['Sec-WebSocket-Version'] = VERSION
35
35
 
36
36
  if @protocols.size > 0
37
37
  @headers['Sec-WebSocket-Protocol'] = @protocols * ', '
@@ -44,7 +44,7 @@ module WebSocket
44
44
  end
45
45
 
46
46
  def version
47
- 'hybi-13'
47
+ "hybi-#{VERSION}"
48
48
  end
49
49
 
50
50
  def proxy(origin, options = {})
@@ -29,7 +29,7 @@ module WebSocket
29
29
 
30
30
  def close(reason = nil, code = nil)
31
31
  return false if @ready_state == 3
32
- @socket.write([0xFF, 0x00].pack('C*'))
32
+ @socket.write([0xFF, 0x00].pack('C*')) if @ready_state == 1
33
33
  @ready_state = 3
34
34
  emit(:close, CloseEvent.new(nil, nil))
35
35
  true
@@ -39,19 +39,20 @@ module WebSocket
39
39
 
40
40
  def handshake_response
41
41
  env = @socket.env
42
-
43
42
  key1 = env['HTTP_SEC_WEBSOCKET_KEY1']
43
+ key2 = env['HTTP_SEC_WEBSOCKET_KEY2']
44
+
45
+ raise ProtocolError.new('Missing required header: Sec-WebSocket-Key1') unless key1
46
+ raise ProtocolError.new('Missing required header: Sec-WebSocket-Key2') unless key2
47
+
44
48
  number1 = number_from_key(key1)
45
49
  spaces1 = spaces_in_key(key1)
46
50
 
47
- key2 = env['HTTP_SEC_WEBSOCKET_KEY2']
48
51
  number2 = number_from_key(key2)
49
52
  spaces2 = spaces_in_key(key2)
50
53
 
51
54
  if number1 % spaces1 != 0 or number2 % spaces2 != 0
52
- emit(:error, ProtocolError.new('Client sent invalid Sec-WebSocket-Key headers'))
53
- close
54
- return nil
55
+ raise ProtocolError.new('Client sent invalid Sec-WebSocket-Key headers')
55
56
  end
56
57
 
57
58
  @key_values = [number1 / spaces1, number2 / spaces2]
@@ -84,7 +85,8 @@ module WebSocket
84
85
  end
85
86
 
86
87
  def number_from_key(key)
87
- key.scan(/[0-9]/).join('').to_i(10)
88
+ number = key.scan(/[0-9]/).join('')
89
+ number == '' ? Float::NAN : number.to_i(10)
88
90
  end
89
91
 
90
92
  def spaces_in_key(key)
@@ -11,7 +11,8 @@ module WebSocket
11
11
  Base64.strict_encode64(Digest::SHA1.digest(key + GUID))
12
12
  end
13
13
 
14
- GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
14
+ VERSION = '13'
15
+ GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
15
16
 
16
17
  BYTE = 0b11111111
17
18
  FIN = MASK = 0b10000000
@@ -68,22 +69,16 @@ module WebSocket
68
69
 
69
70
  return unless @socket.respond_to?(:env)
70
71
 
71
- sec_key = @socket.env['HTTP_SEC_WEBSOCKET_KEY']
72
- protos = @socket.env['HTTP_SEC_WEBSOCKET_PROTOCOL']
73
-
74
- @headers['Upgrade'] = 'websocket'
75
- @headers['Connection'] = 'Upgrade'
76
- @headers['Sec-WebSocket-Accept'] = Hybi.generate_accept(sec_key)
77
-
78
72
  if protos = @socket.env['HTTP_SEC_WEBSOCKET_PROTOCOL']
79
73
  protos = protos.split(/ *, */) if String === protos
80
74
  @protocol = protos.find { |p| @protocols.include?(p) }
81
- @headers['Sec-WebSocket-Protocol'] = @protocol if @protocol
75
+ else
76
+ @protocol = nil
82
77
  end
83
78
  end
84
79
 
85
80
  def version
86
- "hybi-#{@socket.env['HTTP_SEC_WEBSOCKET_VERSION']}"
81
+ "hybi-#{VERSION}"
87
82
  end
88
83
 
89
84
  def add_extension(extension)
@@ -229,13 +224,24 @@ module WebSocket
229
224
  end
230
225
 
231
226
  def handshake_response
232
- begin
233
- extensions = @extensions.generate_response(@socket.env['HTTP_SEC_WEBSOCKET_EXTENSIONS'])
234
- rescue => error
235
- fail(:protocol_error, error.message)
236
- return nil
227
+ sec_key = @socket.env['HTTP_SEC_WEBSOCKET_KEY']
228
+ version = @socket.env['HTTP_SEC_WEBSOCKET_VERSION']
229
+
230
+ unless version == VERSION
231
+ raise ProtocolError.new("Unsupported WebSocket version: #{VERSION}")
232
+ end
233
+
234
+ unless sec_key
235
+ raise ProtocolError.new('Missing handshake request header: Sec-WebSocket-Key')
237
236
  end
238
237
 
238
+ @headers['Upgrade'] = 'websocket'
239
+ @headers['Connection'] = 'Upgrade'
240
+ @headers['Sec-WebSocket-Accept'] = Hybi.generate_accept(sec_key)
241
+
242
+ @headers['Sec-WebSocket-Protocol'] = @protocol if @protocol
243
+
244
+ extensions = @extensions.generate_response(@socket.env['HTTP_SEC_WEBSOCKET_EXTENSIONS'])
239
245
  @headers['Sec-WebSocket-Extensions'] = extensions if extensions
240
246
 
241
247
  start = 'HTTP/1.1 101 Switching Protocols'
Binary file
metadata CHANGED
@@ -1,85 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: websocket-driver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: java
6
6
  authors:
7
7
  - James Coglan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-11 00:00:00.000000000 Z
11
+ date: 2019-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: websocket-extensions
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
18
  version: 0.1.0
19
+ name: websocket-extensions
20
+ prerelease: false
21
+ type: :runtime
20
22
  version_requirements: !ruby/object:Gem::Requirement
21
23
  requirements:
22
24
  - - ">="
23
25
  - !ruby/object:Gem::Version
24
26
  version: 0.1.0
25
- prerelease: false
26
- type: :runtime
27
27
  - !ruby/object:Gem::Dependency
28
- name: eventmachine
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - ">="
32
31
  - !ruby/object:Gem::Version
33
32
  version: '0'
33
+ name: eventmachine
34
+ prerelease: false
35
+ type: :development
34
36
  version_requirements: !ruby/object:Gem::Requirement
35
37
  requirements:
36
38
  - - ">="
37
39
  - !ruby/object:Gem::Version
38
40
  version: '0'
39
- prerelease: false
40
- type: :development
41
41
  - !ruby/object:Gem::Dependency
42
- name: permessage_deflate
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - ">="
46
45
  - !ruby/object:Gem::Version
47
46
  version: '0'
47
+ name: permessage_deflate
48
+ prerelease: false
49
+ type: :development
48
50
  version_requirements: !ruby/object:Gem::Requirement
49
51
  requirements:
50
52
  - - ">="
51
53
  - !ruby/object:Gem::Version
52
54
  version: '0'
53
- prerelease: false
54
- type: :development
55
55
  - !ruby/object:Gem::Dependency
56
- name: rake-compiler
57
56
  requirement: !ruby/object:Gem::Requirement
58
57
  requirements:
59
- - - "~>"
58
+ - - ">="
60
59
  - !ruby/object:Gem::Version
61
- version: 0.8.0
60
+ version: '0'
61
+ name: rake-compiler
62
+ prerelease: false
63
+ type: :development
62
64
  version_requirements: !ruby/object:Gem::Requirement
63
65
  requirements:
64
- - - "~>"
66
+ - - ">="
65
67
  - !ruby/object:Gem::Version
66
- version: 0.8.0
67
- prerelease: false
68
- type: :development
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rspec
71
70
  requirement: !ruby/object:Gem::Requirement
72
71
  requirements:
73
72
  - - ">="
74
73
  - !ruby/object:Gem::Version
75
74
  version: '0'
75
+ name: rspec
76
+ prerelease: false
77
+ type: :development
76
78
  version_requirements: !ruby/object:Gem::Requirement
77
79
  requirements:
78
80
  - - ">="
79
81
  - !ruby/object:Gem::Version
80
82
  version: '0'
81
- prerelease: false
82
- type: :development
83
83
  description:
84
84
  email: jcoglan@gmail.com
85
85
  executables: []
@@ -114,7 +114,7 @@ files:
114
114
  - lib/websocket_mask.jar
115
115
  homepage: https://github.com/faye/websocket-driver-ruby
116
116
  licenses:
117
- - MIT
117
+ - Apache-2.0
118
118
  metadata: {}
119
119
  post_install_message:
120
120
  rdoc_options:
@@ -136,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
136
136
  version: '0'
137
137
  requirements: []
138
138
  rubyforge_project:
139
- rubygems_version: 2.6.11
139
+ rubygems_version: 2.7.6
140
140
  signing_key:
141
141
  specification_version: 4
142
142
  summary: WebSocket protocol handler with pluggable I/O