Make a WS class to eliminate globals

This commit is contained in:
Arlo Breault 2019-05-01 10:11:15 -04:00
parent f3254e3402
commit bd5887a876
5 changed files with 90 additions and 85 deletions

View file

@ -18,6 +18,7 @@ FILES_SPEC = [
'spec/broker.spec.coffee' 'spec/broker.spec.coffee'
'spec/proxypair.spec.coffee' 'spec/proxypair.spec.coffee'
'spec/snowflake.spec.coffee' 'spec/snowflake.spec.coffee'
'spec/websocket.spec.coffee'
] ]
FILES_ALL = FILES.concat FILES_SPEC FILES_ALL = FILES.concat FILES_SPEC
OUTFILE = 'build/snowflake.js' OUTFILE = 'build/snowflake.js'

View file

@ -103,7 +103,7 @@ class ProxyPair
if peer_ip? if peer_ip?
params.push(["client_ip", peer_ip]) params.push(["client_ip", peer_ip])
@relay = makeWebsocket @relayAddr, params @relay = WS.makeWebsocket @relayAddr, params
@relay.label = 'websocket-relay' @relay.label = 'websocket-relay'
@relay.onopen = => @relay.onopen = =>
if @timer if @timer

View file

@ -2,41 +2,6 @@
jasmine tests for Snowflake utils jasmine tests for Snowflake utils
### ###
describe 'BuildUrl', ->
it 'should parse just protocol and host', ->
expect(buildUrl('http', 'example.com')).toBe 'http://example.com'
it 'should handle different ports', ->
expect buildUrl 'http', 'example.com', 80
.toBe 'http://example.com'
expect buildUrl 'http', 'example.com', 81
.toBe 'http://example.com:81'
expect buildUrl 'http', 'example.com', 443
.toBe 'http://example.com:443'
expect buildUrl 'http', 'example.com', 444
.toBe 'http://example.com:444'
it 'should handle paths', ->
expect buildUrl 'http', 'example.com', 80, '/'
.toBe 'http://example.com/'
expect buildUrl 'http', 'example.com', 80,'/test?k=%#v'
.toBe 'http://example.com/test%3Fk%3D%25%23v'
expect buildUrl 'http', 'example.com', 80, '/test'
.toBe 'http://example.com/test'
it 'should handle params', ->
expect buildUrl 'http', 'example.com', 80, '/test', [['k', '%#v']]
.toBe 'http://example.com/test?k=%25%23v'
expect buildUrl 'http', 'example.com', 80, '/test', [['a', 'b'], ['c', 'd']]
.toBe 'http://example.com/test?a=b&c=d'
it 'should handle ips', ->
expect buildUrl 'http', '1.2.3.4'
.toBe 'http://1.2.3.4'
expect buildUrl 'http', '1:2::3:4'
.toBe 'http://[1:2::3:4]'
it 'should handle bogus', ->
expect buildUrl 'http', 'bog][us'
.toBe 'http://bog%5D%5Bus'
expect buildUrl 'http', 'bog:u]s'
.toBe 'http://bog%3Au%5Ds'
describe 'Parse', -> describe 'Parse', ->
describe 'cookie', -> describe 'cookie', ->

View file

@ -0,0 +1,38 @@
###
jasmine tests for Snowflake websocket
###
describe 'BuildUrl', ->
it 'should parse just protocol and host', ->
expect(WS.buildUrl('http', 'example.com')).toBe 'http://example.com'
it 'should handle different ports', ->
expect WS.buildUrl 'http', 'example.com', 80
.toBe 'http://example.com'
expect WS.buildUrl 'http', 'example.com', 81
.toBe 'http://example.com:81'
expect WS.buildUrl 'http', 'example.com', 443
.toBe 'http://example.com:443'
expect WS.buildUrl 'http', 'example.com', 444
.toBe 'http://example.com:444'
it 'should handle paths', ->
expect WS.buildUrl 'http', 'example.com', 80, '/'
.toBe 'http://example.com/'
expect WS.buildUrl 'http', 'example.com', 80,'/test?k=%#v'
.toBe 'http://example.com/test%3Fk%3D%25%23v'
expect WS.buildUrl 'http', 'example.com', 80, '/test'
.toBe 'http://example.com/test'
it 'should handle params', ->
expect WS.buildUrl 'http', 'example.com', 80, '/test', [['k', '%#v']]
.toBe 'http://example.com/test?k=%25%23v'
expect WS.buildUrl 'http', 'example.com', 80, '/test', [['a', 'b'], ['c', 'd']]
.toBe 'http://example.com/test?a=b&c=d'
it 'should handle ips', ->
expect WS.buildUrl 'http', '1.2.3.4'
.toBe 'http://1.2.3.4'
expect WS.buildUrl 'http', '1:2::3:4'
.toBe 'http://[1:2::3:4]'
it 'should handle bogus', ->
expect WS.buildUrl 'http', 'bog][us'
.toBe 'http://bog%5D%5Bus'
expect WS.buildUrl 'http', 'bog:u]s'
.toBe 'http://bog%3Au%5Ds'

