libwebsocket 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ module LibWebSocket
2
+ # Base class for all classes with states
3
+ module Stateful
4
+
5
+ attr_accessor :state
6
+
7
+ # Return true if current state match given state
8
+ def state?(val)
9
+ @state == val
10
+ end
11
+
12
+ # Change state to 'done'
13
+ def done
14
+ @state = 'done'
15
+ true
16
+ end
17
+
18
+ # Check if current state is done
19
+ def done?
20
+ @state == 'done'
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,67 @@
1
+ require 'addressable/uri'
2
+
3
+ module LibWebSocket
4
+ # Construct or parse a WebSocket URL.
5
+ class URL
6
+
7
+ attr_accessor :secure, :host, :port, :resource_name
8
+
9
+ def initialize(hash = {})
10
+ hash.each do |k,v|
11
+ instance_variable_set("@#{k}",v)
12
+ end
13
+
14
+ @secure ||= false
15
+ end
16
+
17
+ # Parse a WebSocket URL.
18
+ # @example Parse
19
+ # url = LibWebSocket::URL.new
20
+ # url.parse('wss://example.com:3000')
21
+ # url.host # => example.com
22
+ # url.port # => 3000
23
+ # url.secure # => true
24
+ def parse(string)
25
+ return nil unless string.is_a?(String)
26
+
27
+ uri = Addressable::URI.parse(string)
28
+
29
+ scheme = uri.scheme
30
+ return nil unless scheme
31
+
32
+ self.secure = true if scheme.match(/ss\Z/m)
33
+
34
+ host = uri.host
35
+ host = '/' unless host && host != ''
36
+ self.host = host
37
+ self.port = uri.port.to_s if uri.port
38
+
39
+ path = uri.path
40
+ path = '/' unless path && path != ''
41
+ self.resource_name = path
42
+
43
+ return self
44
+ end
45
+
46
+ # Construct a WebSocket URL.
47
+ # @example Construct
48
+ # url = LibWebSocket::URL.new
49
+ # url.host = 'example.com'
50
+ # url.port = '3000'
51
+ # url.secure = true
52
+ # url.to_s # => 'wss://example.com:3000'
53
+ def to_s
54
+ string = ''
55
+
56
+ string += 'ws'
57
+ string += 's' if self.secure
58
+ string += '://'
59
+ string += self.host
60
+ string += ':' + self.port.to_s if self.port
61
+ string += self.resource_name || '/'
62
+
63
+ return string
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ class TestCookieRequest < Test::Unit::TestCase
4
+
5
+ def test_parse
6
+ cookie = LibWebSocket::Cookie::Request.new
7
+ cookies = cookie.parse('$Version=1; foo=bar; $Path=/; $Domain=.example.com')
8
+ assert_equal 'foo', cookies[0].name
9
+ assert_equal 'bar', cookies[0].value
10
+ assert_equal 1, cookies[0].version
11
+ assert_equal '/', cookies[0].path
12
+ assert_equal '.example.com', cookies[0].domain
13
+
14
+ cookie = LibWebSocket::Cookie::Request.new
15
+ cookies = cookie.parse('$Version=1; foo=bar')
16
+ assert_equal 'foo', cookies[0].name
17
+ assert_equal 'bar', cookies[0].value
18
+ assert_equal 1, cookies[0].version
19
+ assert_equal nil, cookies[0].path
20
+ assert_equal nil, cookies[0].domain
21
+
22
+ cookie = LibWebSocket::Cookie::Request.new
23
+ cookies = cookie.parse('$Version=1; foo="hello\"there"')
24
+ assert_equal 'foo', cookies[0].name
25
+ assert_equal 'hello"there', cookies[0].value
26
+
27
+ cookie = LibWebSocket::Cookie::Request.new
28
+ cookies = cookie.parse('$Version=1; foo="bar"; $Path=/; bar=baz; $Domain=.example.com')
29
+ assert_equal 'foo', cookies[0].name
30
+ assert_equal 'bar', cookies[0].value
31
+ assert_equal '/', cookies[0].path
32
+ assert_equal 'bar', cookies[1].name
33
+ assert_equal 'baz', cookies[1].value
34
+ assert_equal '.example.com', cookies[1].domain
35
+ end
36
+
37
+ end
@@ -0,0 +1,32 @@
1
+ require 'test_helper'
2
+
3
+ class TestCookieResponse < Test::Unit::TestCase
4
+
5
+ def test_to_s
6
+ cookie = LibWebSocket::Cookie::Response.new(:name => 'foo', :value => 'bar')
7
+ assert_equal 'foo=bar; Version=1', cookie.to_s
8
+
9
+ cookie = LibWebSocket::Cookie::Response.new(
10
+ :name => 'foo',
11
+ :value => 'bar',
12
+ :discard => 1,
13
+ :max_age => 0
14
+ )
15
+ assert_equal 'foo=bar; Discard; Max-Age=0; Version=1', cookie.to_s
16
+
17
+ cookie = LibWebSocket::Cookie::Response.new(
18
+ :name => 'foo',
19
+ :value => 'bar',
20
+ :portlist => 80
21
+ )
22
+ assert_equal 'foo=bar; Port="80"; Version=1', cookie.to_s
23
+
24
+ cookie = LibWebSocket::Cookie::Response.new(
25
+ :name => 'foo',
26
+ :value => 'bar',
27
+ :portlist => [80, 443]
28
+ )
29
+ assert_equal 'foo=bar; Port="80 443"; Version=1', cookie.to_s
30
+ end
31
+
32
+ end
@@ -0,0 +1,64 @@
1
+ require 'test_helper'
2
+
3
+ class TestServerHandshake < Test::Unit::TestCase
4
+
5
+ def test_to_s
6
+ h = LibWebSocket::Handshake::Client.new
7
+ h.url = 'ws://example.com/demo'
8
+
9
+ # Mocking
10
+ h.req.key1 = "18x 6]8vM;54 *(5: { U1]8 z [ 8"
11
+ h.req.key2 = "1_ tx7X d < nw 334J702) 7]o}` 0"
12
+ h.req.challenge = "Tm[K T2u"
13
+
14
+ assert_equal h.to_s, "GET /demo HTTP/1.1\x0d\x0a" +
15
+ "Upgrade: WebSocket\x0d\x0a" +
16
+ "Connection: Upgrade\x0d\x0a" +
17
+ "Host: example.com\x0d\x0a" +
18
+ "Origin: http://example.com\x0d\x0a" +
19
+ "Sec-WebSocket-Key1: 18x 6]8vM;54 *(5: { U1]8 z [ 8\x0d\x0a" +
20
+ "Sec-WebSocket-Key2: 1_ tx7X d < nw 334J702) 7]o}` 0\x0d\x0a" +
21
+ "Content-Length: 8\x0d\x0a" +
22
+ "\x0d\x0aTm[K T2u"
23
+
24
+ h = LibWebSocket::Handshake::Client.new(:url => 'ws://example.com')
25
+
26
+ # Mocking
27
+ h.req.key1 = "18x 6]8vM;54 *(5: { U1]8 z [ 8"
28
+ h.req.key2 = "1_ tx7X d < nw 334J702) 7]o}` 0"
29
+ h.req.challenge = "Tm[K T2u"
30
+
31
+ assert_equal h.to_s, "GET / HTTP/1.1\x0d\x0a" +
32
+ "Upgrade: WebSocket\x0d\x0a" +
33
+ "Connection: Upgrade\x0d\x0a" +
34
+ "Host: example.com\x0d\x0a" +
35
+ "Origin: http://example.com\x0d\x0a" +
36
+ "Sec-WebSocket-Key1: 18x 6]8vM;54 *(5: { U1]8 z [ 8\x0d\x0a" +
37
+ "Sec-WebSocket-Key2: 1_ tx7X d < nw 334J702) 7]o}` 0\x0d\x0a" +
38
+ "Content-Length: 8\x0d\x0a" +
39
+ "\x0d\x0aTm[K T2u"
40
+
41
+ assert !h.done?
42
+ assert h.parse('')
43
+
44
+ assert h.parse("HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a" +
45
+ "Upgrade: WebSocket\x0d\x0a" +
46
+ "Connection: Upgrade\x0d\x0a" +
47
+ "Sec-WebSocket-Origin: http://example.com\x0d\x0a" +
48
+ "Sec-WebSocket-Location: ws://example.com/demo\x0d\x0a" +
49
+ "\x0d\x0a" +
50
+ "fQJ,fN/4F4!~K~MH")
51
+ assert !h.error
52
+ assert h.done?
53
+
54
+ message = "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
55
+ h = LibWebSocket::Handshake::Client.new(:url => 'ws://example.com')
56
+ assert h.parse(message)
57
+ assert !h.error
58
+
59
+ h = LibWebSocket::Handshake::Client.new
60
+ assert !h.parse("HTTP/1.0 foo bar\x0d\x0a")
61
+ assert_equal 'Wrong response line', h.error
62
+ end
63
+
64
+ end
@@ -0,0 +1,39 @@
1
+ require 'test_helper'
2
+
3
+ class TestServerHandshake < Test::Unit::TestCase
4
+
5
+ def test_parse
6
+ h = LibWebSocket::Handshake::Server.new
7
+ assert !h.done?
8
+ assert h.parse('')
9
+
10
+ assert h.parse("GET /demo HTTP/1.1\x0d\x0a")
11
+ assert h.parse("Upgrade: WebSocket\x0d\x0a")
12
+ assert h.parse("Connection: Upgrade\x0d\x0a")
13
+ assert h.parse("Host: example.com\x0d\x0a")
14
+ assert h.parse("Origin: http://example.com\x0d\x0a")
15
+ assert h.parse("Sec-WebSocket-Key1: 18x 6]8vM;54 *(5: { U1]8 z [ 8\x0d\x0a")
16
+ assert h.parse("Sec-WebSocket-Key2: 1_ tx7X d < nw 334J702) 7]o}` 0\x0d\x0a")
17
+ assert h.parse("\x0d\x0aTm[K T2u")
18
+ assert !h.error
19
+ assert h.done?
20
+
21
+ assert_equal h.to_s, "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a" +
22
+ "Upgrade: WebSocket\x0d\x0a" +
23
+ "Connection: Upgrade\x0d\x0a" +
24
+ "Sec-WebSocket-Origin: http://example.com\x0d\x0a" +
25
+ "Sec-WebSocket-Location: ws://example.com/demo\x0d\x0a" +
26
+ "\x0d\x0a" +
27
+ "fQJ,fN/4F4!~K~MH";
28
+
29
+ message = "GET /demo HTTP/1.1\x0d\x0a"
30
+ h = LibWebSocket::Handshake::Server.new
31
+ assert h.parse(message)
32
+ assert_nil h.error
33
+
34
+ h = LibWebSocket::Handshake::Server.new
35
+ assert_nil h.parse("GET /demo\x0d\x0a")
36
+ assert_equal 'Wrong request line', h.error
37
+ end
38
+
39
+ end
@@ -0,0 +1,21 @@
1
+ require 'test_helper'
2
+
3
+ class TestCookie < Test::Unit::TestCase
4
+
5
+ def test_parse
6
+ cookie = LibWebSocket::Cookie.new
7
+ assert_nil cookie.parse('')
8
+ assert cookie.parse('foo=bar; baz = zab; hello= "the;re"; here')
9
+ assert_equal [['foo', 'bar'], ['baz', 'zab'], ['hello', 'the;re'], ['here', nil]], cookie.pairs
10
+ assert_equal 'foo=bar; baz=zab; hello="the;re"; here', cookie.to_s
11
+
12
+ cookie = LibWebSocket::Cookie.new
13
+ cookie.parse('$Foo="bar"')
14
+ assert_equal [['$Foo', 'bar']], cookie.pairs
15
+
16
+ cookie = LibWebSocket::Cookie.new
17
+ cookie.parse('foo=bar=123=xyz')
18
+ assert_equal [['foo', 'bar=123=xyz']], cookie.pairs
19
+ end
20
+
21
+ end
@@ -0,0 +1,65 @@
1
+ require 'test_helper'
2
+
3
+ class TestFrame < Test::Unit::TestCase
4
+
5
+ def test_append
6
+ f = LibWebSocket::Frame.new
7
+
8
+ f.append
9
+ assert_nil f.next
10
+ f.append('')
11
+ assert_nil f.next
12
+
13
+ f.append('qwe')
14
+ assert_nil f.next
15
+ f.append("\x00foo\xff")
16
+ assert_equal 'foo', f.next
17
+ assert_nil f.next
18
+
19
+ f.append("\x00")
20
+ assert_nil f.next
21
+ f.append("\xff")
22
+ assert_equal '', f.next
23
+
24
+ f.append("\x00")
25
+ assert_nil f.next
26
+ f.append("foo")
27
+ f.append("\xff")
28
+ assert_equal 'foo', f.next
29
+
30
+ f.append("\x00foo\xff\x00bar\n\xff")
31
+ assert_equal 'foo', f.next
32
+ assert_equal "bar\n", f.next
33
+ assert_nil f.next
34
+
35
+ f.append("123\x00foo\xff56\x00bar\xff789")
36
+ assert_equal 'foo', f.next
37
+ assert_equal 'bar', f.next
38
+ assert_nil f.next
39
+
40
+ # We append bytes, but read characters
41
+ msg = "\342\230\272"
42
+ f.append("\x00" + msg + "\xff")
43
+ msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding)
44
+ assert_equal msg, f.next
45
+ end
46
+
47
+ def test_new
48
+ f = LibWebSocket::Frame.new
49
+ msg = "\x00\xff"
50
+ msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding)
51
+ assert_equal msg, f.to_s
52
+
53
+ f = LibWebSocket::Frame.new('123')
54
+ msg = "\x00123\xff"
55
+ msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding)
56
+ assert_equal msg, f.to_s
57
+
58
+ # We pass characters, but send bytes
59
+ f = LibWebSocket::Frame.new("\342\230\272")
60
+ msg = "\x00\342\230\272\xff"
61
+ msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding)
62
+ assert_equal msg, f.to_s
63
+ end
64
+
65
+ end
@@ -0,0 +1,16 @@
1
+ require 'test_helper'
2
+
3
+ class TestMessage < Test::Unit::TestCase
4
+
5
+ def test_parse
6
+ m = LibWebSocket::Message.new
7
+ assert m.parse("HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a")
8
+ assert m.parse("Upgrade: WebSocket\x0d\x0a")
9
+ assert m.parse("Connection: Upgrade\x0d\x0a")
10
+ assert m.parse("Sec-WebSocket-Origin: file://\x0d\x0a")
11
+ assert m.parse("Sec-WebSocket-Location: ws://example.com/demo\x0d\x0a")
12
+ assert m.parse("\x0d\x0a0st\x0d\x0al&q-2ZU^weu")
13
+ assert m.done?
14
+ end
15
+
16
+ end
@@ -0,0 +1,145 @@
1
+ require 'test_helper'
2
+
3
+ class TestRequest75 < Test::Unit::TestCase
4
+
5
+ def test_parse
6
+ req = LibWebSocket::Request.new
7
+ assert !req.done?
8
+ assert req.parse('')
9
+ assert req.parse("GET /demo HTTP/1.1\x0d\x0a")
10
+ assert_equal 'fields', req.state
11
+
12
+ assert req.parse("Upgrade: WebSocket\x0d\x0a")
13
+ assert_equal 'fields', req.state
14
+ assert req.parse("Connection: Upgrade\x0d\x0a")
15
+ assert_equal 'fields', req.state
16
+ assert req.parse("Host: example.com\x0d\x0a")
17
+ assert_equal 'fields', req.state
18
+ assert req.parse("Origin: http://example.com\x0d\x0a")
19
+ assert_equal 'fields', req.state
20
+ assert req.parse("\x0d\x0a")
21
+ assert_equal 'done', req.state
22
+
23
+ assert_equal 75, req.version
24
+ assert_equal '/demo', req.resource_name
25
+ assert_equal 'example.com', req.host
26
+ assert_equal 'http://example.com', req.origin
27
+
28
+ req = LibWebSocket::Request.new
29
+ assert req.parse("GET /demo HTTP/1.1\x0d\x0a")
30
+ assert req.parse("Upgrade: WebSocket\x0d\x0a")
31
+ assert req.parse("Connection: Upgrade\x0d\x0a")
32
+ assert req.parse("Host: example.com:3000\x0d\x0a")
33
+ assert req.parse("Origin: null\x0d\x0a")
34
+ assert req.parse("\x0d\x0a")
35
+ assert_equal 75, req.version
36
+ assert_equal 'done', req.state
37
+
38
+ req = LibWebSocket::Request.new
39
+ assert req.parse("GET /demo HTTP/1.1\x0d\x0a")
40
+ assert req.parse("UPGRADE: WebSocket\x0d\x0a")
41
+ assert req.parse("CONNECTION: Upgrade\x0d\x0a")
42
+ assert req.parse("HOST: example.com:3000\x0d\x0a")
43
+ assert req.parse("ORIGIN: null\x0d\x0a")
44
+ assert req.parse("\x0d\x0a")
45
+ assert_equal 75, req.version
46
+ assert_equal 'done', req.state
47
+
48
+ req = LibWebSocket::Request.new
49
+ assert req.parse("GET /demo HTTP/1.1\x0d\x0a")
50
+ assert req.parse("Upgrade: WebSocket\x0d\x0a")
51
+ assert req.parse("Connection: Upgrade\x0d\x0a")
52
+ assert req.parse("Host: example.com:3000\x0d\x0a")
53
+ assert req.parse("Origin: null\x0d\x0a")
54
+ assert req.parse("WebSocket-Protocol: sample\x0d\x0a")
55
+ assert req.parse("\x0d\x0a")
56
+ assert_equal 75, req.version
57
+ assert_equal 'done', req.state
58
+ assert_equal 'sample', req.subprotocol
59
+
60
+ req = LibWebSocket::Request.new
61
+ message = "GET /demo HTTP/1.1\x0d\x0a" +
62
+ "Upgrade: WebSocket\x0d\x0a" +
63
+ "Connection: Upgrade\x0d\x0a"
64
+ assert req.parse(message)
65
+ message = "Host: example.com:3000\x0d\x0a" + "Origin: null\x0d\x0a" + "\x0d\x0a"
66
+ assert req.parse(message)
67
+ assert_equal 75, req.version
68
+ assert req.done?
69
+
70
+ req = LibWebSocket::Request.new
71
+ assert req.parse("GET /demo HTTP/1.1\x0d\x0a")
72
+ assert req.parse("Upgrade: WebSocket\x0d\x0a")
73
+ assert req.parse("Connection: Upgrade\x0d\x0a")
74
+ assert req.parse("Host: example.com\x0d\x0a")
75
+ assert req.parse("Origin: null\x0d\x0a")
76
+ assert req.parse("cookie: \$Version=1; foo=bar; \$Path=/\x0d\x0a")
77
+ assert req.parse("\x0d\x0a")
78
+ assert req.done?
79
+
80
+ assert_equal req.cookies[0].version, '1'
81
+ assert_equal req.cookies[0].name, 'foo'
82
+ assert_equal req.cookies[0].value, 'bar'
83
+
84
+ req = LibWebSocket::Request.new
85
+ assert req.parse("GET /demo HTTP/1.1\x0d\x0a")
86
+ assert req.parse("Upgrade: WebSocket\x0d\x0a")
87
+ assert req.parse("Connection: Bar\x0d\x0a")
88
+ assert req.parse("Host: example.com\x0d\x0a")
89
+ assert req.parse("Origin: http://example.com\x0d\x0a")
90
+ assert_nil req.parse("\x0d\x0a")
91
+ assert_equal 'error', req.state
92
+ assert_equal 'Not a valid request', req.error
93
+
94
+ req = LibWebSocket::Request.new
95
+ assert req.parse("GET /demo HTTP/1.1\x0d\x0a")
96
+ assert req.parse("Upgrade: WebSocket\x0d\x0a")
97
+ assert req.parse("Connection: Upgrade\x0d\x0a")
98
+ assert req.parse("Host: example.com\x0d\x0a")
99
+ assert req.parse("Origin: http://example.com\x0d\x0a")
100
+ assert_nil req.parse("\x0d\x0afoo")
101
+ assert_equal 'error', req.state
102
+ assert_equal 'Leftovers', req.error
103
+ end
104
+
105
+ def test_to_s
106
+ req = LibWebSocket::Request.new(
107
+ :version => 75,
108
+ :host => 'example.com',
109
+ :resource_name => '/demo'
110
+ )
111
+ assert_equal req.to_s, "GET /demo HTTP/1.1\x0d\x0a" +
112
+ "Upgrade: WebSocket\x0d\x0a" +
113
+ "Connection: Upgrade\x0d\x0a" +
114
+ "Host: example.com\x0d\x0a" +
115
+ "Origin: http://example.com\x0d\x0a" +
116
+ "\x0d\x0a"
117
+
118
+ req = LibWebSocket::Request.new(
119
+ :version => 75,
120
+ :host => 'example.com',
121
+ :subprotocol => 'sample',
122
+ :resource_name => '/demo'
123
+ )
124
+ assert_equal req.to_s, "GET /demo HTTP/1.1\x0d\x0a" +
125
+ "Upgrade: WebSocket\x0d\x0a" +
126
+ "Connection: Upgrade\x0d\x0a" +
127
+ "Host: example.com\x0d\x0a" +
128
+ "Origin: http://example.com\x0d\x0a" +
129
+ "WebSocket-Protocol: sample\x0d\x0a" +
130
+ "\x0d\x0a"
131
+
132
+ req = LibWebSocket::Request.new(
133
+ :version => 75,
134
+ :host => 'example.com',
135
+ :resource_name => '/demo'
136
+ );
137
+ assert_equal req.to_s, "GET /demo HTTP/1.1\x0d\x0a" +
138
+ "Upgrade: WebSocket\x0d\x0a" +
139
+ "Connection: Upgrade\x0d\x0a" +
140
+ "Host: example.com\x0d\x0a" +
141
+ "Origin: http://example.com\x0d\x0a" +
142
+ "\x0d\x0a"
143
+ end
144
+
145
+ end