async-websocket 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -19,18 +19,30 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require "async/websocket/client"
22
+ require "async/websocket/response"
22
23
 
23
24
  RSpec.describe Async::WebSocket::Client do
24
- context "headers:" do
25
+ describe '#connect' do
25
26
  let(:headers) {[
26
27
  ["Foo", "Bar"],
27
28
  ["Baz", "Qux"]
28
29
  ]}
29
30
 
30
- subject {described_class.new(nil, headers: headers)}
31
+ let(:client) {double}
32
+ let(:stream) {double}
33
+
34
+ subject {described_class.new(client)}
35
+ let(:response) {Protocol::HTTP::Response.new(nil, 101, "Switching Protocols", {}, nil, Protocol::WebSocket::Headers::PROTOCOL)}
31
36
 
32
37
  it "sets client request headers" do
33
- expect(subject.request_headers.to_h).to include(headers.to_h)
38
+ expect(response).to receive(:stream?).and_return(true)
39
+ expect(response).to receive(:stream).and_return(stream)
40
+
41
+ expect(client).to receive(:call) do |request|
42
+ expect(request.headers.to_h).to include("Foo", "Baz")
43
+ end.and_return(response)
44
+
45
+ subject.connect("/server", headers: headers)
34
46
  end
35
47
  end
36
48
  end
@@ -0,0 +1,77 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'async/websocket/client'
22
+ require 'async/websocket/server'
23
+
24
+ require 'async/http/client'
25
+ require 'async/http/server'
26
+ require 'async/http/endpoint'
27
+
28
+ RSpec.shared_context Async::WebSocket::Server do
29
+ include_context Async::RSpec::Reactor
30
+
31
+ let(:protocol) {described_class}
32
+ let(:endpoint) {Async::HTTP::Endpoint.parse('http://127.0.0.1:8008', reuse_port: true)}
33
+
34
+ let!(:client) {Async::WebSocket::Client.open(endpoint, protocol)}
35
+
36
+ let!(:server_task) do
37
+ reactor.async do
38
+ server.run
39
+ end
40
+ end
41
+
42
+ after(:each) do
43
+ Async.logger.debug(client, "Closing client...")
44
+ client.close
45
+ Async.logger.debug(server_task, "Closing server...")
46
+ server_task.stop
47
+ end
48
+
49
+ let(:handler) {Async::WebSocket::Connection}
50
+ let(:headers) {Array.new}
51
+
52
+ let(:server) do
53
+ Async::HTTP::Server.for(endpoint, protocol) do |request|
54
+ if Async::WebSocket::Request.websocket?(request)
55
+ Async::WebSocket::Response.for(request, headers) do |stream|
56
+ framer = Protocol::WebSocket::Framer.new(stream)
57
+
58
+ connection = handler.call(framer)
59
+
60
+ connection.close
61
+ end
62
+ else
63
+ Protocol::HTTP::Response[404, {}, []]
64
+ end
65
+ end
66
+ end
67
+
68
+ it "can establish connection" do
69
+ connection = client.connect("/server")
70
+
71
+ expect(connection.read).to be_nil
72
+ expect(connection).to be_closed
73
+
74
+ Async.logger.debug(connection, "Closing connection...")
75
+ connection.close
76
+ end
77
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative "server_examples"
22
+
23
+ require "async/http/protocol/http1"
24
+
25
+ RSpec.describe Async::HTTP::Protocol::HTTP1 do
26
+ include_context Async::WebSocket::Server
27
+ end
28
+
29
+ RSpec.describe Async::HTTP::Protocol::HTTP2 do
30
+ include_context Async::WebSocket::Server
31
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-websocket
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-12 00:00:00.000000000 Z
11
+ date: 2019-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-io
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.23'
27
27
  - !ruby/object:Gem::Dependency
28
- name: protocol-http1
28
+ name: async-http
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.4'
33
+ version: '0.41'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0.4'
40
+ version: '0.41'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: protocol-websocket
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -190,17 +190,26 @@ files:
190
190
  - examples/utopia/tasks/log.rake
191
191
  - examples/utopia/tasks/static.rake
192
192
  - lib/async/websocket.rb
193
+ - lib/async/websocket/adapters/rack.rb
193
194
  - lib/async/websocket/client.rb
195
+ - lib/async/websocket/connect_request.rb
196
+ - lib/async/websocket/connect_response.rb
194
197
  - lib/async/websocket/connection.rb
195
198
  - lib/async/websocket/error.rb
199
+ - lib/async/websocket/proxy.rb
200
+ - lib/async/websocket/request.rb
201
+ - lib/async/websocket/response.rb
196
202
  - lib/async/websocket/server.rb
