mirror of
https://github.com/bitwarden/help
synced 2025-12-24 04:04:27 +00:00
Promote to Master (#748)
* initial commit
* adding quotes for the array error
* Create Gemfile
* Create Gemfile.lock
* add .nvmrc and .node-version
* removed /article from URL
* update links to work with netlify
* more fixed links
* link fixes
* update bad links
* Update netlify.toml
toml test for redirects
* article redirect
* link fixes
* Update index.html
* Update netlify.toml
* Update _config.yml
* Update netlify.toml
* Update netlify.toml
* Update netlify.toml
* Update netlify.toml
* Update netlify.toml
* add article back into URL for launch
* Update netlify.toml
* Update netlify.toml
* add order to categories front matter
* Update netlify.toml
* update
* sidemenu update
* Revert "sidemenu update"
This reverts commit 5441c3d35c.
* update order prop
* Navbar updates per Gary and compiler warnings
* font/style tweaks
* Update sidebar.html
* Stage Release Documentation (#739)
* initial drafts
* rewrite Custom Fields article to prioritize new context-menu option & better organize ancillary information
* edit
* edit
* Custom Field Context Menu & CAPTCHA item in release notes
* SSO relink event
* update rn
* small edits
* improve release notes titles
* fix side menu
* Edits courtest of mportune!
* update order
* link fixes
* link cleanup
* image updates and a link
* fix trailing slash
Co-authored-by: DanHillesheim <79476558+DanHillesheim@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
63f78e8979
commit
906e2ca0dd
3
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/.gitignore
vendored
Normal file
3
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*.gemspec
|
||||
pkg
|
||||
Gemfile.lock
|
||||
149
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/CHANGELOG.rdoc
vendored
Normal file
149
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/CHANGELOG.rdoc
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
= Changelog
|
||||
|
||||
== 0.5.1 / 2014-04-23
|
||||
|
||||
- new features:
|
||||
- Support for receiving binary messages
|
||||
|
||||
- changed:
|
||||
- Allow additional close codes to be sent by apps
|
||||
- Raise better errors on missing Sec-WebSocket-Key2
|
||||
- Updated http_parser.rb dependency to 0.6.0
|
||||
|
||||
- bug fixes:
|
||||
- Abort if HTTP request URI is invalid
|
||||
- Force close connections that have been sent a close handshake after a timeout
|
||||
|
||||
- improved spec compliance on:
|
||||
- Missing continuation frames
|
||||
- Fragmented control frames
|
||||
- Close behaviour after protocol errors
|
||||
|
||||
== 0.5.0 / 2013-03-05
|
||||
|
||||
- new features:
|
||||
- onclose handler is now passed a hash containing was_clean (set to true in drafts 03 and above when a connection is closed with a closing handshake, either by the server or the client), the close code, and reason (drafts 06 and above). Close code 1005 indicates that no code was supplied, and 1006 that the connection was closed abnormally.
|
||||
- use Connection#support_close_codes? to easily check whether close codes are supported by the WebSocket protocol (drafts 06 and above)
|
||||
- closes connection with 1007 close code if text frame contains invalid UTF8
|
||||
- added Handshake#secure? for checking whether the connection is secure (either ssl or behind an ssl proxy)
|
||||
|
||||
- changed:
|
||||
- Defaults to sending no close code rather than 1000 (consistent with browsers)
|
||||
- Allows sending a 3xxx close code
|
||||
- Renamed Connection#close_websocket to Connection#close (again for consistency with browsers). Old method is available till 0.6.
|
||||
- Sends reasons with internally generated closure (previously only sent code)
|
||||
- Echos close code when replying to close handshake
|
||||
|
||||
== 0.4.0 / 2013-01-22
|
||||
|
||||
- new features:
|
||||
- on_open handler is now passed a handshake object which exposes the request headers, path, and query parameters
|
||||
- Easily access the protocol version via Handshake#protocol_version
|
||||
- Easily access the origin via Handshake#origin
|
||||
|
||||
- changed:
|
||||
- Removed Connection#request - change to using handshake passed to on_open
|
||||
|
||||
- internals:
|
||||
- Uses the http_parser.rb gem
|
||||
|
||||
== 0.3.8 / 2012-07-12
|
||||
|
||||
- bug fixes:
|
||||
- Fixed support for Ruby 1.8.7 which was broken in 0.3.7
|
||||
|
||||
== 0.3.7 / 2012-07-11
|
||||
|
||||
- new features:
|
||||
- Supports sending 1009 error code when incoming frame is too large to handle, and added associated exception class WSMessageTooBigError [Martyn Loughran]
|
||||
- Supports overriding the maximum frame size by setting the max_frame_size accessor on the connection object (in bytes). Default unchanged at 10MB. [Martyn Loughran]
|
||||
|
||||
- bug fixes:
|
||||
- Fixes some encoding issues on Ruby 1.9 [Dingding Ye]
|
||||
- Raises a HandshakeError if WS header is empty [Markus Fenske]
|
||||
- Connection#send would mutate passed string to BINARY encoding. The fix still mutates the string by forcing the encoding back to UTF-8 before returning, but if the passed string was encoded as UTF-8 this is equivalent [Martyn Loughran]
|
||||
|
||||
== 0.3.6 / 2011-12-23
|
||||
|
||||
- new features:
|
||||
- Supports sending ping & pong messages
|
||||
- Supports binding to received ping & pong messages
|
||||
|
||||
== 0.3.5 / 2011-10-24
|
||||
|
||||
- new features:
|
||||
- Support WebSocket draft 13
|
||||
|
||||
== 0.3.2 / 2011-10-09
|
||||
|
||||
- bugfixes:
|
||||
- Handling of messages with > 2 frames
|
||||
- Encode string passed to onmessage handler as UTF-8 on Ruby 1.9
|
||||
- Add 10MB frame length limit to all draft versions
|
||||
|
||||
== 0.3.1 / 2011-07-28
|
||||
|
||||
- new features:
|
||||
- Support WebSocket drafts 07 & 08
|
||||
|
||||
== 0.3.0 / 2011-05-06
|
||||
|
||||
- new features:
|
||||
- Support WebSocket drafts 05 & 06
|
||||
- changes:
|
||||
- Accept request headers in a case insensitive manner
|
||||
- Change handling of errors. Previously some application errors were caught
|
||||
internally and were invisible unless an onerror callback was supplied. See
|
||||
readme for details
|
||||
|
||||
== 0.2.1 / 2011-03-01
|
||||
|
||||
- bugfixes:
|
||||
- Performance improvements to draft 76 framing
|
||||
- Limit frame lengths for draft 76
|
||||
- Better error handling for draft 76 handshake
|
||||
- Ruby 1.9 support
|
||||
|
||||
== 0.2.0 / 2010-11-23
|
||||
|
||||
- new features:
|
||||
- Support for WebSocket draft 03
|
||||
- bugfixes:
|
||||
- Handle case when handshake split into two receive_data calls
|
||||
- Stricter regexp matching of frames
|
||||
|
||||
== 0.1.4 / 2010-08-23
|
||||
|
||||
- new features:
|
||||
- Allow custom ssl certificate to be used by passing :tls_options
|
||||
- Protect against errors caused by non limited frame lengths
|
||||
- Use custom exceptions rather than RuntimeError
|
||||
- bugfixes:
|
||||
- Handle invalid HTTP request with HandshakeError
|
||||
|
||||
== 0.1.3 / 2010-07-18
|
||||
|
||||
- new features:
|
||||
- onerror callback
|
||||
- bugfixes:
|
||||
- proper handling of zero spaces in key1 or key2(prevent ZeroDivisionError)
|
||||
- convert received data to utf-8 to prevent ruby 1.9 errors
|
||||
- fix handling of null bytes within a frame
|
||||
|
||||
== 0.1.2 / 2010-06-16
|
||||
|
||||
- new features:
|
||||
- none
|
||||
- bugfixes:
|
||||
- allow $ character inside header key
|
||||
|
||||
== 0.1.1 / 2010-06-13
|
||||
|
||||
- new features:
|
||||
- wss/ssl support
|
||||
- bugfixes:
|
||||
- can't & strings
|
||||
|
||||
== 0.1.0 / 2010-06-12
|
||||
|
||||
- initial release
|
||||
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/Gemfile
vendored
Normal file
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/Gemfile
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
source "http://rubygems.org"
|
||||
|
||||
gemspec
|
||||
|
||||
gem "em-websocket-client", git: "git@github.com:movitto/em-websocket-client.git", branch: "expose-websocket-api"
|
||||
gem "em-spec", "~> 0.2.6"
|
||||
gem "em-http-request", "~> 1.1.1"
|
||||
gem "rspec", "~> 3.5.0"
|
||||
gem "rake"
|
||||
7
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/LICENCE
vendored
Normal file
7
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/LICENCE
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
Copyright (c) 2009-2014 Ilya Grigorik, Martyn Loughran
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
142
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/README.md
vendored
Normal file
142
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/README.md
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
# EM-WebSocket
|
||||
|
||||
[](http://rubygems.org/gems/em-websocket)
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
|
||||
EventMachine based, async, Ruby WebSocket server. Take a look at examples directory, or check out the blog post: [Ruby & Websockets: TCP for the Web](http://www.igvita.com/2009/12/22/ruby-websockets-tcp-for-the-browser/).
|
||||
|
||||
## Simple server example
|
||||
|
||||
```ruby
|
||||
require 'em-websocket'
|
||||
|
||||
EM.run {
|
||||
EM::WebSocket.run(:host => "0.0.0.0", :port => 8080) do |ws|
|
||||
ws.onopen { |handshake|
|
||||
puts "WebSocket connection open"
|
||||
|
||||
# Access properties on the EM::WebSocket::Handshake object, e.g.
|
||||
# path, query_string, origin, headers
|
||||
|
||||
# Publish message to the client
|
||||
ws.send "Hello Client, you connected to #{handshake.path}"
|
||||
}
|
||||
|
||||
ws.onclose { puts "Connection closed" }
|
||||
|
||||
ws.onmessage { |msg|
|
||||
puts "Recieved message: #{msg}"
|
||||
ws.send "Pong: #{msg}"
|
||||
}
|
||||
end
|
||||
}
|
||||
```
|
||||
|
||||
## Protocols supported, and protocol specific functionality
|
||||
|
||||
Supports all WebSocket protocols in use in the wild (and a few that are not): drafts 75, 76, 1-17, rfc.
|
||||
|
||||
While some of the changes between protocols are unimportant from the point of view of application developers, a few drafts did introduce new functionality. It's possible to easily test for this functionality by using
|
||||
|
||||
### Ping & pong supported
|
||||
|
||||
Call `ws.pingable?` to check whether ping & pong is supported by the protocol in use.
|
||||
|
||||
It's possible to send a ping frame (`ws.ping(body = '')`), which the client must respond to with a pong, or the server can send an unsolicited pong frame (`ws.pong(body = '')`) which the client should not respond to. These methods can be used regardless of protocol version; they return true if the protocol supports ping&pong or false otherwise.
|
||||
|
||||
When receiving a ping, the server will automatically respond with a pong as the spec requires (so you should _not_ write an onping handler that replies with a pong), however it is possible to bind to ping & pong events if desired by using the `onping` and `onpong` methods.
|
||||
|
||||
### Close codes and reasons
|
||||
|
||||
A WebSocket connection can be closed cleanly, regardless of protocol, by calling `ws.close(code = nil, body = nil)`.
|
||||
|
||||
Early protocols just close the TCP connection, draft 3 introduced a close handshake, and draft 6 added close codes and reasons to the close handshake. Call `ws.supports_close_codes?` to check whether close codes are supported (i.e. the protocol version is 6 or above).
|
||||
|
||||
The `onclose` callback is passed a hash which may contain following keys (depending on the protocol version):
|
||||
|
||||
* `was_clean`: boolean indicating whether the connection was closed via the close handshake.
|
||||
* `code`: the close code. There are two special close codes which the server may set (as defined in the WebSocket spec):
|
||||
* 1005: no code was supplied
|
||||
* 1006: abnormal closure (the same as `was_clean: false`)
|
||||
* `reason`: the close reason
|
||||
|
||||
Acceptable close codes are defined in the WebSocket rfc (<http://tools.ietf.org/html/rfc6455#section-7.4>). The following codes can be supplies when calling `ws.close(code)`:
|
||||
|
||||
* 1000: a generic normal close
|
||||
* range 3xxx: reserved for libraries, frameworks, and applications (and can be registered with IANA)
|
||||
* range 4xxx: for private use
|
||||
|
||||
If unsure use a code in the 4xxx range. em-websocket may also close a connection with one of the following close codes:
|
||||
|
||||
* 1002: WebSocket protocol error.
|
||||
* 1009: Message too big to process. By default em-websocket will accept frames up to 10MB in size. If a frame is larger than this the connection will be closed without reading the frame data. The limit can be overriden globally (`EM::WebSocket.max_frame_size = bytes`) or on a specific connection (`ws.max_frame_size = bytes`).
|
||||
|
||||
## Secure server
|
||||
|
||||
It is possible to accept secure `wss://` connections by passing `:secure => true` when opening the connection. Pass a `:tls_options` hash containing keys as described in http://www.rubydoc.info/github/eventmachine/eventmachine/EventMachine/Connection:start_tls
|
||||
|
||||
**Warning**: Safari 5 does not currently support prompting on untrusted SSL certificates therefore using a self signed certificate may leave you scratching your head.
|
||||
|
||||
```ruby
|
||||
EM::WebSocket.start({
|
||||
:host => "0.0.0.0",
|
||||
:port => 443,
|
||||
:secure => true,
|
||||
:tls_options => {
|
||||
:private_key_file => "/private/key",
|
||||
:cert_chain_file => "/ssl/certificate"
|
||||
}
|
||||
}) do |ws|
|
||||
# ...
|
||||
end
|
||||
```
|
||||
|
||||
It's possible to check whether an incoming connection is secure by reading `handshake.secure?` in the onopen callback.
|
||||
|
||||
## Running behind an SSL Proxy/Terminator, like Stunnel
|
||||
|
||||
The `:secure_proxy => true` option makes it possible to use em-websocket behind a secure SSL proxy/terminator like [Stunnel](http://www.stunnel.org/) which does the actual encryption & decryption.
|
||||
|
||||
Note that this option is only required to support drafts 75 & 76 correctly (e.g. Safari 5.1.x & earlier, and Safari on iOS 5.x & earlier).
|
||||
|
||||
```ruby
|
||||
EM::WebSocket.start({
|
||||
:host => "0.0.0.0",
|
||||
:port => 8080,
|
||||
:secure_proxy => true
|
||||
}) do |ws|
|
||||
# ...
|
||||
end
|
||||
```
|
||||
|
||||
## Handling errors
|
||||
|
||||
There are two kinds of errors that need to be handled -- WebSocket protocol errors and errors in application code.
|
||||
|
||||
WebSocket protocol errors (for example invalid data in the handshake or invalid message frames) raise errors which descend from `EM::WebSocket::WebSocketError`. Such errors are rescued internally and the WebSocket connection will be closed immediately or an error code sent to the browser in accordance to the WebSocket specification. It is possible to be notified in application code of such errors by including an `onerror` callback.
|
||||
|
||||
```ruby
|
||||
ws.onerror { |error|
|
||||
if error.kind_of?(EM::WebSocket::WebSocketError)
|
||||
# ...
|
||||
end
|
||||
}
|
||||
```
|
||||
|
||||
Application errors are treated differently. If no `onerror` callback has been defined these errors will propagate to the EventMachine reactor, typically causing your program to terminate. If you wish to handle exceptions, simply supply an `onerror callback` and check for exceptions which are not descendant from `EM::WebSocket::WebSocketError`.
|
||||
|
||||
It is also possible to log all errors when developing by including the `:debug => true` option when initialising the WebSocket server.
|
||||
|
||||
## Emulating WebSockets in older browsers
|
||||
|
||||
It is possible to emulate WebSockets in older browsers using flash emulation. For example take a look at the [web-socket-js](https://github.com/gimite/web-socket-js) project.
|
||||
|
||||
Using flash emulation does require some minimal support from em-websocket which is enabled by default. If flash connects to the WebSocket port and requests a policy file (which it will do if it fails to receive a policy file on port 843 after a timeout), em-websocket will return one. Also see <https://github.com/igrigorik/em-websocket/issues/61> for an example policy file server which you can run on port 843.
|
||||
|
||||
## Examples & Projects using em-websocket
|
||||
|
||||
* [Pusher](http://pusher.com) - Realtime Messaging Service
|
||||
* [Livereload](https://github.com/mockko/livereload) - LiveReload applies CSS/JS changes to Safari or Chrome w/o reloading
|
||||
* [Twitter AMQP WebSocket Example](http://github.com/rubenfonseca/twitter-amqp-websocket-example)
|
||||
* examples/multicast.rb - broadcast all ruby tweets to all subscribers
|
||||
* examples/echo.rb - server <> client exchange via a websocket
|
||||
11
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/Rakefile
vendored
Normal file
11
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/Rakefile
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
require 'bundler'
|
||||
Bundler::GemHelper.install_tasks
|
||||
|
||||
require 'rspec/core/rake_task'
|
||||
|
||||
RSpec::Core::RakeTask.new do |t|
|
||||
t.rspec_opts = ["-c", "-f progress", "-r ./spec/helper.rb"]
|
||||
t.pattern = 'spec/**/*_spec.rb'
|
||||
end
|
||||
|
||||
task :default => :spec
|
||||
24
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/examples/echo.rb
vendored
Normal file
24
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/examples/echo.rb
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
require File.expand_path('../../lib/em-websocket', __FILE__)
|
||||
|
||||
EM.run {
|
||||
EM::WebSocket.run(:host => "0.0.0.0", :port => 8080, :debug => false) do |ws|
|
||||
ws.onopen { |handshake|
|
||||
puts "WebSocket opened #{{
|
||||
:path => handshake.path,
|
||||
:query => handshake.query,
|
||||
:origin => handshake.origin,
|
||||
}}"
|
||||
|
||||
ws.send "Hello Client!"
|
||||
}
|
||||
ws.onmessage { |msg|
|
||||
ws.send "Pong: #{msg}"
|
||||
}
|
||||
ws.onclose {
|
||||
puts "WebSocket closed"
|
||||
}
|
||||
ws.onerror { |e|
|
||||
puts "Error: #{e.message}"
|
||||
}
|
||||
end
|
||||
}
|
||||
47
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/examples/multicast.rb
vendored
Normal file
47
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/examples/multicast.rb
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
require 'em-websocket'
|
||||
# requires the twitter-stream gem
|
||||
require 'twitter/json_stream'
|
||||
require 'json'
|
||||
|
||||
#
|
||||
# broadcast all ruby related tweets to all connected users!
|
||||
#
|
||||
|
||||
username = ARGV.shift
|
||||
password = ARGV.shift
|
||||
raise "need username and password" if !username or !password
|
||||
|
||||
EventMachine.run {
|
||||
@channel = EM::Channel.new
|
||||
|
||||
@twitter = Twitter::JSONStream.connect(
|
||||
:path => '/1/statuses/filter.json?track=ruby',
|
||||
:auth => "#{username}:#{password}",
|
||||
:ssl => true
|
||||
)
|
||||
|
||||
@twitter.each_item do |status|
|
||||
status = JSON.parse(status)
|
||||
@channel.push "#{status['user']['screen_name']}: #{status['text']}"
|
||||
end
|
||||
|
||||
|
||||
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080, :debug => true) do |ws|
|
||||
|
||||
ws.onopen {
|
||||
sid = @channel.subscribe { |msg| ws.send msg }
|
||||
@channel.push "#{sid} connected!"
|
||||
|
||||
ws.onmessage { |msg|
|
||||
@channel.push "<#{sid}>: #{msg}"
|
||||
}
|
||||
|
||||
ws.onclose {
|
||||
@channel.unsubscribe(sid)
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
puts "Server started"
|
||||
}
|
||||
24
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/examples/ping.rb
vendored
Normal file
24
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/examples/ping.rb
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
require File.expand_path('../../lib/em-websocket', __FILE__)
|
||||
|
||||
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080, :debug => false) do |ws|
|
||||
timer = nil
|
||||
ws.onopen {
|
||||
puts "Ping supported: #{ws.pingable?}"
|
||||
timer = EM.add_periodic_timer(1) {
|
||||
p ["Sent ping", ws.ping('hello')]
|
||||
}
|
||||
}
|
||||
ws.onpong { |value|
|
||||
puts "Received pong: #{value}"
|
||||
}
|
||||
ws.onping { |value|
|
||||
puts "Received ping: #{value}"
|
||||
}
|
||||
ws.onclose {
|
||||
EM.cancel_timer(timer)
|
||||
puts "WebSocket closed"
|
||||
}
|
||||
ws.onerror { |e|
|
||||
puts "Error: #{e.message}"
|
||||
}
|
||||
end
|
||||
29
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/examples/test.html
vendored
Normal file
29
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/examples/test.html
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
function init() {
|
||||
function debug(string) {
|
||||
var element = document.getElementById("debug");
|
||||
var p = document.createElement("p");
|
||||
p.appendChild(document.createTextNode(string));
|
||||
element.appendChild(p);
|
||||
}
|
||||
|
||||
var Socket = "MozWebSocket" in window ? MozWebSocket : WebSocket;
|
||||
var ws = new Socket("ws://localhost:8080/foo/bar?hello=world");
|
||||
ws.onmessage = function(evt) { debug("Received: " + evt.data); };
|
||||
ws.onclose = function(event) {
|
||||
debug("Closed - code: " + event.code + ", reason: " + event.reason + ", wasClean: " + event.wasClean);
|
||||
};
|
||||
ws.onopen = function() {
|
||||
debug("connected...");
|
||||
ws.send("hello server");
|
||||
ws.send("hello again");
|
||||
};
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init();">
|
||||
<div id="debug"></div>
|
||||
</body>
|
||||
</html>
|
||||
24
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket.rb
vendored
Normal file
24
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket.rb
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
||||
|
||||
require "eventmachine"
|
||||
|
||||
%w[
|
||||
debugger websocket connection
|
||||
handshake
|
||||
handshake75 handshake76 handshake04
|
||||
framing76 framing03 framing04 framing05 framing07
|
||||
close75 close03 close05 close06
|
||||
masking04
|
||||
message_processor_03 message_processor_06
|
||||
handler handler75 handler76 handler03 handler05 handler06 handler07 handler08 handler13
|
||||
].each do |file|
|
||||
require "em-websocket/#{file}"
|
||||
end
|
||||
|
||||
unless ''.respond_to?(:getbyte)
|
||||
class String
|
||||
def getbyte(i)
|
||||
self[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
14
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/close03.rb
vendored
Normal file
14
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/close03.rb
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module Close03
|
||||
def close_websocket(code, body)
|
||||
# TODO: Ideally send body data and check that it matches in ack
|
||||
send_frame(:close, '')
|
||||
@state = :closing
|
||||
start_close_timeout
|
||||
end
|
||||
|
||||
def supports_close_codes?; false; end
|
||||
end
|
||||
end
|
||||
end
|
||||
14
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/close05.rb
vendored
Normal file
14
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/close05.rb
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module Close05
|
||||
def close_websocket(code, body)
|
||||
# TODO: Ideally send body data and check that it matches in ack
|
||||
send_frame(:close, "\x53")
|
||||
@state = :closing
|
||||
start_close_timeout
|
||||
end
|
||||
|
||||
def supports_close_codes?; false; end
|
||||
end
|
||||
end
|
||||
end
|
||||
19
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/close06.rb
vendored
Normal file
19
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/close06.rb
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module Close06
|
||||
def close_websocket(code, body)
|
||||
if code
|
||||
close_data = [code].pack('n')
|
||||
close_data << body if body
|
||||
send_frame(:close, close_data)
|
||||
else
|
||||
send_frame(:close, '')
|
||||
end
|
||||
@state = :closing
|
||||
start_close_timeout
|
||||
end
|
||||
|
||||
def supports_close_codes?; true; end
|
||||
end
|
||||
end
|
||||
end
|
||||
11
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/close75.rb
vendored
Normal file
11
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/close75.rb
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module Close75
|
||||
def close_websocket(code, body)
|
||||
@connection.close_connection_after_writing
|
||||
end
|
||||
|
||||
def supports_close_codes?; false; end
|
||||
end
|
||||
end
|
||||
end
|
||||
349
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/connection.rb
vendored
Normal file
349
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/connection.rb
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class Connection < EventMachine::Connection
|
||||
include Debugger
|
||||
|
||||
attr_writer :max_frame_size
|
||||
|
||||
# define WebSocket callbacks
|
||||
def onopen(&blk); @onopen = blk; end
|
||||
def onclose(&blk); @onclose = blk; end
|
||||
def onerror(&blk); @onerror = blk; end
|
||||
def onmessage(&blk); @onmessage = blk; end
|
||||
def onbinary(&blk); @onbinary = blk; end
|
||||
def onping(&blk); @onping = blk; end
|
||||
def onpong(&blk); @onpong = blk; end
|
||||
|
||||
def trigger_on_message(msg)
|
||||
@onmessage.call(msg) if defined? @onmessage
|
||||
end
|
||||
def trigger_on_binary(msg)
|
||||
@onbinary.call(msg) if defined? @onbinary
|
||||
end
|
||||
def trigger_on_open(handshake)
|
||||
@onopen.call(handshake) if defined? @onopen
|
||||
end
|
||||
def trigger_on_close(event = {})
|
||||
@onclose.call(event) if defined? @onclose
|
||||
end
|
||||
def trigger_on_ping(data)
|
||||
@onping.call(data) if defined? @onping
|
||||
end
|
||||
def trigger_on_pong(data)
|
||||
@onpong.call(data) if defined? @onpong
|
||||
end
|
||||
def trigger_on_error(reason)
|
||||
return false unless defined? @onerror
|
||||
@onerror.call(reason)
|
||||
true
|
||||
end
|
||||
|
||||
def initialize(options)
|
||||
@options = options
|
||||
@debug = options[:debug] || false
|
||||
@secure = options[:secure] || false
|
||||
@secure_proxy = options[:secure_proxy] || false
|
||||
@tls_options = options[:tls_options] || {}
|
||||
@close_timeout = options[:close_timeout]
|
||||
@outbound_limit = options[:outbound_limit] || 0
|
||||
|
||||
@handler = nil
|
||||
|
||||
debug [:initialize]
|
||||
end
|
||||
|
||||
# Use this method to close the websocket connection cleanly
|
||||
# This sends a close frame and waits for acknowlegement before closing
|
||||
# the connection
|
||||
def close(code = nil, body = nil)
|
||||
if code && !acceptable_close_code?(code)
|
||||
raise "Application code may only use codes from 1000, 3000-4999"
|
||||
end
|
||||
|
||||
close_websocket_private(code, body)
|
||||
end
|
||||
|
||||
# Deprecated, to be removed in version 0.6
|
||||
alias :close_websocket :close
|
||||
|
||||
def post_init
|
||||
start_tls(@tls_options) if @secure
|
||||
end
|
||||
|
||||
def receive_data(data)
|
||||
debug [:receive_data, data]
|
||||
|
||||
if @handler
|
||||
@handler.receive_data(data)
|
||||
else
|
||||
dispatch(data)
|
||||
end
|
||||
rescue => e
|
||||
debug [:error, e]
|
||||
|
||||
# There is no code defined for application errors, so use 3000
|
||||
# (which is reserved for frameworks)
|
||||
close_websocket_private(3000, "Application error")
|
||||
|
||||
# These are application errors - raise unless onerror defined
|
||||
trigger_on_error(e) || raise(e)
|
||||
end
|
||||
|
||||
def send_data(data)
|
||||
if @outbound_limit > 0 &&
|
||||
get_outbound_data_size + data.bytesize > @outbound_limit
|
||||
abort(:outbound_limit_reached)
|
||||
return 0
|
||||
end
|
||||
|
||||
super(data)
|
||||
end
|
||||
|
||||
def unbind
|
||||
debug [:unbind, :connection]
|
||||
|
||||
@handler.unbind if @handler
|
||||
rescue => e
|
||||
debug [:error, e]
|
||||
# These are application errors - raise unless onerror defined
|
||||
trigger_on_error(e) || raise(e)
|
||||
end
|
||||
|
||||
def dispatch(data)
|
||||
if data.match(%r|^GET /healthcheck|)
|
||||
send_healthcheck_response
|
||||
elsif data.match(/\A<policy-file-request\s*\/>/)
|
||||
send_flash_cross_domain_file
|
||||
else
|
||||
@handshake ||= begin
|
||||
handshake = Handshake.new(@secure || @secure_proxy)
|
||||
|
||||
handshake.callback { |upgrade_response, handler_klass|
|
||||
debug [:accepting_ws_version, handshake.protocol_version]
|
||||
debug [:upgrade_response, upgrade_response]
|
||||
self.send_data(upgrade_response)
|
||||
@handler = handler_klass.new(self, @debug)
|
||||
@handshake = nil
|
||||
trigger_on_open(handshake)
|
||||
}
|
||||
|
||||
handshake.errback { |e|
|
||||
debug [:error, e]
|
||||
trigger_on_error(e)
|
||||
# Handshake errors require the connection to be aborted
|
||||
abort(:handshake_error)
|
||||
}
|
||||
|
||||
handshake
|
||||
end
|
||||
|
||||
@handshake.receive_data(data)
|
||||
end
|
||||
end
|
||||
|
||||
def send_healthcheck_response
|
||||
debug [:healthcheck, 'OK']
|
||||
|
||||
healthcheck_res = ["HTTP/1.1 200 OK"]
|
||||
healthcheck_res << "Content-Type: text/plain"
|
||||
healthcheck_res << "Content-Length: 2"
|
||||
|
||||
healthcheck_res = healthcheck_res.join("\r\n") + "\r\n\r\nOK"
|
||||
|
||||
send_data healthcheck_res
|
||||
|
||||
# handle the healthcheck request transparently
|
||||
# no need to notify the user about this connection
|
||||
@onclose = nil
|
||||
close_connection_after_writing
|
||||
end
|
||||
|
||||
def send_flash_cross_domain_file
|
||||
file = '<?xml version="1.0"?><cross-domain-policy><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>'
|
||||
debug [:cross_domain, file]
|
||||
send_data file
|
||||
|
||||
# handle the cross-domain request transparently
|
||||
# no need to notify the user about this connection
|
||||
@onclose = nil
|
||||
close_connection_after_writing
|
||||
end
|
||||
|
||||
# Cache encodings since it's moderately expensive to look them up each time
|
||||
ENCODING_SUPPORTED = "string".respond_to?(:force_encoding)
|
||||
UTF8 = Encoding.find("UTF-8") if ENCODING_SUPPORTED
|
||||
BINARY = Encoding.find("BINARY") if ENCODING_SUPPORTED
|
||||
|
||||
# Send a WebSocket text frame.
|
||||
#
|
||||
# A WebSocketError may be raised if the connection is in an opening or a
|
||||
# closing state, or if the passed in data is not valid UTF-8
|
||||
#
|
||||
def send_text(data)
|
||||
# If we're using Ruby 1.9, be pedantic about encodings
|
||||
if ENCODING_SUPPORTED
|
||||
# Also accept ascii only data in other encodings for convenience
|
||||
unless (data.encoding == UTF8 && data.valid_encoding?) || data.ascii_only?
|
||||
raise WebSocketError, "Data sent to WebSocket must be valid UTF-8 but was #{data.encoding} (valid: #{data.valid_encoding?})"
|
||||
end
|
||||
# This labels the encoding as binary so that it can be combined with
|
||||
# the BINARY framing
|
||||
data.force_encoding(BINARY)
|
||||
else
|
||||
# TODO: Check that data is valid UTF-8
|
||||
end
|
||||
|
||||
if @handler
|
||||
@handler.send_text_frame(data)
|
||||
else
|
||||
raise WebSocketError, "Cannot send data before onopen callback"
|
||||
end
|
||||
|
||||
# Revert data back to the original encoding (which we assume is UTF-8)
|
||||
# Doing this to avoid duping the string - there may be a better way
|
||||
data.force_encoding(UTF8) if ENCODING_SUPPORTED
|
||||
return nil
|
||||
end
|
||||
|
||||
alias :send :send_text
|
||||
|
||||
# Send a WebSocket binary frame.
|
||||
#
|
||||
def send_binary(data)
|
||||
if @handler
|
||||
@handler.send_frame(:binary, data)
|
||||
else
|
||||
raise WebSocketError, "Cannot send binary before onopen callback"
|
||||
end
|
||||
end
|
||||
|
||||
# Send a ping to the client. The client must respond with a pong.
|
||||
#
|
||||
# In the case that the client is running a WebSocket draft < 01, false
|
||||
# is returned since ping & pong are not supported
|
||||
#
|
||||
def ping(body = '')
|
||||
if @handler
|
||||
@handler.pingable? ? @handler.send_frame(:ping, body) && true : false
|
||||
else
|
||||
raise WebSocketError, "Cannot ping before onopen callback"
|
||||
end
|
||||
end
|
||||
|
||||
# Send an unsolicited pong message, as allowed by the protocol. The
|
||||
# client is not expected to respond to this message.
|
||||
#
|
||||
# em-websocket automatically takes care of sending pong replies to
|
||||
# incoming ping messages, as the protocol demands.
|
||||
#
|
||||
def pong(body = '')
|
||||
if @handler
|
||||
@handler.pingable? ? @handler.send_frame(:pong, body) && true : false
|
||||
else
|
||||
raise WebSocketError, "Cannot ping before onopen callback"
|
||||
end
|
||||
end
|
||||
|
||||
# Test whether the connection is pingable (i.e. the WebSocket draft in
|
||||
# use is >= 01)
|
||||
def pingable?
|
||||
if @handler
|
||||
@handler.pingable?
|
||||
else
|
||||
raise WebSocketError, "Cannot test whether pingable before onopen callback"
|
||||
end
|
||||
end
|
||||
|
||||
def supports_close_codes?
|
||||
if @handler
|
||||
@handler.supports_close_codes?
|
||||
else
|
||||
raise WebSocketError, "Cannot test before onopen callback"
|
||||
end
|
||||
end
|
||||
|
||||
def state
|
||||
@handler ? @handler.state : :handshake
|
||||
end
|
||||
|
||||
# Returns the IP address for the remote peer
|
||||
def remote_ip
|
||||
get_peername[2,6].unpack('nC4')[1..4].join('.')
|
||||
end
|
||||
|
||||
# Returns the maximum frame size which this connection is configured to
|
||||
# accept. This can be set globally or on a per connection basis, and
|
||||
# defaults to a value of 10MB if not set.
|
||||
#
|
||||
# The behaviour when a too large frame is received varies by protocol,
|
||||
# but in the newest protocols the connection will be closed with the
|
||||
# correct close code (1009) immediately after receiving the frame header
|
||||
#
|
||||
def max_frame_size
|
||||
defined?(@max_frame_size) ? @max_frame_size : WebSocket.max_frame_size
|
||||
end
|
||||
|
||||
def close_timeout
|
||||
@close_timeout || WebSocket.close_timeout
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# As definited in draft 06 7.2.2, some failures require that the server
|
||||
# abort the websocket connection rather than close cleanly
|
||||
def abort(reason)
|
||||
debug [:abort, reason]
|
||||
close_connection
|
||||
end
|
||||
|
||||
def close_websocket_private(code, body)
|
||||
if @handler
|
||||
debug [:closing, code]
|
||||
@handler.close_websocket(code, body)
|
||||
else
|
||||
# The handshake hasn't completed - should be safe to terminate
|
||||
abort(:handshake_incomplete)
|
||||
end
|
||||
end
|
||||
|
||||
# Allow applications to close with 1000, 1003, 1008, 1011, 3xxx or 4xxx.
|
||||
#
|
||||
# em-websocket uses a few other codes internally which should not be
|
||||
# used by applications
|
||||
#
|
||||
# Browsers generally allow connections to be closed with code 1000,
|
||||
# 3xxx, and 4xxx. em-websocket allows closing with a few other codes
|
||||
# which seem reasonable (for discussion see
|
||||
# https://github.com/igrigorik/em-websocket/issues/98)
|
||||
#
|
||||
# Usage from the rfc:
|
||||
#
|
||||
# 1000 indicates a normal closure
|
||||
#
|
||||
# 1003 indicates that an endpoint is terminating the connection
|
||||
# because it has received a type of data it cannot accept
|
||||
#
|
||||
# 1008 indicates that an endpoint is terminating the connection because
|
||||
# it has received a message that violates its policy
|
||||
#
|
||||
# 1011 indicates that a server is terminating the connection because it
|
||||
# encountered an unexpected condition that prevented it from fulfilling
|
||||
# the request
|
||||
#
|
||||
# Status codes in the range 3000-3999 are reserved for use by libraries,
|
||||
# frameworks, and applications
|
||||
#
|
||||
# Status codes in the range 4000-4999 are reserved for private use and
|
||||
# thus can't be registered
|
||||
#
|
||||
def acceptable_close_code?(code)
|
||||
case code
|
||||
when 1000, 1003, 1008, 1011, (3000..4999)
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
17
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/debugger.rb
vendored
Normal file
17
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/debugger.rb
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module Debugger
|
||||
|
||||
private
|
||||
|
||||
def debug(*data)
|
||||
if @debug
|
||||
require 'pp'
|
||||
pp data
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
162
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/framing03.rb
vendored
Normal file
162
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/framing03.rb
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
# encoding: BINARY
|
||||
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module Framing03
|
||||
def initialize_framing
|
||||
@data = ''
|
||||
@application_data_buffer = '' # Used for MORE frames
|
||||
@frame_type = nil
|
||||
end
|
||||
|
||||
def process_data
|
||||
error = false
|
||||
|
||||
while !error && @data.size > 1
|
||||
pointer = 0
|
||||
|
||||
more = ((@data.getbyte(pointer) & 0b10000000) == 0b10000000) ^ fin
|
||||
# Ignoring rsv1-3 for now
|
||||
opcode = @data.getbyte(0) & 0b00001111
|
||||
pointer += 1
|
||||
|
||||
# Ignoring rsv4
|
||||
length = @data.getbyte(pointer) & 0b01111111
|
||||
pointer += 1
|
||||
|
||||
payload_length = case length
|
||||
when 127 # Length defined by 8 bytes
|
||||
# Check buffer size
|
||||
if @data.getbyte(pointer+8-1) == nil
|
||||
debug [:buffer_incomplete, @data]
|
||||
error = true
|
||||
next
|
||||
end
|
||||
|
||||
# Only using the last 4 bytes for now, till I work out how to
|
||||
# unpack 8 bytes. I'm sure 4GB frames will do for now :)
|
||||
l = @data[(pointer+4)..(pointer+7)].unpack('N').first
|
||||
pointer += 8
|
||||
l
|
||||
when 126 # Length defined by 2 bytes
|
||||
# Check buffer size
|
||||
if @data.getbyte(pointer+2-1) == nil
|
||||
debug [:buffer_incomplete, @data]
|
||||
error = true
|
||||
next
|
||||
end
|
||||
|
||||
l = @data[pointer..(pointer+1)].unpack('n').first
|
||||
pointer += 2
|
||||
l
|
||||
else
|
||||
length
|
||||
end
|
||||
|
||||
if payload_length > @connection.max_frame_size
|
||||
raise WSMessageTooBigError, "Frame length too long (#{payload_length} bytes)"
|
||||
end
|
||||
|
||||
# Check buffer size
|
||||
if @data.getbyte(pointer+payload_length-1) == nil
|
||||
debug [:buffer_incomplete, @data]
|
||||
error = true
|
||||
next
|
||||
end
|
||||
|
||||
# Throw away data up to pointer
|
||||
@data.slice!(0...pointer)
|
||||
|
||||
# Read application data
|
||||
application_data = @data.slice!(0...payload_length)
|
||||
|
||||
frame_type = opcode_to_type(opcode)
|
||||
|
||||
if frame_type == :continuation && !@frame_type
|
||||
raise WSProtocolError, 'Continuation frame not expected'
|
||||
end
|
||||
|
||||
if more
|
||||
debug [:moreframe, frame_type, application_data]
|
||||
@application_data_buffer << application_data
|
||||
# The message type is passed in the first frame
|
||||
@frame_type ||= frame_type
|
||||
else
|
||||
# Message is complete
|
||||
if frame_type == :continuation
|
||||
@application_data_buffer << application_data
|
||||
message(@frame_type, '', @application_data_buffer)
|
||||
@application_data_buffer = ''
|
||||
@frame_type = nil
|
||||
else
|
||||
message(frame_type, '', application_data)
|
||||
end
|
||||
end
|
||||
end # end while
|
||||
end
|
||||
|
||||
def send_frame(frame_type, application_data)
|
||||
debug [:sending_frame, frame_type, application_data]
|
||||
|
||||
if @state == :closing && data_frame?(frame_type)
|
||||
raise WebSocketError, "Cannot send data frame since connection is closing"
|
||||
end
|
||||
|
||||
frame = ''
|
||||
|
||||
opcode = type_to_opcode(frame_type)
|
||||
byte1 = opcode # since more, rsv1-3 are 0
|
||||
frame << byte1
|
||||
|
||||
length = application_data.size
|
||||
if length <= 125
|
||||
byte2 = length # since rsv4 is 0
|
||||
frame << byte2
|
||||
elsif length < 65536 # write 2 byte length
|
||||
frame << 126
|
||||
frame << [length].pack('n')
|
||||
else # write 8 byte length
|
||||
frame << 127
|
||||
frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
|
||||
end
|
||||
|
||||
frame << application_data
|
||||
|
||||
@connection.send_data(frame)
|
||||
end
|
||||
|
||||
def send_text_frame(data)
|
||||
send_frame(:text, data)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# This allows flipping the more bit to fin for draft 04
|
||||
def fin; false; end
|
||||
|
||||
FRAME_TYPES = {
|
||||
:continuation => 0,
|
||||
:close => 1,
|
||||
:ping => 2,
|
||||
:pong => 3,
|
||||
:text => 4,
|
||||
:binary => 5
|
||||
}
|
||||
FRAME_TYPES_INVERSE = FRAME_TYPES.invert
|
||||
# Frames are either data frames or control frames
|
||||
DATA_FRAMES = [:text, :binary, :continuation]
|
||||
|
||||
def type_to_opcode(frame_type)
|
||||
FRAME_TYPES[frame_type] || raise("Unknown frame type")
|
||||
end
|
||||
|
||||
def opcode_to_type(opcode)
|
||||
FRAME_TYPES_INVERSE[opcode] || raise(WSProtocolError, "Unknown opcode #{opcode}")
|
||||
end
|
||||
|
||||
def data_frame?(type)
|
||||
DATA_FRAMES.include?(type)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
15
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/framing04.rb
vendored
Normal file
15
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/framing04.rb
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# encoding: BINARY
|
||||
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
# The only difference between draft 03 framing and draft 04 framing is
|
||||
# that the MORE bit has been changed to a FIN bit
|
||||
module Framing04
|
||||
include Framing03
|
||||
|
||||
private
|
||||
|
||||
def fin; true; end
|
||||
end
|
||||
end
|
||||
end
|
||||
163
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/framing05.rb
vendored
Normal file
163
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/framing05.rb
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
# encoding: BINARY
|
||||
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module Framing05
|
||||
def initialize_framing
|
||||
@data = MaskedString.new
|
||||
@application_data_buffer = '' # Used for MORE frames
|
||||
@frame_type = nil
|
||||
end
|
||||
|
||||
def process_data
|
||||
error = false
|
||||
|
||||
while !error && @data.size > 5 # mask plus first byte present
|
||||
pointer = 0
|
||||
|
||||
@data.read_mask
|
||||
pointer += 4
|
||||
|
||||
fin = (@data.getbyte(pointer) & 0b10000000) == 0b10000000
|
||||
# Ignoring rsv1-3 for now
|
||||
opcode = @data.getbyte(pointer) & 0b00001111
|
||||
pointer += 1
|
||||
|
||||
# Ignoring rsv4
|
||||
length = @data.getbyte(pointer) & 0b01111111
|
||||
pointer += 1
|
||||
|
||||
payload_length = case length
|
||||
when 127 # Length defined by 8 bytes
|
||||
# Check buffer size
|
||||
if @data.getbyte(pointer+8-1) == nil
|
||||
debug [:buffer_incomplete, @data]
|
||||
error = true
|
||||
next
|
||||
end
|
||||
|
||||
# Only using the last 4 bytes for now, till I work out how to
|
||||
# unpack 8 bytes. I'm sure 4GB frames will do for now :)
|
||||
l = @data.getbytes(pointer+4, 4).unpack('N').first
|
||||
pointer += 8
|
||||
l
|
||||
when 126 # Length defined by 2 bytes
|
||||
# Check buffer size
|
||||
if @data.getbyte(pointer+2-1) == nil
|
||||
debug [:buffer_incomplete, @data]
|
||||
error = true
|
||||
next
|
||||
end
|
||||
|
||||
l = @data.getbytes(pointer, 2).unpack('n').first
|
||||
pointer += 2
|
||||
l
|
||||
else
|
||||
length
|
||||
end
|
||||
|
||||
if payload_length > @connection.max_frame_size
|
||||
raise WSMessageTooBigError, "Frame length too long (#{payload_length} bytes)"
|
||||
end
|
||||
|
||||
# Check buffer size
|
||||
if @data.getbyte(pointer+payload_length-1) == nil
|
||||
debug [:buffer_incomplete, @data]
|
||||
error = true
|
||||
next
|
||||
end
|
||||
|
||||
# Read application data
|
||||
application_data = @data.getbytes(pointer, payload_length)
|
||||
pointer += payload_length
|
||||
|
||||
# Throw away data up to pointer
|
||||
@data.unset_mask
|
||||
@data.slice!(0...pointer)
|
||||
|
||||
frame_type = opcode_to_type(opcode)
|
||||
|
||||
if frame_type == :continuation && !@frame_type
|
||||
raise WSProtocolError, 'Continuation frame not expected'
|
||||
end
|
||||
|
||||
if !fin
|
||||
debug [:moreframe, frame_type, application_data]
|
||||
@application_data_buffer << application_data
|
||||
@frame_type = frame_type
|
||||
else
|
||||
# Message is complete
|
||||
if frame_type == :continuation
|
||||
@application_data_buffer << application_data
|
||||
message(@frame_type, '', @application_data_buffer)
|
||||
@application_data_buffer = ''
|
||||
@frame_type = nil
|
||||
else
|
||||
message(frame_type, '', application_data)
|
||||
end
|
||||
end
|
||||
end # end while
|
||||
end
|
||||
|
||||
def send_frame(frame_type, application_data)
|
||||
debug [:sending_frame, frame_type, application_data]
|
||||
|
||||
if @state == :closing && data_frame?(frame_type)
|
||||
raise WebSocketError, "Cannot send data frame since connection is closing"
|
||||
end
|
||||
|
||||
frame = ''
|
||||
|
||||
opcode = type_to_opcode(frame_type)
|
||||
byte1 = opcode | 0b10000000 # fin bit set, rsv1-3 are 0
|
||||
frame << byte1
|
||||
|
||||
length = application_data.size
|
||||
if length <= 125
|
||||
byte2 = length # since rsv4 is 0
|
||||
frame << byte2
|
||||
elsif length < 65536 # write 2 byte length
|
||||
frame << 126
|
||||
frame << [length].pack('n')
|
||||
else # write 8 byte length
|
||||
frame << 127
|
||||
frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
|
||||
end
|
||||
|
||||
frame << application_data
|
||||
|
||||
@connection.send_data(frame)
|
||||
end
|
||||
|
||||
def send_text_frame(data)
|
||||
send_frame(:text, data)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
FRAME_TYPES = {
|
||||
:continuation => 0,
|
||||
:close => 1,
|
||||
:ping => 2,
|
||||
:pong => 3,
|
||||
:text => 4,
|
||||
:binary => 5
|
||||
}
|
||||
FRAME_TYPES_INVERSE = FRAME_TYPES.invert
|
||||
# Frames are either data frames or control frames
|
||||
DATA_FRAMES = [:text, :binary, :continuation]
|
||||
|
||||
def type_to_opcode(frame_type)
|
||||
FRAME_TYPES[frame_type] || raise("Unknown frame type")
|
||||
end
|
||||
|
||||
def opcode_to_type(opcode)
|
||||
FRAME_TYPES_INVERSE[opcode] || raise(WSProtocolError, "Unknown opcode #{opcode}")
|
||||
end
|
||||
|
||||
def data_frame?(type)
|
||||
DATA_FRAMES.include?(type)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
185
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/framing07.rb
vendored
Normal file
185
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/framing07.rb
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
# encoding: BINARY
|
||||
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module Framing07
|
||||
|
||||
def initialize_framing
|
||||
@data = MaskedString.new
|
||||
@application_data_buffer = '' # Used for MORE frames
|
||||
@frame_type = nil
|
||||
end
|
||||
|
||||
def process_data
|
||||
error = false
|
||||
|
||||
while !error && @data.size >= 2
|
||||
pointer = 0
|
||||
|
||||
fin = (@data.getbyte(pointer) & 0b10000000) == 0b10000000
|
||||
# Ignoring rsv1-3 for now
|
||||
opcode = @data.getbyte(pointer) & 0b00001111
|
||||
pointer += 1
|
||||
|
||||
mask = (@data.getbyte(pointer) & 0b10000000) == 0b10000000
|
||||
length = @data.getbyte(pointer) & 0b01111111
|
||||
pointer += 1
|
||||
|
||||
# raise WebSocketError, 'Data from client must be masked' unless mask
|
||||
|
||||
payload_length = case length
|
||||
when 127 # Length defined by 8 bytes
|
||||
# Check buffer size
|
||||
if @data.getbyte(pointer+8-1) == nil
|
||||
debug [:buffer_incomplete, @data]
|
||||
error = true
|
||||
next
|
||||
end
|
||||
|
||||
# Only using the last 4 bytes for now, till I work out how to
|
||||
# unpack 8 bytes. I'm sure 4GB frames will do for now :)
|
||||
l = @data.getbytes(pointer+4, 4).unpack('N').first
|
||||
pointer += 8
|
||||
l
|
||||
when 126 # Length defined by 2 bytes
|
||||
# Check buffer size
|
||||
if @data.getbyte(pointer+2-1) == nil
|
||||
debug [:buffer_incomplete, @data]
|
||||
error = true
|
||||
next
|
||||
end
|
||||
|
||||
l = @data.getbytes(pointer, 2).unpack('n').first
|
||||
pointer += 2
|
||||
l
|
||||
else
|
||||
length
|
||||
end
|
||||
|
||||
# Compute the expected frame length
|
||||
frame_length = pointer + payload_length
|
||||
frame_length += 4 if mask
|
||||
|
||||
if frame_length > @connection.max_frame_size
|
||||
raise WSMessageTooBigError, "Frame length too long (#{frame_length} bytes)"
|
||||
end
|
||||
|
||||
# Check buffer size
|
||||
if @data.getbyte(frame_length - 1) == nil
|
||||
debug [:buffer_incomplete, @data]
|
||||
error = true
|
||||
next
|
||||
end
|
||||
|
||||
# Remove frame header
|
||||
@data.slice!(0...pointer)
|
||||
pointer = 0
|
||||
|
||||
# Read application data (unmasked if required)
|
||||
@data.read_mask if mask
|
||||
pointer += 4 if mask
|
||||
application_data = @data.getbytes(pointer, payload_length)
|
||||
pointer += payload_length
|
||||
@data.unset_mask if mask
|
||||
|
||||
# Throw away data up to pointer
|
||||
@data.slice!(0...pointer)
|
||||
|
||||
frame_type = opcode_to_type(opcode)
|
||||
|
||||
if frame_type == :continuation
|
||||
if !@frame_type
|
||||
raise WSProtocolError, 'Continuation frame not expected'
|
||||
end
|
||||
else # Not a continuation frame
|
||||
if @frame_type && data_frame?(frame_type)
|
||||
raise WSProtocolError, "Continuation frame expected"
|
||||
end
|
||||
end
|
||||
|
||||
# Validate that control frames are not fragmented
|
||||
if !fin && !data_frame?(frame_type)
|
||||
raise WSProtocolError, 'Control frames must not be fragmented'
|
||||
end
|
||||
|
||||
if !fin
|
||||
debug [:moreframe, frame_type, application_data]
|
||||
@application_data_buffer << application_data
|
||||
# The message type is passed in the first frame
|
||||
@frame_type ||= frame_type
|
||||
else
|
||||
# Message is complete
|
||||
if frame_type == :continuation
|
||||
@application_data_buffer << application_data
|
||||
message(@frame_type, '', @application_data_buffer)
|
||||
@application_data_buffer = ''
|
||||
@frame_type = nil
|
||||
else
|
||||
message(frame_type, '', application_data)
|
||||
end
|
||||
end
|
||||
end # end while
|
||||
end
|
||||
|
||||
def send_frame(frame_type, application_data)
|
||||
debug [:sending_frame, frame_type, application_data]
|
||||
|
||||
if @state == :closing && data_frame?(frame_type)
|
||||
raise WebSocketError, "Cannot send data frame since connection is closing"
|
||||
end
|
||||
|
||||
frame = ''
|
||||
|
||||
opcode = type_to_opcode(frame_type)
|
||||
byte1 = opcode | 0b10000000 # fin bit set, rsv1-3 are 0
|
||||
frame << byte1
|
||||
|
||||
length = application_data.size
|
||||
if length <= 125
|
||||
byte2 = length # since rsv4 is 0
|
||||
frame << byte2
|
||||
elsif length < 65536 # write 2 byte length
|
||||
frame << 126
|
||||
frame << [length].pack('n')
|
||||
else # write 8 byte length
|
||||
frame << 127
|
||||
frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
|
||||
end
|
||||
|
||||
frame << application_data
|
||||
|
||||
@connection.send_data(frame)
|
||||
end
|
||||
|
||||
def send_text_frame(data)
|
||||
send_frame(:text, data)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
FRAME_TYPES = {
|
||||
:continuation => 0,
|
||||
:text => 1,
|
||||
:binary => 2,
|
||||
:close => 8,
|
||||
:ping => 9,
|
||||
:pong => 10,
|
||||
}
|
||||
FRAME_TYPES_INVERSE = FRAME_TYPES.invert
|
||||
# Frames are either data frames or control frames
|
||||
DATA_FRAMES = [:text, :binary, :continuation]
|
||||
|
||||
def type_to_opcode(frame_type)
|
||||
FRAME_TYPES[frame_type] || raise("Unknown frame type")
|
||||
end
|
||||
|
||||
def opcode_to_type(opcode)
|
||||
FRAME_TYPES_INVERSE[opcode] || raise(WSProtocolError, "Unknown opcode #{opcode}")
|
||||
end
|
||||
|
||||
def data_frame?(type)
|
||||
DATA_FRAMES.include?(type)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
105
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/framing76.rb
vendored
Normal file
105
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/framing76.rb
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
# encoding: BINARY
|
||||
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module Framing76
|
||||
def initialize_framing
|
||||
@data = ''
|
||||
end
|
||||
|
||||
def process_data
|
||||
debug [:message, @data]
|
||||
|
||||
# This algorithm comes straight from the spec
|
||||
# http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#section-5.3
|
||||
|
||||
error = false
|
||||
|
||||
while !error
|
||||
return if @data.size == 0
|
||||
|
||||
pointer = 0
|
||||
frame_type = @data.getbyte(pointer)
|
||||
pointer += 1
|
||||
|
||||
if (frame_type & 0x80) == 0x80
|
||||
# If the high-order bit of the /frame type/ byte is set
|
||||
length = 0
|
||||
|
||||
loop do
|
||||
return false if !@data.getbyte(pointer)
|
||||
b = @data.getbyte(pointer)
|
||||
pointer += 1
|
||||
b_v = b & 0x7F
|
||||
length = length * 128 + b_v
|
||||
break unless (b & 0x80) == 0x80
|
||||
end
|
||||
|
||||
if length > @connection.max_frame_size
|
||||
raise WSMessageTooBigError, "Frame length too long (#{length} bytes)"
|
||||
end
|
||||
|
||||
if @data.getbyte(pointer+length-1) == nil
|
||||
debug [:buffer_incomplete, @data]
|
||||
# Incomplete data - leave @data to accumulate
|
||||
error = true
|
||||
else
|
||||
# Straight from spec - I'm sure this isn't crazy...
|
||||
# 6. Read /length/ bytes.
|
||||
# 7. Discard the read bytes.
|
||||
@data = @data[(pointer+length)..-1]
|
||||
|
||||
# If the /frame type/ is 0xFF and the /length/ was 0, then close
|
||||
if length == 0
|
||||
@connection.send_data("\xff\x00")
|
||||
@state = :closing
|
||||
@connection.close_connection_after_writing
|
||||
else
|
||||
error = true
|
||||
end
|
||||
end
|
||||
else
|
||||
# If the high-order bit of the /frame type/ byte is _not_ set
|
||||
|
||||
if @data.getbyte(0) != 0x00
|
||||
# Close the connection since this buffer can never match
|
||||
raise WSProtocolError, "Invalid frame received"
|
||||
end
|
||||
|
||||
# Addition to the spec to protect against malicious requests
|
||||
if @data.size > @connection.max_frame_size
|
||||
raise WSMessageTooBigError, "Frame length too long (#{@data.size} bytes)"
|
||||
end
|
||||
|
||||
msg = @data.slice!(/\A\x00[^\xff]*\xff/)
|
||||
if msg
|
||||
msg.gsub!(/\A\x00|\xff\z/, '')
|
||||
if @state == :closing
|
||||
debug [:ignored_message, msg]
|
||||
else
|
||||
msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding)
|
||||
@connection.trigger_on_message(msg)
|
||||
end
|
||||
else
|
||||
error = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
# frames need to start with 0x00-0x7f byte and end with
|
||||
# an 0xFF byte. Per spec, we can also set the first
|
||||
# byte to a value betweent 0x80 and 0xFF, followed by
|
||||
# a leading length indicator
|
||||
def send_text_frame(data)
|
||||
debug [:sending_text_frame, data]
|
||||
ary = ["\x00", data, "\xff"]
|
||||
ary.collect{ |s| s.force_encoding('UTF-8') if s.respond_to?(:force_encoding) }
|
||||
@connection.send_data(ary.join)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
97
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler.rb
vendored
Normal file
97
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler.rb
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class Handler
|
||||
def self.klass_factory(version)
|
||||
case version
|
||||
when 75
|
||||
Handler75
|
||||
when 76
|
||||
Handler76
|
||||
when 1..3
|
||||
# We'll use handler03 - I believe they're all compatible
|
||||
Handler03
|
||||
when 5
|
||||
Handler05
|
||||
when 6
|
||||
Handler06
|
||||
when 7
|
||||
Handler07
|
||||
when 8
|
||||
# drafts 9, 10, 11 and 12 should never change the version
|
||||
# number as they are all the same as version 08.
|
||||
Handler08
|
||||
when 13
|
||||
# drafts 13 to 17 all identify as version 13 as they are
|
||||
# only minor changes or text changes.
|
||||
Handler13
|
||||
else
|
||||
# According to spec should abort the connection
|
||||
raise HandshakeError, "Protocol version #{version} not supported"
|
||||
end
|
||||
end
|
||||
|
||||
include Debugger
|
||||
|
||||
attr_reader :request, :state
|
||||
|
||||
def initialize(connection, debug = false)
|
||||
@connection = connection
|
||||
@debug = debug
|
||||
@state = :connected
|
||||
@close_timer = nil
|
||||
initialize_framing
|
||||
end
|
||||
|
||||
def receive_data(data)
|
||||
@data << data
|
||||
process_data
|
||||
rescue WSProtocolError => e
|
||||
fail_websocket(e)
|
||||
end
|
||||
|
||||
def close_websocket(code, body)
|
||||
# Implemented in subclass
|
||||
end
|
||||
|
||||
# Used to avoid un-acked and unclosed remaining open indefinitely
|
||||
def start_close_timeout
|
||||
@close_timer = EM::Timer.new(@connection.close_timeout) {
|
||||
@connection.close_connection
|
||||
e = WSProtocolError.new("Close handshake un-acked after #{@connection.close_timeout}s, closing tcp connection")
|
||||
@connection.trigger_on_error(e)
|
||||
}
|
||||
end
|
||||
|
||||
# This corresponds to "Fail the WebSocket Connection" in the spec.
|
||||
def fail_websocket(e)
|
||||
debug [:error, e]
|
||||
close_websocket(e.code, e.message)
|
||||
@connection.close_connection_after_writing
|
||||
@connection.trigger_on_error(e)
|
||||
end
|
||||
|
||||
def unbind
|
||||
@state = :closed
|
||||
|
||||
@close_timer.cancel if @close_timer
|
||||
|
||||
@close_info = defined?(@close_info) ? @close_info : {
|
||||
:code => 1006,
|
||||
:was_clean => false,
|
||||
}
|
||||
|
||||
@connection.trigger_on_close(@close_info)
|
||||
end
|
||||
|
||||
def ping
|
||||
# Overridden in subclass
|
||||
false
|
||||
end
|
||||
|
||||
def pingable?
|
||||
# Also Overridden
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler03.rb
vendored
Normal file
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler03.rb
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class Handler03 < Handler
|
||||
include Framing03
|
||||
include MessageProcessor03
|
||||
include Close03
|
||||
end
|
||||
end
|
||||
end
|
||||
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler05.rb
vendored
Normal file
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler05.rb
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class Handler05 < Handler
|
||||
include Framing05
|
||||
include MessageProcessor03
|
||||
include Close05
|
||||
end
|
||||
end
|
||||
end
|
||||
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler06.rb
vendored
Normal file
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler06.rb
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class Handler06 < Handler
|
||||
include Framing05
|
||||
include MessageProcessor06
|
||||
include Close06
|
||||
end
|
||||
end
|
||||
end
|
||||
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler07.rb
vendored
Normal file
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler07.rb
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class Handler07 < Handler
|
||||
include Framing07
|
||||
include MessageProcessor06
|
||||
include Close06
|
||||
end
|
||||
end
|
||||
end
|
||||
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler08.rb
vendored
Normal file
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler08.rb
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class Handler08 < Handler
|
||||
include Framing07
|
||||
include MessageProcessor06
|
||||
include Close06
|
||||
end
|
||||
end
|
||||
end
|
||||
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler13.rb
vendored
Normal file
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler13.rb
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class Handler13 < Handler
|
||||
include Framing07
|
||||
include MessageProcessor06
|
||||
include Close06
|
||||
end
|
||||
end
|
||||
end
|
||||
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler75.rb
vendored
Normal file
9
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler75.rb
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class Handler75 < Handler
|
||||
include Handshake75
|
||||
include Framing76
|
||||
include Close75
|
||||
end
|
||||
end
|
||||
end
|
||||
14
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler76.rb
vendored
Normal file
14
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handler76.rb
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# encoding: BINARY
|
||||
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class Handler76 < Handler
|
||||
include Handshake76
|
||||
include Framing76
|
||||
include Close75
|
||||
|
||||
# "\377\000" is octet version and "\xff\x00" is hex version
|
||||
TERMINATE_STRING = "\xff\x00"
|
||||
end
|
||||
end
|
||||
end
|
||||
156
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handshake.rb
vendored
Normal file
156
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handshake.rb
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
require "http/parser"
|
||||
require "uri"
|
||||
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
|
||||
# Resposible for creating the server handshake response
|
||||
class Handshake
|
||||
include EM::Deferrable
|
||||
|
||||
attr_reader :parser, :protocol_version
|
||||
|
||||
# Unfortunately drafts 75 & 76 require knowledge of whether the
|
||||
# connection is being terminated as ws/wss in order to generate the
|
||||
# correct handshake response
|
||||
def initialize(secure)
|
||||
@parser = Http::Parser.new
|
||||
@secure = secure
|
||||
|
||||
@parser.on_headers_complete = proc { |headers|
|
||||
@headers = Hash[headers.map { |k,v| [k.downcase, v] }]
|
||||
}
|
||||
end
|
||||
|
||||
def receive_data(data)
|
||||
@parser << data
|
||||
|
||||
if defined? @headers
|
||||
process(@headers, @parser.upgrade_data)
|
||||
end
|
||||
rescue HTTP::Parser::Error => e
|
||||
fail(HandshakeError.new("Invalid HTTP header: #{e.message}"))
|
||||
end
|
||||
|
||||
# Returns the WebSocket upgrade headers as a hash.
|
||||
#
|
||||
# Keys are strings, unmodified from the request.
|
||||
#
|
||||
def headers
|
||||
@parser.headers
|
||||
end
|
||||
|
||||
# The same as headers, except that the hash keys are downcased
|
||||
#
|
||||
def headers_downcased
|
||||
@headers
|
||||
end
|
||||
|
||||
# Returns the request path (excluding any query params)
|
||||
#
|
||||
def path
|
||||
@path
|
||||
end
|
||||
|
||||
# Returns the query params as a string foo=bar&baz=...
|
||||
def query_string
|
||||
@query_string
|
||||
end
|
||||
|
||||
def query
|
||||
Hash[query_string.split('&').map { |c| c.split('=', 2) }]
|
||||
end
|
||||
|
||||
# Returns the WebSocket origin header if provided
|
||||
#
|
||||
def origin
|
||||
@headers["origin"] || @headers["sec-websocket-origin"] || nil
|
||||
end
|
||||
|
||||
def secure?
|
||||
@secure
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process(headers, remains)
|
||||
unless @parser.http_method == "GET"
|
||||
raise HandshakeError, "Must be GET request"
|
||||
end
|
||||
|
||||
# Validate request path
|
||||
#
|
||||
# According to http://tools.ietf.org/search/rfc2616#section-5.1.2, an
|
||||
# invalid Request-URI should result in a 400 status code, but
|
||||
# HandshakeError's currently result in a WebSocket abort. It's not
|
||||
# clear which should take precedence, but an abort will do just fine.
|
||||
begin
|
||||
uri = URI.parse(@parser.request_url)
|
||||
@path = uri.path
|
||||
@query_string = uri.query || ""
|
||||
rescue URI::InvalidURIError
|
||||
raise HandshakeError, "Invalid request URI: #{@parser.request_url}"
|
||||
end
|
||||
|
||||
# Validate Upgrade
|
||||
unless @parser.upgrade?
|
||||
raise HandshakeError, "Not an upgrade request"
|
||||
end
|
||||
upgrade = @headers['upgrade']
|
||||
unless upgrade.kind_of?(String) && upgrade.downcase == 'websocket'
|
||||
raise HandshakeError, "Invalid upgrade header: #{upgrade.inspect}"
|
||||
end
|
||||
|
||||
# Determine version heuristically
|
||||
version = if @headers['sec-websocket-version']
|
||||
# Used from drafts 04 onwards
|
||||
@headers['sec-websocket-version'].to_i
|
||||
elsif @headers['sec-websocket-draft']
|
||||
# Used in drafts 01 - 03
|
||||
@headers['sec-websocket-draft'].to_i
|
||||
elsif @headers['sec-websocket-key1']
|
||||
76
|
||||
else
|
||||
75
|
||||
end
|
||||
|
||||
# Additional handling of bytes after the header if required
|
||||
case version
|
||||
when 75
|
||||
if !remains.empty?
|
||||
raise HandshakeError, "Extra bytes after header"
|
||||
end
|
||||
when 76, 1..3
|
||||
if remains.length < 8
|
||||
# The whole third-key has not been received yet.
|
||||
return nil
|
||||
elsif remains.length > 8
|
||||
raise HandshakeError, "Extra bytes after third key"
|
||||
end
|
||||
@headers['third-key'] = remains
|
||||
end
|
||||
|
||||
handshake_klass = case version
|
||||
when 75
|
||||
Handshake75
|
||||
when 76, 1..3
|
||||
Handshake76
|
||||
when 5, 6, 7, 8, 13
|
||||
Handshake04
|
||||
else
|
||||
# According to spec should abort the connection
|
||||
raise HandshakeError, "Protocol version #{version} not supported"
|
||||
end
|
||||
|
||||
upgrade_response = handshake_klass.handshake(@headers, @parser.request_url, @secure)
|
||||
|
||||
handler_klass = Handler.klass_factory(version)
|
||||
|
||||
@protocol_version = version
|
||||
succeed(upgrade_response, handler_klass)
|
||||
rescue HandshakeError => e
|
||||
fail(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
37
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handshake04.rb
vendored
Normal file
37
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handshake04.rb
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
require 'digest/sha1'
|
||||
require 'base64'
|
||||
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module Handshake04
|
||||
def self.handshake(headers, _, __)
|
||||
# Required
|
||||
unless key = headers['sec-websocket-key']
|
||||
raise HandshakeError, "sec-websocket-key header is required"
|
||||
end
|
||||
|
||||
string_to_sign = "#{key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
signature = Base64.encode64(Digest::SHA1.digest(string_to_sign)).chomp
|
||||
|
||||
upgrade = ["HTTP/1.1 101 Switching Protocols"]
|
||||
upgrade << "Upgrade: websocket"
|
||||
upgrade << "Connection: Upgrade"
|
||||
upgrade << "Sec-WebSocket-Accept: #{signature}"
|
||||
if protocol = headers['sec-websocket-protocol']
|
||||
validate_protocol!(protocol)
|
||||
upgrade << "Sec-WebSocket-Protocol: #{protocol}"
|
||||
end
|
||||
|
||||
# TODO: Support sec-websocket-protocol selection
|
||||
# TODO: sec-websocket-extensions
|
||||
|
||||
return upgrade.join("\r\n") + "\r\n\r\n"
|
||||
end
|
||||
|
||||
def self.validate_protocol!(protocol)
|
||||
raise HandshakeError, "Invalid WebSocket-Protocol: empty" if protocol.empty?
|
||||
# TODO: Validate characters
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
28
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handshake75.rb
vendored
Normal file
28
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handshake75.rb
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module Handshake75
|
||||
def self.handshake(headers, path, secure)
|
||||
scheme = (secure ? "wss" : "ws")
|
||||
location = "#{scheme}://#{headers['host']}#{path}"
|
||||
|
||||
upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
|
||||
upgrade << "Upgrade: WebSocket\r\n"
|
||||
upgrade << "Connection: Upgrade\r\n"
|
||||
upgrade << "WebSocket-Origin: #{headers['origin']}\r\n"
|
||||
upgrade << "WebSocket-Location: #{location}\r\n"
|
||||
if protocol = headers['sec-websocket-protocol']
|
||||
validate_protocol!(protocol)
|
||||
upgrade << "Sec-WebSocket-Protocol: #{protocol}\r\n"
|
||||
end
|
||||
upgrade << "\r\n"
|
||||
|
||||
return upgrade
|
||||
end
|
||||
|
||||
def self.validate_protocol!(protocol)
|
||||
raise HandshakeError, "Invalid WebSocket-Protocol: empty" if protocol.empty?
|
||||
# TODO: Validate characters
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
72
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handshake76.rb
vendored
Normal file
72
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/handshake76.rb
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
require 'digest/md5'
|
||||
|
||||
module EventMachine::WebSocket
|
||||
module Handshake76
|
||||
class << self
|
||||
def handshake(headers, path, secure)
|
||||
challenge_response = solve_challenge(
|
||||
headers['sec-websocket-key1'],
|
||||
headers['sec-websocket-key2'],
|
||||
headers['third-key']
|
||||
)
|
||||
|
||||
scheme = (secure ? "wss" : "ws")
|
||||
location = "#{scheme}://#{headers['host']}#{path}"
|
||||
|
||||
upgrade = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
|
||||
upgrade << "Upgrade: WebSocket\r\n"
|
||||
upgrade << "Connection: Upgrade\r\n"
|
||||
upgrade << "Sec-WebSocket-Location: #{location}\r\n"
|
||||
upgrade << "Sec-WebSocket-Origin: #{headers['origin']}\r\n"
|
||||
if protocol = headers['sec-websocket-protocol']
|
||||
validate_protocol!(protocol)
|
||||
upgrade << "Sec-WebSocket-Protocol: #{protocol}\r\n"
|
||||
end
|
||||
upgrade << "\r\n"
|
||||
upgrade << challenge_response
|
||||
|
||||
return upgrade
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def solve_challenge(first, second, third)
|
||||
# Refer to 5.2 4-9 of the draft 76
|
||||
sum = [numbers_over_spaces(first)].pack("N*") +
|
||||
[numbers_over_spaces(second)].pack("N*") +
|
||||
third
|
||||
Digest::MD5.digest(sum)
|
||||
end
|
||||
|
||||
def numbers_over_spaces(string)
|
||||
unless string
|
||||
raise HandshakeError, "WebSocket key1 or key2 is missing"
|
||||
end
|
||||
|
||||
numbers = string.scan(/[0-9]/).join.to_i
|
||||
|
||||
spaces = string.scan(/ /).size
|
||||
# As per 5.2.5, abort the connection if spaces are zero.
|
||||
raise HandshakeError, "Websocket Key1 or Key2 does not contain spaces - this is a symptom of a cross-protocol attack" if spaces == 0
|
||||
|
||||
# As per 5.2.6, abort if numbers is not an integral multiple of spaces
|
||||
if numbers % spaces != 0
|
||||
raise HandshakeError, "Invalid Key #{string.inspect}"
|
||||
end
|
||||
|
||||
quotient = numbers / spaces
|
||||
|
||||
if quotient > 2**32-1
|
||||
raise HandshakeError, "Challenge computation out of range for key #{string.inspect}"
|
||||
end
|
||||
|
||||
return quotient
|
||||
end
|
||||
|
||||
def validate_protocol!(protocol)
|
||||
raise HandshakeError, "Invalid WebSocket-Protocol: empty" if protocol.empty?
|
||||
# TODO: Validate characters
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
37
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/masking04.rb
vendored
Normal file
37
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/masking04.rb
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class MaskedString < String
|
||||
# Read a 4 bit XOR mask - further requested bytes will be unmasked
|
||||
def read_mask
|
||||
if respond_to?(:encoding) && encoding.name != "ASCII-8BIT"
|
||||
raise "MaskedString only operates on BINARY strings"
|
||||
end
|
||||
raise "Too short" if bytesize < 4 # TODO - change
|
||||
@masking_key = String.new(self[0..3])
|
||||
end
|
||||
|
||||
# Removes the mask, behaves like a normal string again
|
||||
def unset_mask
|
||||
@masking_key = nil
|
||||
end
|
||||
|
||||
def getbyte(index)
|
||||
if defined?(@masking_key) && @masking_key
|
||||
masked_char = super
|
||||
masked_char ? masked_char ^ @masking_key.getbyte(index % 4) : nil
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def getbytes(start_index, count)
|
||||
data = ''
|
||||
data.force_encoding('ASCII-8BIT') if data.respond_to?(:force_encoding)
|
||||
count.times do |i|
|
||||
data << getbyte(start_index + i)
|
||||
end
|
||||
data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
47
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/message_processor_03.rb
vendored
Normal file
47
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/message_processor_03.rb
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
# encoding: BINARY
|
||||
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module MessageProcessor03
|
||||
def message(message_type, extension_data, application_data)
|
||||
case message_type
|
||||
when :close
|
||||
@close_info = {
|
||||
:code => 1005,
|
||||
:reason => "",
|
||||
:was_clean => true,
|
||||
}
|
||||
if @state == :closing
|
||||
# TODO: Check that message body matches sent data
|
||||
# We can close connection immediately since there is no more data
|
||||
# is allowed to be sent or received on this connection
|
||||
@connection.close_connection
|
||||
else
|
||||
# Acknowlege close
|
||||
# The connection is considered closed
|
||||
send_frame(:close, application_data)
|
||||
@connection.close_connection_after_writing
|
||||
end
|
||||
when :ping
|
||||
# Pong back the same data
|
||||
send_frame(:pong, application_data)
|
||||
@connection.trigger_on_ping(application_data)
|
||||
when :pong
|
||||
@connection.trigger_on_pong(application_data)
|
||||
when :text
|
||||
if application_data.respond_to?(:force_encoding)
|
||||
application_data.force_encoding("UTF-8")
|
||||
end
|
||||
@connection.trigger_on_message(application_data)
|
||||
when :binary
|
||||
@connection.trigger_on_binary(application_data)
|
||||
end
|
||||
end
|
||||
|
||||
# Ping & Pong supported
|
||||
def pingable?
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
78
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/message_processor_06.rb
vendored
Normal file
78
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/message_processor_06.rb
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
module MessageProcessor06
|
||||
def message(message_type, extension_data, application_data)
|
||||
debug [:message_received, message_type, application_data]
|
||||
|
||||
case message_type
|
||||
when :close
|
||||
status_code = case application_data.length
|
||||
when 0
|
||||
# close messages MAY contain a body
|
||||
nil
|
||||
when 1
|
||||
# Illegal close frame
|
||||
raise WSProtocolError, "Close frames with a body must contain a 2 byte status code"
|
||||
else
|
||||
application_data.slice!(0, 2).unpack('n').first
|
||||
end
|
||||
|
||||
debug [:close_frame_received, status_code, application_data]
|
||||
|
||||
@close_info = {
|
||||
:code => status_code || 1005,
|
||||
:reason => application_data,
|
||||
:was_clean => true,
|
||||
}
|
||||
|
||||
if @state == :closing
|
||||
# We can close connection immediately since no more data may be
|
||||
# sent or received on this connection
|
||||
@connection.close_connection
|
||||
elsif @state == :connected
|
||||
# Acknowlege close & echo status back to client
|
||||
# The connection is considered closed
|
||||
close_data = [status_code || 1000].pack('n')
|
||||
send_frame(:close, close_data)
|
||||
@connection.close_connection_after_writing
|
||||
end
|
||||
when :ping
|
||||
# There are a couple of protections here against malicious/broken WebSocket abusing ping frames.
|
||||
#
|
||||
# 1. Delay 200ms before replying. This reduces the number of pings from WebSocket clients behaving as
|
||||
# `for (;;) { send_ping(conn); rcv_pong(conn); }`. The spec says we "SHOULD respond with Pong frame as soon
|
||||
# as is practical".
|
||||
# 2. Reply at most every 200ms. This reduces the number of pong frames sent to WebSocket clients behaving as
|
||||
# `for (;;) { send_ping(conn); }`. The spec says "If an endpoint receives a Ping frame and has not yet sent
|
||||
# Pong frame(s) in response to previous Ping frame(s), the endpoint MAY elect to send a Pong frame for only
|
||||
# the most recently processed Ping frame."
|
||||
@most_recent_pong_application_data = application_data
|
||||
if @pong_timer == nil then
|
||||
@pong_timer = EventMachine.add_timer(0.2) do
|
||||
@pong_timer = nil
|
||||
send_frame(:pong, @most_recent_pong_application_data)
|
||||
end
|
||||
end
|
||||
@connection.trigger_on_ping(application_data)
|
||||
when :pong
|
||||
@connection.trigger_on_pong(application_data)
|
||||
when :text
|
||||
if application_data.respond_to?(:force_encoding)
|
||||
application_data.force_encoding("UTF-8")
|
||||
unless application_data.valid_encoding?
|
||||
raise InvalidDataError, "Invalid UTF8 data"
|
||||
end
|
||||
end
|
||||
@connection.trigger_on_message(application_data)
|
||||
when :binary
|
||||
@connection.trigger_on_binary(application_data)
|
||||
end
|
||||
end
|
||||
|
||||
# Ping & Pong supported
|
||||
def pingable?
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
5
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/version.rb
vendored
Normal file
5
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/version.rb
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
module EventMachine
|
||||
module Websocket
|
||||
VERSION = "0.5.2"
|
||||
end
|
||||
end
|
||||
56
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/websocket.rb
vendored
Normal file
56
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/lib/em-websocket/websocket.rb
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class << self
|
||||
attr_accessor :max_frame_size
|
||||
attr_accessor :close_timeout
|
||||
end
|
||||
@max_frame_size = 10 * 1024 * 1024 # 10MB
|
||||
# Connections are given 60s to close after being sent a close handshake
|
||||
@close_timeout = 60
|
||||
|
||||
# All errors raised by em-websocket should descend from this class
|
||||
class WebSocketError < RuntimeError; end
|
||||
|
||||
# Used for errors that occur during WebSocket handshake
|
||||
class HandshakeError < WebSocketError; end
|
||||
|
||||
# Used for errors which should cause the connection to close.
|
||||
# See RFC6455 §7.4.1 for a full description of meanings
|
||||
class WSProtocolError < WebSocketError
|
||||
def code; 1002; end
|
||||
end
|
||||
|
||||
class InvalidDataError < WSProtocolError
|
||||
def code; 1007; end
|
||||
end
|
||||
|
||||
# 1009: Message too big to process
|
||||
class WSMessageTooBigError < WSProtocolError
|
||||
def code; 1009; end
|
||||
end
|
||||
|
||||
# Start WebSocket server, including starting eventmachine run loop
|
||||
def self.start(options, &blk)
|
||||
EM.epoll
|
||||
EM.run {
|
||||
trap("TERM") { stop }
|
||||
trap("INT") { stop }
|
||||
|
||||
run(options, &blk)
|
||||
}
|
||||
end
|
||||
|
||||
# Start WebSocket server inside eventmachine run loop
|
||||
def self.run(options)
|
||||
host, port = options.values_at(:host, :port)
|
||||
EM.start_server(host, port, Connection, options) do |c|
|
||||
yield c
|
||||
end
|
||||
end
|
||||
|
||||
def self.stop
|
||||
puts "Terminating WebSocket Server"
|
||||
EM.stop
|
||||
end
|
||||
end
|
||||
end
|
||||
173
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/helper.rb
vendored
Normal file
173
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/helper.rb
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
# encoding: BINARY
|
||||
|
||||
require 'rubygems'
|
||||
require 'rspec'
|
||||
require 'em-spec/rspec'
|
||||
require 'em-http'
|
||||
|
||||
require 'em-websocket'
|
||||
require 'em-websocket-client'
|
||||
|
||||
require 'integration/shared_examples'
|
||||
require 'integration/gte_03_examples'
|
||||
|
||||
RSpec.configure do |c|
|
||||
c.mock_with :rspec
|
||||
end
|
||||
|
||||
class FakeWebSocketClient < EM::Connection
|
||||
attr_reader :handshake_response, :packets
|
||||
|
||||
def onopen(&blk); @onopen = blk; end
|
||||
def onclose(&blk); @onclose = blk; end
|
||||
def onerror(&blk); @onerror = blk; end
|
||||
def onmessage(&blk); @onmessage = blk; end
|
||||
|
||||
def initialize
|
||||
@state = :new
|
||||
@packets = []
|
||||
end
|
||||
|
||||
def receive_data(data)
|
||||
# puts "RECEIVE DATA #{data}"
|
||||
if @state == :new
|
||||
@handshake_response = data
|
||||
@onopen.call if defined? @onopen
|
||||
@state = :open
|
||||
else
|
||||
@onmessage.call(data) if defined? @onmessage
|
||||
@packets << data
|
||||
end
|
||||
end
|
||||
|
||||
def send(application_data)
|
||||
send_frame(:text, application_data)
|
||||
end
|
||||
|
||||
def send_frame(type, application_data)
|
||||
send_data construct_frame(type, application_data)
|
||||
end
|
||||
|
||||
def unbind
|
||||
@onclose.call if defined? @onclose
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def construct_frame(type, data)
|
||||
"\x00#{data}\xff"
|
||||
end
|
||||
end
|
||||
|
||||
class Draft03FakeWebSocketClient < FakeWebSocketClient
|
||||
private
|
||||
|
||||
def construct_frame(type, data)
|
||||
frame = ""
|
||||
frame << EM::WebSocket::Framing03::FRAME_TYPES[type]
|
||||
frame << encoded_length(data.size)
|
||||
frame << data
|
||||
end
|
||||
|
||||
def encoded_length(length)
|
||||
if length <= 125
|
||||
[length].pack('C') # since rsv4 is 0
|
||||
elsif length < 65536 # write 2 byte length
|
||||
"\126#{[length].pack('n')}"
|
||||
else # write 8 byte length
|
||||
"\127#{[length >> 32, length & 0xFFFFFFFF].pack("NN")}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Draft05FakeWebSocketClient < Draft03FakeWebSocketClient
|
||||
private
|
||||
|
||||
def construct_frame(type, data)
|
||||
frame = ""
|
||||
frame << "\x00\x00\x00\x00" # Mask with nothing for simplicity
|
||||
frame << (EM::WebSocket::Framing05::FRAME_TYPES[type] | 0b10000000)
|
||||
frame << encoded_length(data.size)
|
||||
frame << data
|
||||
end
|
||||
end
|
||||
|
||||
class Draft07FakeWebSocketClient < Draft05FakeWebSocketClient
|
||||
private
|
||||
|
||||
def construct_frame(type, data)
|
||||
frame = ""
|
||||
frame << (EM::WebSocket::Framing07::FRAME_TYPES[type] | 0b10000000)
|
||||
# Should probably mask the data, but I get away without bothering since
|
||||
# the server doesn't enforce that incoming frames are masked
|
||||
frame << encoded_length(data.size)
|
||||
frame << data
|
||||
end
|
||||
end
|
||||
|
||||
# Wrapper around em-websocket-client
|
||||
class Draft75WebSocketClient
|
||||
def onopen(&blk); @onopen = blk; end
|
||||
def onclose(&blk); @onclose = blk; end
|
||||
def onerror(&blk); @onerror = blk; end
|
||||
def onmessage(&blk); @onmessage = blk; end
|
||||
|
||||
def initialize
|
||||
@ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/',
|
||||
:version => 75,
|
||||
:origin => 'http://example.com')
|
||||
@ws.errback { |err| @onerror.call if defined? @onerror }
|
||||
@ws.callback { @onopen.call if defined? @onopen }
|
||||
@ws.stream { |msg| @onmessage.call(msg) if defined? @onmessage }
|
||||
@ws.disconnect { @onclose.call if defined? @onclose }
|
||||
end
|
||||
|
||||
def send(message)
|
||||
@ws.send_msg(message)
|
||||
end
|
||||
|
||||
def close_connection
|
||||
@ws.close_connection
|
||||
end
|
||||
end
|
||||
|
||||
def start_server(opts = {})
|
||||
EM::WebSocket.run({:host => "0.0.0.0", :port => 12345}.merge(opts)) { |ws|
|
||||
yield ws if block_given?
|
||||
}
|
||||
end
|
||||
|
||||
def format_request(r)
|
||||
data = "#{r[:method]} #{r[:path]} HTTP/1.1\r\n"
|
||||
header_lines = r[:headers].map { |k,v| "#{k}: #{v}" }
|
||||
data << [header_lines, '', r[:body]].join("\r\n")
|
||||
data
|
||||
end
|
||||
|
||||
def format_response(r)
|
||||
data = r[:protocol] || "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
|
||||
header_lines = r[:headers].map { |k,v| "#{k}: #{v}" }
|
||||
data << [header_lines, '', r[:body]].join("\r\n")
|
||||
data
|
||||
end
|
||||
|
||||
RSpec::Matchers.define :succeed_with_upgrade do |response|
|
||||
match do |actual|
|
||||
success = nil
|
||||
actual.callback { |upgrade_response, handler_klass|
|
||||
success = (upgrade_response.lines.sort == format_response(response).lines.sort)
|
||||
}
|
||||
success
|
||||
end
|
||||
end
|
||||
|
||||
RSpec::Matchers.define :fail_with_error do |error_klass, error_message|
|
||||
match do |actual|
|
||||
success = nil
|
||||
actual.errback { |e|
|
||||
success = (e.class == error_klass)
|
||||
success &= (e.message == error_message) if error_message
|
||||
}
|
||||
success
|
||||
end
|
||||
end
|
||||
138
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/common_spec.rb
vendored
Normal file
138
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/common_spec.rb
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
require 'helper'
|
||||
|
||||
# These tests are not specific to any particular draft of the specification
|
||||
#
|
||||
describe "WebSocket server" do
|
||||
include EM::SpecHelper
|
||||
default_timeout 1
|
||||
|
||||
it "should fail on non WebSocket requests" do
|
||||
em {
|
||||
EM.add_timer(0.1) do
|
||||
http = EM::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0
|
||||
http.errback { done }
|
||||
http.callback { fail }
|
||||
end
|
||||
|
||||
start_server
|
||||
}
|
||||
end
|
||||
|
||||
it "should expose the WebSocket request headers, path and query params" do
|
||||
em {
|
||||
EM.add_timer(0.1) do
|
||||
ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/',
|
||||
:origin => 'http://example.com')
|
||||
ws.errback { fail }
|
||||
ws.callback { ws.close_connection }
|
||||
ws.stream { |msg| }
|
||||
end
|
||||
|
||||
start_server do |ws|
|
||||
ws.onopen { |handshake|
|
||||
headers = handshake.headers
|
||||
headers["Connection"].should == "Upgrade"
|
||||
headers["Upgrade"].should == "websocket"
|
||||
headers["Host"].to_s.should == "127.0.0.1:12345"
|
||||
handshake.path.should == "/"
|
||||
handshake.query.should == {}
|
||||
handshake.origin.should == 'http://example.com'
|
||||
}
|
||||
ws.onclose {
|
||||
ws.state.should == :closed
|
||||
done
|
||||
}
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
it "should expose the WebSocket path and query params when nonempty" do
|
||||
em {
|
||||
EM.add_timer(0.1) do
|
||||
ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/hello?foo=bar&baz=qux')
|
||||
ws.errback { fail }
|
||||
ws.callback {
|
||||
ws.close_connection
|
||||
}
|
||||
ws.stream { |msg| }
|
||||
end
|
||||
|
||||
start_server do |ws|
|
||||
ws.onopen { |handshake|
|
||||
handshake.path.should == '/hello'
|
||||
handshake.query_string.split('&').sort.
|
||||
should == ["baz=qux", "foo=bar"]
|
||||
handshake.query.should == {"foo"=>"bar", "baz"=>"qux"}
|
||||
}
|
||||
ws.onclose {
|
||||
ws.state.should == :closed
|
||||
done
|
||||
}
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
it "should raise an exception if frame sent before handshake complete" do
|
||||
em {
|
||||
# 1. Start WebSocket server
|
||||
start_server { |ws|
|
||||
# 3. Try to send a message to the socket
|
||||
lambda {
|
||||
ws.send('early message')
|
||||
}.should raise_error('Cannot send data before onopen callback')
|
||||
done
|
||||
}
|
||||
|
||||
# 2. Connect a dumb TCP connection (will not send handshake)
|
||||
EM.connect('0.0.0.0', 12345, EM::Connection)
|
||||
}
|
||||
end
|
||||
|
||||
it "should allow the server to be started inside an existing EM" do
|
||||
em {
|
||||
EM.add_timer(0.1) do
|
||||
http = EM::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0
|
||||
http.errback { |e| done }
|
||||
http.callback { fail }
|
||||
end
|
||||
|
||||
start_server do |ws|
|
||||
ws.onopen { |handshake|
|
||||
headers = handshake.headers
|
||||
headers["Host"].to_s.should == "127.0.0.1:12345"
|
||||
}
|
||||
ws.onclose {
|
||||
ws.state.should == :closed
|
||||
done
|
||||
}
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
context "outbound limit set" do
|
||||
it "should close the connection if the limit is reached" do
|
||||
em {
|
||||
start_server(:outbound_limit => 150) do |ws|
|
||||
# Increase the message size by one on each loop
|
||||
ws.onmessage{|msg| ws.send(msg + "x") }
|
||||
ws.onclose{|status|
|
||||
status[:code].should == 1006 # Unclean
|
||||
status[:was_clean].should be false
|
||||
}
|
||||
end
|
||||
|
||||
EM.add_timer(0.1) do
|
||||
ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/')
|
||||
ws.callback { ws.send_msg "hello" }
|
||||
ws.disconnect { done } # Server closed the connection
|
||||
ws.stream { |msg|
|
||||
# minus frame size ? (getting 146 max here)
|
||||
msg.data.size.should <= 150
|
||||
# Return back the message
|
||||
ws.send_msg(msg.data)
|
||||
}
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
298
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/draft03_spec.rb
vendored
Normal file
298
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/draft03_spec.rb
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
require 'helper'
|
||||
|
||||
describe "draft03" do
|
||||
include EM::SpecHelper
|
||||
default_timeout 1
|
||||
|
||||
before :each do
|
||||
@request = {
|
||||
:port => 80,
|
||||
:method => "GET",
|
||||
:path => "/demo",
|
||||
:headers => {
|
||||
'Host' => 'example.com',
|
||||
'Connection' => 'Upgrade',
|
||||
'Sec-WebSocket-Key2' => '12998 5 Y3 1 .P00',
|
||||
'Sec-WebSocket-Protocol' => 'sample',
|
||||
'Upgrade' => 'WebSocket',
|
||||
'Sec-WebSocket-Key1' => '4 @1 46546xW%0l 1 5',
|
||||
'Origin' => 'http://example.com',
|
||||
'Sec-WebSocket-Draft' => '3'
|
||||
},
|
||||
:body => '^n:ds[4U'
|
||||
}
|
||||
|
||||
@response = {
|
||||
:headers => {
|
||||
"Upgrade" => "WebSocket",
|
||||
"Connection" => "Upgrade",
|
||||
"Sec-WebSocket-Location" => "ws://example.com/demo",
|
||||
"Sec-WebSocket-Origin" => "http://example.com",
|
||||
"Sec-WebSocket-Protocol" => "sample"
|
||||
},
|
||||
:body => "8jKS\'y:G*Co,Wxa-"
|
||||
}
|
||||
end
|
||||
|
||||
def start_client
|
||||
client = EM.connect('0.0.0.0', 12345, Draft03FakeWebSocketClient)
|
||||
client.send_data(format_request(@request))
|
||||
yield client if block_given?
|
||||
return client
|
||||
end
|
||||
|
||||
it_behaves_like "a websocket server" do
|
||||
let(:version) { 3 }
|
||||
end
|
||||
|
||||
it_behaves_like "a WebSocket server drafts 3 and above" do
|
||||
let(:version) { 3 }
|
||||
end
|
||||
|
||||
# These examples are straight from the spec
|
||||
# http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03#section-4.6
|
||||
describe "examples from the spec" do
|
||||
it "should accept a single-frame text message" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onmessage { |msg|
|
||||
msg.should == 'Hello'
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client { |client|
|
||||
client.onopen {
|
||||
client.send_data("\x04\x05Hello")
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should accept a fragmented text message" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onmessage { |msg|
|
||||
msg.should == 'Hello'
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
connection = start_client
|
||||
|
||||
# Send frame
|
||||
connection.onopen {
|
||||
connection.send_data("\x84\x03Hel")
|
||||
connection.send_data("\x00\x02lo")
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should accept a ping request and respond with the same body" do
|
||||
em {
|
||||
start_server
|
||||
|
||||
connection = start_client
|
||||
|
||||
# Send frame
|
||||
connection.onopen {
|
||||
connection.send_data("\x02\x05Hello")
|
||||
}
|
||||
|
||||
connection.onmessage { |frame|
|
||||
next if frame.nil?
|
||||
frame.should == "\x03\x05Hello"
|
||||
done
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should accept a 256 bytes binary message in a single frame" do
|
||||
em {
|
||||
data = "a" * 256
|
||||
|
||||
start_server { |ws|
|
||||
ws.onbinary { |msg|
|
||||
msg.encoding.should == Encoding.find("BINARY") if defined?(Encoding)
|
||||
msg.should == data
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
connection = start_client
|
||||
|
||||
# Send frame
|
||||
connection.onopen {
|
||||
connection.send_data("\x05\x7E\x01\x00" + data)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should accept a 64KiB binary message in a single frame" do
|
||||
em {
|
||||
data = "a" * 65536
|
||||
|
||||
start_server { |ws|
|
||||
ws.onbinary { |msg|
|
||||
msg.encoding.should == Encoding.find("BINARY") if defined?(Encoding)
|
||||
msg.should == data
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
connection = start_client
|
||||
|
||||
# Send frame
|
||||
connection.onopen {
|
||||
connection.send_data("\x05\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data)
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe "close handling" do
|
||||
it "should respond to a new close frame with a close frame" do
|
||||
em {
|
||||
start_server
|
||||
|
||||
connection = start_client
|
||||
|
||||
# Send close frame
|
||||
connection.onopen {
|
||||
connection.send_data("\x01\x00")
|
||||
}
|
||||
|
||||
# Check that close ack received
|
||||
connection.onmessage { |frame|
|
||||
frame.should == "\x01\x00"
|
||||
done
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should close the connection on receiving a close acknowlegement and call onclose with close code 1005 and was_clean=true (initiated by server)" do
|
||||
em {
|
||||
ack_received = false
|
||||
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
# 2. Send a close frame
|
||||
EM.next_tick {
|
||||
ws.close
|
||||
}
|
||||
}
|
||||
|
||||
# 5. Onclose event on server
|
||||
ws.onclose { |event|
|
||||
event.should == {
|
||||
:code => 1005,
|
||||
:reason => "",
|
||||
:was_clean => true,
|
||||
}
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
# 1. Create a fake client which sends draft 76 handshake
|
||||
connection = start_client
|
||||
|
||||
# 3. Check that close frame recieved and acknowlege it
|
||||
connection.onmessage { |frame|
|
||||
frame.should == "\x01\x00"
|
||||
ack_received = true
|
||||
connection.send_data("\x01\x00")
|
||||
}
|
||||
|
||||
# 4. Check that connection is closed _after_ the ack
|
||||
connection.onclose {
|
||||
ack_received.should == true
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# it "should repur"
|
||||
#
|
||||
it "should return close code 1005 and was_clean=true after closing handshake (initiated by client)" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onclose { |event|
|
||||
event.should == {
|
||||
:code => 1005,
|
||||
:reason => "",
|
||||
:was_clean => true,
|
||||
}
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client { |client|
|
||||
client.onopen {
|
||||
client.send_data("\x01\x00")
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should not allow data frame to be sent after close frame sent" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
# 2. Send a close frame
|
||||
EM.next_tick {
|
||||
ws.close
|
||||
}
|
||||
|
||||
# 3. Check that exception raised if I attempt to send more data
|
||||
EM.add_timer(0.1) {
|
||||
lambda {
|
||||
ws.send('hello world')
|
||||
}.should raise_error(EM::WebSocket::WebSocketError, 'Cannot send data frame since connection is closing')
|
||||
done
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 1. Create a fake client which sends draft 76 handshake
|
||||
start_client
|
||||
}
|
||||
end
|
||||
|
||||
it "should still respond to control frames after close frame sent" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
# 2. Send a close frame
|
||||
EM.next_tick {
|
||||
ws.close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 1. Create a fake client which sends draft 76 handshake
|
||||
connection = start_client
|
||||
|
||||
connection.onmessage { |frame|
|
||||
if frame == "\x01\x00"
|
||||
# 3. After the close frame is received send a ping frame, but
|
||||
# don't respond with a close ack
|
||||
connection.send_data("\x02\x05Hello")
|
||||
else
|
||||
# 4. Check that the pong is received
|
||||
frame.should == "\x03\x05Hello"
|
||||
done
|
||||
end
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should report that close codes are not supported" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
ws.supports_close_codes?.should == false
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
50
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/draft05_spec.rb
vendored
Normal file
50
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/draft05_spec.rb
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
require 'helper'
|
||||
|
||||
describe "draft05" do
|
||||
include EM::SpecHelper
|
||||
default_timeout 1
|
||||
|
||||
before :each do
|
||||
@request = {
|
||||
:port => 80,
|
||||
:method => "GET",
|
||||
:path => "/demo",
|
||||
:headers => {
|
||||
'Host' => 'example.com',
|
||||
'Upgrade' => 'websocket',
|
||||
'Connection' => 'Upgrade',
|
||||
'Sec-WebSocket-Key' => 'dGhlIHNhbXBsZSBub25jZQ==',
|
||||
'Sec-WebSocket-Protocol' => 'sample',
|
||||
'Sec-WebSocket-Origin' => 'http://example.com',
|
||||
'Sec-WebSocket-Version' => '5'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def start_client
|
||||
client = EM.connect('0.0.0.0', 12345, Draft05FakeWebSocketClient)
|
||||
client.send_data(format_request(@request))
|
||||
yield client if block_given?
|
||||
return client
|
||||
end
|
||||
|
||||
it_behaves_like "a websocket server" do
|
||||
let(:version) { 5 }
|
||||
end
|
||||
|
||||
it_behaves_like "a WebSocket server drafts 3 and above" do
|
||||
let(:version) { 5 }
|
||||
end
|
||||
|
||||
it "should report that close codes are not supported" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
ws.supports_close_codes?.should == false
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client
|
||||
}
|
||||
end
|
||||
end
|
||||
145
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/draft06_spec.rb
vendored
Normal file
145
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/draft06_spec.rb
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
require 'helper'
|
||||
|
||||
describe "draft06" do
|
||||
include EM::SpecHelper
|
||||
default_timeout 1
|
||||
|
||||
before :each do
|
||||
@request = {
|
||||
:port => 80,
|
||||
:method => "GET",
|
||||
:path => "/demo",
|
||||
:headers => {
|
||||
'Host' => 'example.com',
|
||||
'Upgrade' => 'websocket',
|
||||
'Connection' => 'Upgrade',
|
||||
'Sec-WebSocket-Key' => 'dGhlIHNhbXBsZSBub25jZQ==',
|
||||
'Sec-WebSocket-Protocol' => 'sample',
|
||||
'Sec-WebSocket-Origin' => 'http://example.com',
|
||||
'Sec-WebSocket-Version' => '6'
|
||||
}
|
||||
}
|
||||
|
||||
@response = {
|
||||
:protocol => "HTTP/1.1 101 Switching Protocols\r\n",
|
||||
:headers => {
|
||||
"Upgrade" => "websocket",
|
||||
"Connection" => "Upgrade",
|
||||
"Sec-WebSocket-Accept" => "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
|
||||
"Sec-WebSocket-Protocol" => "sample",
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def start_client
|
||||
client = EM.connect('0.0.0.0', 12345, Draft05FakeWebSocketClient)
|
||||
client.send_data(format_request(@request))
|
||||
yield client if block_given?
|
||||
return client
|
||||
end
|
||||
|
||||
it_behaves_like "a websocket server" do
|
||||
let(:version) { 6 }
|
||||
end
|
||||
|
||||
it_behaves_like "a WebSocket server drafts 3 and above" do
|
||||
let(:version) { 6 }
|
||||
end
|
||||
|
||||
it "should open connection" do
|
||||
em {
|
||||
start_server { |server|
|
||||
server.onopen {
|
||||
server.instance_variable_get(:@handler).class.should == EventMachine::WebSocket::Handler06
|
||||
}
|
||||
}
|
||||
|
||||
start_client { |client|
|
||||
client.onopen {
|
||||
client.handshake_response.lines.sort.
|
||||
should == format_response(@response).lines.sort
|
||||
done
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should accept a single-frame text message (masked)" do
|
||||
em {
|
||||
start_server { |server|
|
||||
server.onmessage { |msg|
|
||||
msg.should == 'Hello'
|
||||
if msg.respond_to?(:encoding)
|
||||
msg.encoding.should == Encoding.find("UTF-8")
|
||||
end
|
||||
done
|
||||
}
|
||||
server.onerror {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
||||
start_client { |client|
|
||||
client.onopen {
|
||||
client.send_data("\x00\x00\x01\x00\x84\x05Ielln")
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should return close code and reason if closed via handshake" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onclose { |event|
|
||||
# 2. Receive close event in server
|
||||
event.should == {
|
||||
:code => 4004,
|
||||
:reason => "close reason",
|
||||
:was_clean => true,
|
||||
}
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client { |client|
|
||||
client.onopen {
|
||||
# 1: Send close handshake
|
||||
close_data = [4004].pack('n')
|
||||
close_data << "close reason"
|
||||
client.send_frame(:close, close_data)
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should return close code 1005 if no code was specified" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onclose { |event|
|
||||
event.should == {
|
||||
:code => 1005,
|
||||
:reason => "",
|
||||
:was_clean => true,
|
||||
}
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client { |client|
|
||||
client.onopen {
|
||||
client.send_frame(:close, '')
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should report that close codes are supported" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
ws.supports_close_codes?.should == true
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client
|
||||
}
|
||||
end
|
||||
end
|
||||
105
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/draft13_spec.rb
vendored
Normal file
105
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/draft13_spec.rb
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
# encoding: BINARY
|
||||
|
||||
require 'helper'
|
||||
|
||||
describe "draft13" do
|
||||
include EM::SpecHelper
|
||||
default_timeout 1
|
||||
|
||||
before :each do
|
||||
@request = {
|
||||
:port => 80,
|
||||
:method => "GET",
|
||||
:path => "/demo",
|
||||
:headers => {
|
||||
'Host' => 'example.com',
|
||||
'Upgrade' => 'websocket',
|
||||
'Connection' => 'Upgrade',
|
||||
'Sec-WebSocket-Key' => 'dGhlIHNhbXBsZSBub25jZQ==',
|
||||
'Sec-WebSocket-Protocol' => 'sample',
|
||||
'Sec-WebSocket-Origin' => 'http://example.com',
|
||||
'Sec-WebSocket-Version' => '13'
|
||||
}
|
||||
}
|
||||
|
||||
@response = {
|
||||
:protocol => "HTTP/1.1 101 Switching Protocols\r\n",
|
||||
:headers => {
|
||||
"Upgrade" => "websocket",
|
||||
"Connection" => "Upgrade",
|
||||
"Sec-WebSocket-Accept" => "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
|
||||
"Sec-WebSocket-Protocol" => "sample",
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def start_client
|
||||
client = EM.connect('0.0.0.0', 12345, Draft07FakeWebSocketClient)
|
||||
client.send_data(format_request(@request))
|
||||
yield client if block_given?
|
||||
return client
|
||||
end
|
||||
|
||||
it_behaves_like "a websocket server" do
|
||||
let(:version) { 13 }
|
||||
end
|
||||
|
||||
it_behaves_like "a WebSocket server drafts 3 and above" do
|
||||
let(:version) { 13 }
|
||||
end
|
||||
|
||||
it "should send back the correct handshake response" do
|
||||
em {
|
||||
start_server
|
||||
|
||||
connection = start_client
|
||||
|
||||
connection.onopen {
|
||||
connection.handshake_response.lines.sort.
|
||||
should == format_response(@response).lines.sort
|
||||
done
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# TODO: This test would be much nicer with a real websocket client...
|
||||
it "should support sending pings and binding to onpong" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
ws.should be_pingable
|
||||
EM.next_tick {
|
||||
ws.ping('hello').should == true
|
||||
}
|
||||
|
||||
}
|
||||
ws.onpong { |data|
|
||||
data.should == 'hello'
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
connection = start_client
|
||||
|
||||
# Confusing, fake onmessage means any data after the handshake
|
||||
connection.onmessage { |data|
|
||||
# This is what a ping looks like
|
||||
data.should == "\x89\x05hello"
|
||||
# This is what a pong looks like
|
||||
connection.send_data("\x8a\x05hello")
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should report that close codes are supported" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
ws.supports_close_codes?.should == true
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client
|
||||
}
|
||||
end
|
||||
end
|
||||
123
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/draft75_spec.rb
vendored
Normal file
123
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/draft75_spec.rb
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
require 'helper'
|
||||
|
||||
# These integration tests are older and use a different testing style to the
|
||||
# integration tests for newer drafts. They use EM::HttpRequest which happens
|
||||
# to currently estabish a websocket connection using the draft75 protocol.
|
||||
#
|
||||
describe "WebSocket server draft75" do
|
||||
include EM::SpecHelper
|
||||
default_timeout 1
|
||||
|
||||
def start_client
|
||||
client = Draft75WebSocketClient.new
|
||||
yield client if block_given?
|
||||
return client
|
||||
end
|
||||
|
||||
it_behaves_like "a websocket server" do
|
||||
let(:version) { 75 }
|
||||
end
|
||||
|
||||
it "should automatically complete WebSocket handshake" do
|
||||
em {
|
||||
MSG = "Hello World!"
|
||||
EventMachine.add_timer(0.1) do
|
||||
ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/')
|
||||
ws.errback { fail }
|
||||
ws.callback { }
|
||||
|
||||
ws.stream { |msg|
|
||||
msg.data.should == MSG
|
||||
EventMachine.stop
|
||||
}
|
||||
end
|
||||
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
ws.send MSG
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should split multiple messages into separate callbacks" do
|
||||
em {
|
||||
messages = %w[1 2]
|
||||
received = []
|
||||
|
||||
EventMachine.add_timer(0.1) do
|
||||
ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/')
|
||||
ws.errback { fail }
|
||||
ws.stream {|msg|}
|
||||
ws.callback {
|
||||
ws.send_msg messages[0]
|
||||
ws.send_msg messages[1]
|
||||
}
|
||||
end
|
||||
|
||||
start_server { |ws|
|
||||
ws.onopen {}
|
||||
ws.onclose {}
|
||||
ws.onmessage {|msg|
|
||||
msg.should == messages[received.size]
|
||||
received.push msg
|
||||
|
||||
EventMachine.stop if received.size == messages.size
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should call onclose callback when client closes connection" do
|
||||
em {
|
||||
EventMachine.add_timer(0.1) do
|
||||
ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/')
|
||||
ws.errback { fail }
|
||||
ws.callback {
|
||||
ws.close_connection
|
||||
}
|
||||
ws.stream{|msg|}
|
||||
end
|
||||
|
||||
start_server { |ws|
|
||||
ws.onopen {}
|
||||
ws.onclose {
|
||||
ws.state.should == :closed
|
||||
EventMachine.stop
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should call onerror callback with raised exception and close connection on bad handshake" do
|
||||
em {
|
||||
EventMachine.add_timer(0.1) do
|
||||
http = EM::HttpRequest.new('http://127.0.0.1:12345/').get
|
||||
http.errback { }
|
||||
http.callback { fail }
|
||||
end
|
||||
|
||||
start_server { |ws|
|
||||
ws.onopen { fail }
|
||||
ws.onclose { EventMachine.stop }
|
||||
ws.onerror {|e|
|
||||
e.should be_an_instance_of EventMachine::WebSocket::HandshakeError
|
||||
e.message.should match('Not an upgrade request')
|
||||
EventMachine.stop
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should report that close codes are not supported" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
ws.supports_close_codes?.should == false
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client
|
||||
}
|
||||
end
|
||||
end
|
||||
234
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/draft76_spec.rb
vendored
Normal file
234
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/draft76_spec.rb
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
# encoding: BINARY
|
||||
|
||||
require 'helper'
|
||||
|
||||
describe "WebSocket server draft76" do
|
||||
include EM::SpecHelper
|
||||
default_timeout 1
|
||||
|
||||
before :each do
|
||||
@request = {
|
||||
:port => 80,
|
||||
:method => "GET",
|
||||
:path => "/demo",
|
||||
:headers => {
|
||||
'Host' => 'example.com',
|
||||
'Connection' => 'Upgrade',
|
||||
'Sec-WebSocket-Key2' => '12998 5 Y3 1 .P00',
|
||||
'Sec-WebSocket-Protocol' => 'sample',
|
||||
'Upgrade' => 'WebSocket',
|
||||
'Sec-WebSocket-Key1' => '4 @1 46546xW%0l 1 5',
|
||||
'Origin' => 'http://example.com'
|
||||
},
|
||||
:body => '^n:ds[4U'
|
||||
}
|
||||
|
||||
@response = {
|
||||
:headers => {
|
||||
"Upgrade" => "WebSocket",
|
||||
"Connection" => "Upgrade",
|
||||
"Sec-WebSocket-Location" => "ws://example.com/demo",
|
||||
"Sec-WebSocket-Origin" => "http://example.com",
|
||||
"Sec-WebSocket-Protocol" => "sample"
|
||||
},
|
||||
:body => "8jKS\'y:G*Co,Wxa-"
|
||||
}
|
||||
end
|
||||
|
||||
def start_client
|
||||
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
||||
client.send_data(format_request(@request))
|
||||
yield client if block_given?
|
||||
return client
|
||||
end
|
||||
|
||||
it_behaves_like "a websocket server" do
|
||||
let(:version) { 76 }
|
||||
end
|
||||
|
||||
it "should send back the correct handshake response" do
|
||||
em {
|
||||
start_server
|
||||
|
||||
start_client { |connection|
|
||||
connection.onopen {
|
||||
connection.handshake_response.lines.sort.
|
||||
should == format_response(@response).lines.sort
|
||||
done
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should send closing frame back and close the connection after recieving closing frame" do
|
||||
em {
|
||||
start_server
|
||||
|
||||
connection = start_client
|
||||
|
||||
# Send closing frame after handshake complete
|
||||
connection.onopen {
|
||||
connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING)
|
||||
}
|
||||
|
||||
# Check that this causes a termination string to be returned and the
|
||||
# connection close
|
||||
connection.onclose {
|
||||
connection.packets[0].should ==
|
||||
EM::WebSocket::Handler76::TERMINATE_STRING
|
||||
done
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should ignore any data received after the closing frame" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
# Fail if foobar message is received
|
||||
ws.onmessage { |msg|
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
||||
connection = start_client
|
||||
|
||||
# Send closing frame after handshake complete, followed by another msg
|
||||
connection.onopen {
|
||||
connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING)
|
||||
connection.send('foobar')
|
||||
}
|
||||
|
||||
connection.onclose {
|
||||
done
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should accept null bytes within the frame after a line return" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onmessage { |msg|
|
||||
msg.should == "\n\000"
|
||||
}
|
||||
}
|
||||
|
||||
connection = start_client
|
||||
|
||||
# Send closing frame after handshake complete
|
||||
connection.onopen {
|
||||
connection.send_data("\000\n\000\377")
|
||||
connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING)
|
||||
}
|
||||
|
||||
connection.onclose {
|
||||
done
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should handle unreasonable frame lengths by calling onerror callback" do
|
||||
em {
|
||||
start_server { |server|
|
||||
server.onerror { |error|
|
||||
error.should be_an_instance_of EM::WebSocket::WSMessageTooBigError
|
||||
error.message.should == "Frame length too long (1180591620717411303296 bytes)"
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
client = start_client
|
||||
|
||||
# This particular frame indicates a message length of
|
||||
# 1180591620717411303296 bytes. Such a message would previously cause
|
||||
# a "bignum too big to convert into `long'" error.
|
||||
# However it is clearly unreasonable and should be rejected.
|
||||
client.onopen {
|
||||
client.send_data("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00")
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should handle impossible frames by calling onerror callback" do
|
||||
em {
|
||||
start_server { |server|
|
||||
server.onerror { |error|
|
||||
error.should be_an_instance_of EM::WebSocket::WSProtocolError
|
||||
error.message.should == "Invalid frame received"
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
client = start_client
|
||||
|
||||
client.onopen {
|
||||
client.send_data("foobar") # Does not start with \x00 or \xff
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should handle invalid http requests by raising HandshakeError passed to onerror callback" do
|
||||
em {
|
||||
start_server { |server|
|
||||
server.onerror { |error|
|
||||
error.should be_an_instance_of EM::WebSocket::HandshakeError
|
||||
error.message.should == "Invalid HTTP header: Could not parse data entirely (1 != 29)"
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
||||
client.send_data("This is not a HTTP header\r\n\r\n")
|
||||
}
|
||||
end
|
||||
|
||||
it "should handle handshake request split into two TCP packets" do
|
||||
em {
|
||||
start_server
|
||||
|
||||
# Create a fake client which sends draft 76 handshake
|
||||
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
||||
data = format_request(@request)
|
||||
# Sends first half of the request
|
||||
connection.send_data(data[0...(data.length / 2)])
|
||||
|
||||
connection.onopen {
|
||||
connection.handshake_response.lines.sort.
|
||||
should == format_response(@response).lines.sort
|
||||
done
|
||||
}
|
||||
|
||||
EM.add_timer(0.1) do
|
||||
# Sends second half of the request
|
||||
connection.send_data(data[(data.length / 2)..-1])
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
it "should report that close codes are not supported" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
ws.supports_close_codes?.should == false
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client
|
||||
}
|
||||
end
|
||||
|
||||
it "should call onclose when the server closes the connection [antiregression]" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
EM.add_timer(0.1) {
|
||||
ws.close()
|
||||
}
|
||||
}
|
||||
ws.onclose {
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client
|
||||
}
|
||||
end
|
||||
end
|
||||
42
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/gte_03_examples.rb
vendored
Normal file
42
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/gte_03_examples.rb
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
shared_examples_for "a WebSocket server drafts 3 and above" do
|
||||
it "should force close connections after a timeout if close handshake is not sent by the client" do
|
||||
em {
|
||||
server_onerror_fired = false
|
||||
server_onclose_fired = false
|
||||
client_got_close_handshake = false
|
||||
|
||||
start_server(:close_timeout => 0.1) { |ws|
|
||||
ws.onopen {
|
||||
# 1: Send close handshake to client
|
||||
EM.next_tick { ws.close(4999, "Close message") }
|
||||
}
|
||||
|
||||
ws.onerror { |e|
|
||||
# 3: Client should receive onerror
|
||||
e.class.should == EM::WebSocket::WSProtocolError
|
||||
e.message.should == "Close handshake un-acked after 0.1s, closing tcp connection"
|
||||
server_onerror_fired = true
|
||||
}
|
||||
|
||||
ws.onclose {
|
||||
server_onclose_fired = true
|
||||
}
|
||||
}
|
||||
start_client { |client|
|
||||
client.onmessage { |msg|
|
||||
# 2: Client does not respond to close handshake (the fake client
|
||||
# doesn't understand them at all hence this is in onmessage)
|
||||
msg.should =~ /Close message/ if version >= 6
|
||||
client_got_close_handshake = true
|
||||
}
|
||||
|
||||
client.onclose {
|
||||
server_onerror_fired.should == true
|
||||
server_onclose_fired.should == true
|
||||
client_got_close_handshake.should == true
|
||||
done
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
265
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/shared_examples.rb
vendored
Normal file
265
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/integration/shared_examples.rb
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
# These tests are run against all draft versions
|
||||
#
|
||||
shared_examples_for "a websocket server" do
|
||||
it "should expose the protocol version" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen { |handshake|
|
||||
handshake.protocol_version.should == version
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
start_client
|
||||
}
|
||||
end
|
||||
|
||||
it "should expose the origin header" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen { |handshake|
|
||||
handshake.origin.should == 'http://example.com'
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
start_client
|
||||
}
|
||||
end
|
||||
|
||||
it "should expose the remote IP address" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
ws.remote_ip.should == "127.0.0.1"
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
start_client
|
||||
}
|
||||
end
|
||||
|
||||
it "should send messages successfully" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onmessage { |message|
|
||||
message.should == "hello server"
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
start_client { |client|
|
||||
client.onopen {
|
||||
client.send("hello server")
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should allow connection to be closed with valid close code" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
ws.close(4004, "Bye bye")
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
start_client
|
||||
# TODO: Use a real client which understands how to respond to closing
|
||||
# handshakes, sending the handshake currently untested
|
||||
}
|
||||
end
|
||||
|
||||
it "should raise error if if invalid close code is used" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
lambda {
|
||||
ws.close(2000)
|
||||
}.should raise_error("Application code may only use codes from 1000, 3000-4999")
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
start_client
|
||||
}
|
||||
end
|
||||
|
||||
it "should call onclose with was_clean set to false if connection closed without closing handshake by server" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
# Close tcp connection (no close handshake)
|
||||
ws.close_connection
|
||||
}
|
||||
ws.onclose { |event|
|
||||
event.should == {:code => 1006, :was_clean => false}
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client
|
||||
}
|
||||
end
|
||||
|
||||
it "should call onclose with was_clean set to false if connection closed without closing handshake by client" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onclose { |event|
|
||||
event.should == {:code => 1006, :was_clean => false}
|
||||
done
|
||||
}
|
||||
}
|
||||
start_client { |client|
|
||||
client.onopen {
|
||||
# Close tcp connection (no close handshake)
|
||||
client.close_connection
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should call onerror if an application error raised in onopen" do
|
||||
em {
|
||||
start_server { |ws|
|
||||
ws.onopen {
|
||||
raise "application error"
|
||||
}
|
||||
|
||||
ws.onerror { |e|
|
||||
e.message.should == "application error"
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
start_client
|
||||
}
|
||||
end
|
||||
|
||||
it "should call onerror if an application error raised in onmessage" do
|
||||
em {
|
||||
start_server { |server|
|
||||
server.onmessage {
|
||||
raise "application error"
|
||||
}
|
||||
|
||||
server.onerror { |e|
|
||||
e.message.should == "application error"
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
start_client { |client|
|
||||
client.onopen {
|
||||
client.send('a message')
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should call onerror in an application error raised in onclose" do
|
||||
em {
|
||||
start_server { |server|
|
||||
server.onclose {
|
||||
raise "application error"
|
||||
}
|
||||
|
||||
server.onerror { |e|
|
||||
e.message.should == "application error"
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
start_client { |client|
|
||||
client.onopen {
|
||||
EM.add_timer(0.1) {
|
||||
client.close_connection
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "should close the connection when a too long frame is sent" do
|
||||
em {
|
||||
start_server { |server|
|
||||
server.max_frame_size = 20
|
||||
|
||||
server.onerror { |e|
|
||||
# 3: Error should be reported to server
|
||||
e.class.should == EventMachine::WebSocket::WSMessageTooBigError
|
||||
e.message.should =~ /Frame length too long/
|
||||
}
|
||||
}
|
||||
|
||||
start_client { |client|
|
||||
client.onopen {
|
||||
EM.next_tick {
|
||||
client.send("This message is longer than 20 characters")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
client.onmessage { |msg|
|
||||
# 4: This is actually the close message. Really need to use a real
|
||||
# WebSocket client in these tests...
|
||||
done
|
||||
}
|
||||
|
||||
client.onclose {
|
||||
# 4: Drafts 75 & 76 don't send a close message, they just close the
|
||||
# connection
|
||||
done
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# Only run these tests on ruby 1.9
|
||||
if "a".respond_to?(:force_encoding)
|
||||
it "should raise error if you try to send non utf8 text data to ws" do
|
||||
em {
|
||||
start_server { |server|
|
||||
server.onopen {
|
||||
# Create a string which claims to be UTF-8 but which is not
|
||||
s = "ê" # utf-8 string
|
||||
s.encode!("ISO-8859-1")
|
||||
s.force_encoding("UTF-8")
|
||||
s.valid_encoding?.should == false # now invalid utf8
|
||||
|
||||
# Send non utf8 encoded data
|
||||
server.send(s)
|
||||
}
|
||||
server.onerror { |error|
|
||||
error.class.should == EventMachine::WebSocket::WebSocketError
|
||||
error.message.should == "Data sent to WebSocket must be valid UTF-8 but was UTF-8 (valid: false)"
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
start_client { }
|
||||
}
|
||||
end
|
||||
|
||||
it "should not change the encoding of strings sent to send [antiregression]" do
|
||||
em {
|
||||
start_server { |server|
|
||||
server.onopen {
|
||||
s = "example string"
|
||||
s.force_encoding("UTF-8")
|
||||
|
||||
server.send(s)
|
||||
|
||||
s.encoding.should == Encoding.find("UTF-8")
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
start_client { }
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
298
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/unit/framing_spec.rb
vendored
Normal file
298
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/unit/framing_spec.rb
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
# encoding: BINARY
|
||||
|
||||
require 'helper'
|
||||
|
||||
describe EM::WebSocket::Framing03 do
|
||||
class FramingContainer
|
||||
include EM::WebSocket::Framing03
|
||||
|
||||
def initialize
|
||||
@connection = Object.new
|
||||
def @connection.max_frame_size
|
||||
1000000
|
||||
end
|
||||
end
|
||||
|
||||
def <<(data)
|
||||
@data << data
|
||||
process_data
|
||||
end
|
||||
|
||||
def debug(*args); end
|
||||
end
|
||||
|
||||
before :each do
|
||||
@f = FramingContainer.new
|
||||
@f.initialize_framing
|
||||
end
|
||||
|
||||
describe "basic examples" do
|
||||
it "connection close" do
|
||||
@f.should_receive(:message).with(:close, '', '')
|
||||
@f << 0b00000001
|
||||
@f << 0b00000000
|
||||
end
|
||||
|
||||
it "ping" do
|
||||
@f.should_receive(:message).with(:ping, '', '')
|
||||
@f << 0b00000010
|
||||
@f << 0b00000000
|
||||
end
|
||||
|
||||
it "pong" do
|
||||
@f.should_receive(:message).with(:pong, '', '')
|
||||
@f << 0b00000011
|
||||
@f << 0b00000000
|
||||
end
|
||||
|
||||
it "text" do
|
||||
@f.should_receive(:message).with(:text, '', 'foo')
|
||||
@f << 0b00000100
|
||||
@f << 0b00000011
|
||||
@f << 'foo'
|
||||
end
|
||||
|
||||
it "Text in two frames" do
|
||||
@f.should_receive(:message).with(:text, '', 'hello world')
|
||||
@f << 0b10000100
|
||||
@f << 0b00000110
|
||||
@f << "hello "
|
||||
@f << 0b00000000
|
||||
@f << 0b00000101
|
||||
@f << "world"
|
||||
end
|
||||
|
||||
it "2 byte extended payload length text frame" do
|
||||
data = 'a' * 256
|
||||
@f.should_receive(:message).with(:text, '', data)
|
||||
@f << 0b00000100 # Single frame, text
|
||||
@f << 0b01111110 # Length 126 (so read 2 bytes)
|
||||
@f << 0b00000001 # Two bytes in network byte order (256)
|
||||
@f << 0b00000000
|
||||
@f << data
|
||||
end
|
||||
end
|
||||
|
||||
# These examples are straight from the spec
|
||||
# http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03#section-4.6
|
||||
describe "examples from the spec" do
|
||||
it "a single-frame text message" do
|
||||
@f.should_receive(:message).with(:text, '', 'Hello')
|
||||
@f << "\x04\x05Hello"
|
||||
end
|
||||
|
||||
it "a fragmented text message" do
|
||||
@f.should_receive(:message).with(:text, '', 'Hello')
|
||||
@f << "\x84\x03Hel"
|
||||
@f << "\x00\x02lo"
|
||||
end
|
||||
|
||||
it "Ping request and response" do
|
||||
@f.should_receive(:message).with(:ping, '', 'Hello')
|
||||
@f << "\x02\x05Hello"
|
||||
end
|
||||
|
||||
it "256 bytes binary message in a single frame" do
|
||||
data = "a"*256
|
||||
@f.should_receive(:message).with(:binary, '', data)
|
||||
@f << "\x05\x7E\x01\x00" + data
|
||||
end
|
||||
|
||||
it "64KiB binary message in a single frame" do
|
||||
data = "a"*65536
|
||||
@f.should_receive(:message).with(:binary, '', data)
|
||||
@f << "\x05\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data
|
||||
end
|
||||
end
|
||||
|
||||
describe "other tests" do
|
||||
it "should accept a fragmented unmasked text message in 3 frames" do
|
||||
@f.should_receive(:message).with(:text, '', 'Hello world')
|
||||
@f << "\x84\x03Hel"
|
||||
@f << "\x80\x02lo"
|
||||
@f << "\x00\x06 world"
|
||||
end
|
||||
end
|
||||
|
||||
describe "error cases" do
|
||||
it "should raise an exception on continuation frame without preceeding more frame" do
|
||||
lambda {
|
||||
@f << 0b00000000 # Single frame, continuation
|
||||
@f << 0b00000001 # Length 1
|
||||
@f << 'f'
|
||||
}.should raise_error(EM::WebSocket::WebSocketError, 'Continuation frame not expected')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# These examples are straight from the spec
|
||||
# http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03#section-4.6
|
||||
describe EM::WebSocket::Framing04 do
|
||||
class FramingContainer04
|
||||
include EM::WebSocket::Framing04
|
||||
|
||||
def initialize
|
||||
@connection = Object.new
|
||||
def @connection.max_frame_size
|
||||
1000000
|
||||
end
|
||||
end
|
||||
|
||||
def <<(data)
|
||||
@data << data
|
||||
process_data
|
||||
end
|
||||
|
||||
def debug(*args); end
|
||||
end
|
||||
|
||||
before :each do
|
||||
@f = FramingContainer04.new
|
||||
@f.initialize_framing
|
||||
end
|
||||
|
||||
describe "examples from the spec" do
|
||||
it "a single-frame text message" do
|
||||
@f.should_receive(:message).with(:text, '', 'Hello')
|
||||
@f << "\x84\x05\x48\x65\x6c\x6c\x6f" # "\x84\x05Hello"
|
||||
end
|
||||
|
||||
it "a fragmented text message" do
|
||||
@f.should_receive(:message).with(:text, '', 'Hello')
|
||||
@f << "\x04\x03Hel"
|
||||
@f << "\x80\x02lo"
|
||||
end
|
||||
|
||||
it "Ping request" do
|
||||
@f.should_receive(:message).with(:ping, '', 'Hello')
|
||||
@f << "\x82\x05Hello"
|
||||
end
|
||||
|
||||
it "a pong response" do
|
||||
@f.should_receive(:message).with(:pong, '', 'Hello')
|
||||
@f << "\x83\x05Hello"
|
||||
end
|
||||
|
||||
it "256 bytes binary message in a single frame" do
|
||||
data = "a"*256
|
||||
@f.should_receive(:message).with(:binary, '', data)
|
||||
@f << "\x85\x7E\x01\x00" + data
|
||||
end
|
||||
|
||||
it "64KiB binary message in a single frame" do
|
||||
data = "a"*65536
|
||||
@f.should_receive(:message).with(:binary, '', data)
|
||||
@f << "\x85\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data
|
||||
end
|
||||
end
|
||||
|
||||
describe "other tests" do
|
||||
it "should accept a fragmented unmasked text message in 3 frames" do
|
||||
@f.should_receive(:message).with(:text, '', 'Hello world')
|
||||
@f << "\x04\x03Hel"
|
||||
@f << "\x00\x02lo"
|
||||
@f << "\x80\x06 world"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe EM::WebSocket::Framing07 do
|
||||
class FramingContainer07
|
||||
include EM::WebSocket::Framing07
|
||||
|
||||
def initialize
|
||||
@connection = Object.new
|
||||
def @connection.max_frame_size
|
||||
1000000
|
||||
end
|
||||
end
|
||||
|
||||
def <<(data)
|
||||
@data << data
|
||||
process_data
|
||||
end
|
||||
|
||||
def debug(*args); end
|
||||
end
|
||||
|
||||
before :each do
|
||||
@f = FramingContainer07.new
|
||||
@f.initialize_framing
|
||||
end
|
||||
|
||||
# These examples are straight from the spec
|
||||
# http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07#section-4.6
|
||||
describe "examples from the spec" do
|
||||
it "a single-frame unmakedtext message" do
|
||||
@f.should_receive(:message).with(:text, '', 'Hello')
|
||||
@f << "\x81\x05\x48\x65\x6c\x6c\x6f" # "\x84\x05Hello"
|
||||
end
|
||||
|
||||
it "a single-frame masked text message" do
|
||||
@f.should_receive(:message).with(:text, '', 'Hello')
|
||||
@f << "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58" # "\x84\x05Hello"
|
||||
end
|
||||
|
||||
it "a fragmented unmasked text message" do
|
||||
@f.should_receive(:message).with(:text, '', 'Hello')
|
||||
@f << "\x01\x03Hel"
|
||||
@f << "\x80\x02lo"
|
||||
end
|
||||
|
||||
it "Ping request" do
|
||||
@f.should_receive(:message).with(:ping, '', 'Hello')
|
||||
@f << "\x89\x05Hello"
|
||||
end
|
||||
|
||||
it "a pong response" do
|
||||
@f.should_receive(:message).with(:pong, '', 'Hello')
|
||||
@f << "\x8a\x05Hello"
|
||||
end
|
||||
|
||||
it "256 bytes binary message in a single unmasked frame" do
|
||||
data = "a"*256
|
||||
@f.should_receive(:message).with(:binary, '', data)
|
||||
@f << "\x82\x7E\x01\x00" + data
|
||||
end
|
||||
|
||||
it "64KiB binary message in a single unmasked frame" do
|
||||
data = "a"*65536
|
||||
@f.should_receive(:message).with(:binary, '', data)
|
||||
@f << "\x82\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data
|
||||
end
|
||||
end
|
||||
|
||||
describe "other tests" do
|
||||
it "should raise a WSProtocolError if an invalid frame type is requested" do
|
||||
lambda {
|
||||
# Opcode 3 is not supported by this draft
|
||||
@f << "\x83\x05Hello"
|
||||
}.should raise_error(EventMachine::WebSocket::WSProtocolError, "Unknown opcode 3")
|
||||
end
|
||||
|
||||
it "should accept a fragmented unmasked text message in 3 frames" do
|
||||
@f.should_receive(:message).with(:text, '', 'Hello world')
|
||||
@f << "\x01\x03Hel"
|
||||
@f << "\x00\x02lo"
|
||||
@f << "\x80\x06 world"
|
||||
end
|
||||
|
||||
it "should raise if non-fin frame is followed by a non-continuation data frame (continuation frame would be expected)" do
|
||||
lambda {
|
||||
@f << 0b00000001 # Not fin, text
|
||||
@f << 0b00000001 # Length 1
|
||||
@f << 'f'
|
||||
@f << 0b10000001 # fin, text (continutation expected)
|
||||
@f << 0b00000001 # Length 1
|
||||
@f << 'b'
|
||||
}.should raise_error(EM::WebSocket::WebSocketError, 'Continuation frame expected')
|
||||
end
|
||||
|
||||
it "should raise on non-fin control frames (control frames must not be fragmented)" do
|
||||
lambda {
|
||||
@f << 0b00001010 # Not fin, pong (opcode 10)
|
||||
@f << 0b00000000 # Length 1
|
||||
}.should raise_error(EM::WebSocket::WebSocketError, 'Control frames must not be fragmented')
|
||||
end
|
||||
end
|
||||
end
|
||||
216
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/unit/handshake_spec.rb
vendored
Normal file
216
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/unit/handshake_spec.rb
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
require 'helper'
|
||||
|
||||
describe EM::WebSocket::Handshake do
|
||||
def handshake(request, secure = false)
|
||||
handshake = EM::WebSocket::Handshake.new(secure)
|
||||
handshake.receive_data(format_request(request))
|
||||
handshake
|
||||
end
|
||||
|
||||
before :each do
|
||||
@request = {
|
||||
:port => 80,
|
||||
:method => "GET",
|
||||
:path => "/demo",
|
||||
:headers => {
|
||||
'Host' => 'example.com',
|
||||
'Connection' => 'Upgrade',
|
||||
'Sec-WebSocket-Key2' => '12998 5 Y3 1 .P00',
|
||||
'Sec-WebSocket-Protocol' => 'sample',
|
||||
'Upgrade' => 'WebSocket',
|
||||
'Sec-WebSocket-Key1' => '4 @1 46546xW%0l 1 5',
|
||||
'Origin' => 'http://example.com'
|
||||
},
|
||||
:body => '^n:ds[4U'
|
||||
}
|
||||
@secure_request = @request.merge(:port => 443)
|
||||
|
||||
@response = {
|
||||
:headers => {
|
||||
"Upgrade" => "WebSocket",
|
||||
"Connection" => "Upgrade",
|
||||
"Sec-WebSocket-Location" => "ws://example.com/demo",
|
||||
"Sec-WebSocket-Origin" => "http://example.com",
|
||||
"Sec-WebSocket-Protocol" => "sample"
|
||||
},
|
||||
:body => "8jKS\'y:G*Co,Wxa-"
|
||||
}
|
||||
@secure_response = @response.merge(:headers => @response[:headers].merge('Sec-WebSocket-Location' => "wss://example.com/demo"))
|
||||
end
|
||||
|
||||
it "should handle good request" do
|
||||
handshake(@request).should succeed_with_upgrade(@response)
|
||||
end
|
||||
|
||||
it "should handle good request to secure default port if secure mode is enabled" do
|
||||
handshake(@secure_request, true).
|
||||
should succeed_with_upgrade(@secure_response)
|
||||
end
|
||||
|
||||
it "should not handle good request to secure default port if secure mode is disabled" do
|
||||
handshake(@secure_request, false).
|
||||
should_not succeed_with_upgrade(@secure_response)
|
||||
end
|
||||
|
||||
it "should handle good request on nondefault port" do
|
||||
@request[:port] = 8081
|
||||
@request[:headers]['Host'] = 'example.com:8081'
|
||||
@response[:headers]['Sec-WebSocket-Location'] =
|
||||
'ws://example.com:8081/demo'
|
||||
|
||||
handshake(@request).should succeed_with_upgrade(@response)
|
||||
end
|
||||
|
||||
it "should handle good request to secure nondefault port" do
|
||||
@secure_request[:port] = 8081
|
||||
@secure_request[:headers]['Host'] = 'example.com:8081'
|
||||
@secure_response[:headers]['Sec-WebSocket-Location'] = 'wss://example.com:8081/demo'
|
||||
|
||||
handshake(@secure_request, true).
|
||||
should succeed_with_upgrade(@secure_response)
|
||||
end
|
||||
|
||||
it "should handle good request with no protocol" do
|
||||
@request[:headers].delete('Sec-WebSocket-Protocol')
|
||||
@response[:headers].delete("Sec-WebSocket-Protocol")
|
||||
|
||||
handshake(@request).should succeed_with_upgrade(@response)
|
||||
end
|
||||
|
||||
it "should handle extra headers by simply ignoring them" do
|
||||
@request[:headers]['EmptyValue'] = ""
|
||||
@request[:headers]['AKey'] = "AValue"
|
||||
|
||||
handshake(@request).should succeed_with_upgrade(@response)
|
||||
end
|
||||
|
||||
it "should raise error on HTTP request" do
|
||||
@request[:headers] = {
|
||||
'Host' => 'www.google.com',
|
||||
'User-Agent' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 GTB6 GTBA',
|
||||
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||
'Accept-Language' => 'en-us,en;q=0.5',
|
||||
'Accept-Encoding' => 'gzip,deflate',
|
||||
'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
|
||||
'Keep-Alive' => '300',
|
||||
'Connection' => 'keep-alive',
|
||||
}
|
||||
|
||||
handshake(@request).should fail_with_error(EM::WebSocket::HandshakeError)
|
||||
end
|
||||
|
||||
it "should raise error on wrong method" do
|
||||
@request[:method] = 'POST'
|
||||
|
||||
handshake(@request).should fail_with_error(EM::WebSocket::HandshakeError)
|
||||
end
|
||||
|
||||
it "should raise error if upgrade header incorrect" do
|
||||
@request[:headers]['Upgrade'] = 'NonWebSocket'
|
||||
|
||||
handshake(@request).should fail_with_error(EM::WebSocket::HandshakeError)
|
||||
end
|
||||
|
||||
it "should raise error if Sec-WebSocket-Protocol is empty" do
|
||||
@request[:headers]['Sec-WebSocket-Protocol'] = ''
|
||||
|
||||
handshake(@request).should fail_with_error(EM::WebSocket::HandshakeError)
|
||||
end
|
||||
|
||||
%w[Sec-WebSocket-Key1 Sec-WebSocket-Key2].each do |header|
|
||||
it "should raise error if #{header} has zero spaces" do
|
||||
@request[:headers][header] = 'nospaces'
|
||||
|
||||
handshake(@request).
|
||||
should fail_with_error(EM::WebSocket::HandshakeError, 'Websocket Key1 or Key2 does not contain spaces - this is a symptom of a cross-protocol attack')
|
||||
end
|
||||
end
|
||||
|
||||
it "should raise error if Sec-WebSocket-Key1 is missing" do
|
||||
@request[:headers].delete("Sec-WebSocket-Key1")
|
||||
|
||||
# The error message isn't correct since key1 is used to heuristically
|
||||
# determine the protocol version in use, however this test at least checks
|
||||
# that the handshake does correctly fail
|
||||
handshake(@request).
|
||||
should fail_with_error(EM::WebSocket::HandshakeError, 'Extra bytes after header')
|
||||
end
|
||||
|
||||
it "should raise error if Sec-WebSocket-Key2 is missing" do
|
||||
@request[:headers].delete("Sec-WebSocket-Key2")
|
||||
|
||||
handshake(@request).
|
||||
should fail_with_error(EM::WebSocket::HandshakeError, 'WebSocket key1 or key2 is missing')
|
||||
end
|
||||
|
||||
it "should raise error if spaces do not divide numbers in Sec-WebSocket-Key* " do
|
||||
@request[:headers]['Sec-WebSocket-Key2'] = '12998 5 Y3 1.P00'
|
||||
|
||||
handshake(@request).
|
||||
should fail_with_error(EM::WebSocket::HandshakeError, 'Invalid Key "12998 5 Y3 1.P00"')
|
||||
end
|
||||
|
||||
it "should raise error if the HTTP header is empty" do
|
||||
handshake = EM::WebSocket::Handshake.new(false)
|
||||
handshake.receive_data("\r\n\r\nfoobar")
|
||||
|
||||
handshake.
|
||||
should fail_with_error(EM::WebSocket::HandshakeError, 'Invalid HTTP header: Could not parse data entirely (4 != 10)')
|
||||
end
|
||||
|
||||
# This might seems crazy, but very occasionally we saw multiple "Upgrade:
|
||||
# WebSocket" headers in the wild. RFC 4.2.1 isn't particularly clear on this
|
||||
# point, so for now I have decided not to accept --@mloughran
|
||||
it "should raise error on multiple upgrade headers" do
|
||||
handshake = EM::WebSocket::Handshake.new(false)
|
||||
|
||||
# Add a duplicate upgrade header
|
||||
headers = format_request(@request)
|
||||
upgrade_header = "Upgrade: WebSocket\r\n"
|
||||
headers.gsub!(upgrade_header, "#{upgrade_header}#{upgrade_header}")
|
||||
|
||||
handshake.receive_data(headers)
|
||||
|
||||
handshake.errback { |e|
|
||||
e.class.should == EM::WebSocket::HandshakeError
|
||||
e.message.should == 'Invalid upgrade header: ["WebSocket", "WebSocket"]'
|
||||
}
|
||||
end
|
||||
|
||||
it "should cope with requests where the header is split" do
|
||||
request = format_request(@request)
|
||||
incomplete_request = request[0...(request.length / 2)]
|
||||
rest = request[(request.length / 2)..-1]
|
||||
handshake = EM::WebSocket::Handshake.new(false)
|
||||
handshake.receive_data(incomplete_request)
|
||||
|
||||
handshake.instance_variable_get(:@deferred_status).should == nil
|
||||
|
||||
# Send the remaining header
|
||||
handshake.receive_data(rest)
|
||||
|
||||
handshake(@request).should succeed_with_upgrade(@response)
|
||||
end
|
||||
|
||||
it "should cope with requests where the third key is split" do
|
||||
request = format_request(@request)
|
||||
# Removes last two bytes of the third key
|
||||
incomplete_request = request[0..-3]
|
||||
rest = request[-2..-1]
|
||||
handshake = EM::WebSocket::Handshake.new(false)
|
||||
handshake.receive_data(incomplete_request)
|
||||
|
||||
handshake.instance_variable_get(:@deferred_status).should == nil
|
||||
|
||||
# Send the remaining third key
|
||||
handshake.receive_data(rest)
|
||||
|
||||
handshake(@request).should succeed_with_upgrade(@response)
|
||||
end
|
||||
|
||||
it "should fail if the request URI is invalid" do
|
||||
@request[:path] = "/%"
|
||||
handshake(@request).should \
|
||||
fail_with_error(EM::WebSocket::HandshakeError, 'Invalid request URI: /%')
|
||||
end
|
||||
end
|
||||
29
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/unit/masking_spec.rb
vendored
Normal file
29
vendor/bundle/ruby/2.6.0/gems/em-websocket-0.5.2/spec/unit/masking_spec.rb
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# encoding: BINARY
|
||||
|
||||
require 'helper'
|
||||
|
||||
describe EM::WebSocket::MaskedString do
|
||||
it "should allow reading 4 byte mask and unmasking byte / bytes" do
|
||||
t = EM::WebSocket::MaskedString.new("\x00\x00\x00\x01\x00\x01\x00\x01")
|
||||
t.read_mask
|
||||
t.getbyte(3).should == 0x00
|
||||
t.getbytes(4, 4).should == "\x00\x01\x00\x00"
|
||||
t.getbytes(5, 3).should == "\x01\x00\x00"
|
||||
end
|
||||
|
||||
it "should return nil from getbyte if index requested is out of range" do
|
||||
t = EM::WebSocket::MaskedString.new("\x00\x00\x00\x00\x53")
|
||||
t.read_mask
|
||||
t.getbyte(4).should == 0x53
|
||||
t.getbyte(5).should == nil
|
||||
end
|
||||
|
||||
it "should allow switching masking on and off" do
|
||||
t = EM::WebSocket::MaskedString.new("\x02\x00\x00\x00\x03")
|
||||
t.getbyte(4).should == 0x03
|
||||
t.read_mask
|
||||
t.getbyte(4).should == 0x01
|
||||
t.unset_mask
|
||||
t.getbyte(4).should == 0x03
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user