View file

@ -2,58 +2,59 @@
Only websocket-specific stuff. Only websocket-specific stuff.
### ###
WSS_ENABLED = true class WS
DEFAULT_PORTS = @WSS_ENABLED: true
http: 80 @DEFAULT_PORTS:
https: 443 http: 80
https: 443
# Build an escaped URL string from unescaped components. Only scheme and host # Build an escaped URL string from unescaped components. Only scheme and host
# are required. See RFC 3986, section 3. # are required. See RFC 3986, section 3.
buildUrl = (scheme, host, port, path, params) -> @buildUrl: (scheme, host, port, path, params) ->
parts = [] parts = []
parts.push(encodeURIComponent scheme) parts.push(encodeURIComponent scheme)
parts.push '://' parts.push '://'
# If it contains a colon but no square brackets, treat it as IPv6. # If it contains a colon but no square brackets, treat it as IPv6.
if host.match(/:/) && !host.match(/[[\]]/) if host.match(/:/) && !host.match(/[[\]]/)
parts.push '[' parts.push '['
parts.push host parts.push host
parts.push ']' parts.push ']'
else else
parts.push(encodeURIComponent host) parts.push(encodeURIComponent host)
if undefined != port && DEFAULT_PORTS[scheme] != port if undefined != port && @DEFAULT_PORTS[scheme] != port
parts.push ':' parts.push ':'
parts.push(encodeURIComponent port.toString()) parts.push(encodeURIComponent port.toString())
if undefined != path && '' != path if undefined != path && '' != path
if !path.match(/^\//) if !path.match(/^\//)
path = '/' + path path = '/' + path
###
Slash is significant so we must protect it from encodeURIComponent, while
still encoding question mark and number sign. RFC 3986, section 3.3: 'The
path is terminated by the first question mark ('?') or number sign ('#')
character, or by the end of the URI. ... A path consists of a sequence of
path segments separated by a slash ('/') character.'
###
path = path.replace /[^\/]+/, (m) ->
encodeURIComponent m
parts.push path
if undefined != params
parts.push '?'
parts.push Query.buildString params
parts.join ''
@makeWebsocket: (addr, params) ->
wsProtocol = if @WSS_ENABLED then 'wss' else 'ws'
url = @buildUrl wsProtocol, addr.host, addr.port, '/', params
ws = new WebSocket url
### ###
Slash is significant so we must protect it from encodeURIComponent, while 'User agents can use this as a hint for how to handle incoming binary data: if
still encoding question mark and number sign. RFC 3986, section 3.3: 'The the attribute is set to 'blob', it is safe to spool it to disk, and if it is
path is terminated by the first question mark ('?') or number sign ('#') set to 'arraybuffer', it is likely more efficient to keep the data in memory.'
character, or by the end of the URI. ... A path consists of a sequence of
path segments separated by a slash ('/') character.'
### ###
path = path.replace /[^\/]+/, (m) -> ws.binaryType = 'arraybuffer'
encodeURIComponent m ws
parts.push path
if undefined != params
parts.push '?'
parts.push Query.buildString params
parts.join ''
makeWebsocket = (addr, params) ->
wsProtocol = if WSS_ENABLED then 'wss' else 'ws'
url = buildUrl wsProtocol, addr.host, addr.port, '/', params
ws = new WebSocket url
###
'User agents can use this as a hint for how to handle incoming binary data: if
the attribute is set to 'blob', it is safe to spool it to disk, and if it is
set to 'arraybuffer', it is likely more efficient to keep the data in memory.'
###
ws.binaryType = 'arraybuffer'
ws