197
- - lib/async/websocket/server/rack.rb
203
+ - lib/async/websocket/upgrade_request.rb
204
+ - lib/async/websocket/upgrade_response.rb
198
205
  - lib/async/websocket/version.rb
206
+ - spec/async/websocket/adapters/rack/client.rb
207
+ - spec/async/websocket/adapters/rack/config.ru
208
+ - spec/async/websocket/adapters/rack_spec.rb
199
209
  - spec/async/websocket/client_spec.rb
200
210
  - spec/async/websocket/connection_spec.rb
201
- - spec/async/websocket/server/rack/client.rb
202
- - spec/async/websocket/server/rack/config.ru
203
- - spec/async/websocket/server/rack_spec.rb
211
+ - spec/async/websocket/server_examples.rb
212
+ - spec/async/websocket/server_spec.rb
204
213
  - spec/async/websocket/upgrade.rb
205
214
  - spec/spec_helper.rb
206
215
  homepage: ''
@@ -222,15 +231,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
231
  - !ruby/object:Gem::Version
223
232
  version: '0'
224
233
  requirements: []
225
- rubygems_version: 3.0.3
234
+ rubygems_version: 3.0.2
226
235
  signing_key:
227
236
  specification_version: 4
228
237
  summary: An async websocket library on top of websocket-driver.
229
238
  test_files:
239
+ - spec/async/websocket/adapters/rack/client.rb
240
+ - spec/async/websocket/adapters/rack/config.ru
241
+ - spec/async/websocket/adapters/rack_spec.rb
230
242
  - spec/async/websocket/client_spec.rb
231
243
  - spec/async/websocket/connection_spec.rb
232
- - spec/async/websocket/server/rack/client.rb
233
- - spec/async/websocket/server/rack/config.ru
234
- - spec/async/websocket/server/rack_spec.rb
244
+ - spec/async/websocket/server_examples.rb
245
+ - spec/async/websocket/server_spec.rb
235
246
  - spec/async/websocket/upgrade.rb
236
247
  - spec/spec_helper.rb
@@ -1,104 +0,0 @@
1
- # frozen_string_literals: true
2
- #
3
- # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require 'protocol/websocket/digest'
24
-
25
- require_relative '../connection'
26
-
27
- module Async
28
- module WebSocket
29
- module Server
30
- class Rack
31
- def self.websocket?(env)
32
- env['HTTP_UPGRADE'] == "websocket"
33
- end
34
-
35
- def self.open(env, **options, &block)
36
- # Is hijack supported:
37
- return nil unless env['rack.hijack?']
38
-
39
- return nil unless websocket?(env)
40
-
41
- server = self.new(env, **options)
42
-
43
- if server.supported?
44
- return server.response(&block)
45
- else
46
- return nil
47
- end
48
- end
49
-
50
- def initialize(env, supported_protocols: [], connect: Connection)
51
- # scheme = env['rack.url_scheme'] == 'https' ? 'wss' : 'ws'
52
- # @url = "#{scheme}://#{env['HTTP_HOST']}#{env['REQUEST_URI']}"
53
- @key = env['HTTP_SEC_WEBSOCKET_KEY']
54
- @version = Integer(env['HTTP_SEC_WEBSOCKET_VERSION'])
55
-
56
- @protocol = negotiate_protocol(env, supported_protocols)
57
-
58
- @connect = connect
59
- end
60
-
61
- def negotiate_protocol(env, supported_protocols)
62
- if supported_protocols and client_protocols = env['HTTP_SEC_WEBSOCKET_PROTOCOL']
63
- return (supported_protocols & client_protocols.split(/\s*,\s/)).first
64
- end
65
- end
66
-
67
- attr :protocol
68
-
69
- def supported?
70
- @key and @version == 13
71
- end
72
-
73
- def make_connection(stream)
74
- framer = Protocol::WebSocket::Framer.new(stream)
75
-
76
- return @connect.call(framer, @protocol)
77
- end
78
-
79
- def response_headers
80
- headers = [
81
- ['connection', 'upgrade'],
82
- ['upgrade', 'websocket'],
83
- ['sec-websocket-accept', ::Protocol::WebSocket.accept_digest(@key)],
84
- ]
85
-
86
- if @protocol
87
- headers << ['sec-websocket-protocol', @protocol]
88
- end
89
-
90
- return headers
91
- end
92
-
93
- def response(&block)
94
- headers = [
95
- ['rack.hijack', ->(stream){block.call(make_connection(stream))}]
96
- ]
97
-
98
- # https://stackoverflow.com/questions/13545453/http-response-code-when-requested-websocket-subprotocol-isnt-supported-recogniz
99
- return [101, response_headers + headers, nil]
100
- end
101
- end
102
- end
103
- end
104
- end