/
client.rb
117 lines (89 loc) · 2.96 KB
/
client.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
require 'forwardable'
module Faye
class WebSocket
class Client
extend Forwardable
include API
DEFAULT_PORTS = { 'http' => 80, 'https' => 443, 'ws' => 80, 'wss' => 443 }
SECURE_PROTOCOLS = ['https', 'wss']
def_delegators :@driver, :headers, :status
def initialize(url, protocols = nil, options = {})
@url = url
super(options) { ::WebSocket::Driver.client(self, :max_length => options[:max_length], :protocols => protocols) }
proxy = options.fetch(:proxy, {})
@endpoint = URI.parse(proxy[:origin] || @url)
port = @endpoint.port || DEFAULT_PORTS[@endpoint.scheme]
@origin_tls = options.fetch(:tls, {})
@socket_tls = proxy[:origin] ? proxy.fetch(:tls, {}) : @origin_tls
configure_proxy(proxy)
EventMachine.connect(@endpoint.host, port, Connection) do |conn|
conn.parent = self
end
rescue => error
on_network_error(error)
end
private
def configure_proxy(proxy)
return unless proxy[:origin]
@proxy = @driver.proxy(proxy[:origin])
@proxy.on(:error) { |error| @driver.emit(:error, error) }
if headers = proxy[:headers]
headers.each { |name, value| @proxy.set_header(name, value) }
end
@proxy.on(:connect) do
@proxy = nil
start_tls(URI.parse(@url), @origin_tls)
@driver.start
end
end
def start_tls(uri, options)
return unless SECURE_PROTOCOLS.include?(uri.scheme)
tls_options = { :sni_hostname => uri.host, :verify_peer => true }.merge(options)
@ssl_verifier = SslVerifier.new(uri.host, tls_options)
@stream.start_tls(tls_options)
end
def on_connect(stream)
@stream = stream
start_tls(@endpoint, @socket_tls)
worker = @proxy || @driver
worker.start
end
def on_network_error(error)
emit_error("Network error: #{ @url }: #{ error.message }")
finalize_close
end
def ssl_verify_peer(cert)
@ssl_verifier.ssl_verify_peer(cert)
rescue => error
on_network_error(error)
end
def ssl_handshake_completed
@ssl_verifier.ssl_handshake_completed
rescue => error
on_network_error(error)
end
module Connection
attr_accessor :parent
def connection_completed
parent.__send__(:on_connect, self)
end
def ssl_verify_peer(cert)
parent.__send__(:ssl_verify_peer, cert)
end
def ssl_handshake_completed
parent.__send__(:ssl_handshake_completed)
end
def receive_data(data)
parent.__send__(:parse, data)
end
def unbind(error = nil)
parent.__send__(:emit_error, error) if error
parent.__send__(:finalize_close)
end
def write(data)
send_data(data) rescue nil
end
end
end
end
end