kinetic_sdk 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (245) hide show
  1. checksums.yaml +7 -0
  2. data/GettingStarted.md +64 -0
  3. data/README.md +383 -0
  4. data/bin/console +12 -0
  5. data/bin/setup +8 -0
  6. data/gems/kontena-websocket-client-0.1.1/Gemfile +4 -0
  7. data/gems/kontena-websocket-client-0.1.1/LICENSE +190 -0
  8. data/gems/kontena-websocket-client-0.1.1/README.md +138 -0
  9. data/gems/kontena-websocket-client-0.1.1/Rakefile +6 -0
  10. data/gems/kontena-websocket-client-0.1.1/benchmark/benchmark-client.rb +45 -0
  11. data/gems/kontena-websocket-client-0.1.1/benchmark/benchmark-em.rb +66 -0
  12. data/gems/kontena-websocket-client-0.1.1/benchmark/benchmark.rb +161 -0
  13. data/gems/kontena-websocket-client-0.1.1/benchmark/benchmark.sh +17 -0
  14. data/gems/kontena-websocket-client-0.1.1/benchmark/websocket-echo-server.go +207 -0
  15. data/gems/kontena-websocket-client-0.1.1/examples/websocket-echo-client.rb +80 -0
  16. data/gems/kontena-websocket-client-0.1.1/kontena-websocket-client.gemspec +24 -0
  17. data/gems/kontena-websocket-client-0.1.1/lib/kontena/websocket/client/connection.rb +119 -0
  18. data/gems/kontena-websocket-client-0.1.1/lib/kontena/websocket/client/version.rb +13 -0
  19. data/gems/kontena-websocket-client-0.1.1/lib/kontena/websocket/client.rb +848 -0
  20. data/gems/kontena-websocket-client-0.1.1/lib/kontena/websocket/error.rb +81 -0
  21. data/gems/kontena-websocket-client-0.1.1/lib/kontena/websocket/logging.rb +55 -0
  22. data/gems/kontena-websocket-client-0.1.1/lib/kontena/websocket/openssl_patch.rb +10 -0
  23. data/gems/kontena-websocket-client-0.1.1/lib/kontena-websocket-client.rb +15 -0
  24. data/gems/mime-types-3.1/Code-of-Conduct.rdoc +74 -0
  25. data/gems/mime-types-3.1/Contributing.rdoc +130 -0
  26. data/gems/mime-types-3.1/History.rdoc +658 -0
  27. data/gems/mime-types-3.1/Licence.rdoc +25 -0
  28. data/gems/mime-types-3.1/Manifest.txt +31 -0
  29. data/gems/mime-types-3.1/README.rdoc +202 -0
  30. data/gems/mime-types-3.1/Rakefile +254 -0
  31. data/gems/mime-types-3.1/lib/mime/type/columnar.rb +55 -0
  32. data/gems/mime-types-3.1/lib/mime/type.rb +573 -0
  33. data/gems/mime-types-3.1/lib/mime/types/_columnar.rb +135 -0
  34. data/gems/mime-types-3.1/lib/mime/types/cache.rb +56 -0
  35. data/gems/mime-types-3.1/lib/mime/types/columnar.rb +1 -0
  36. data/gems/mime-types-3.1/lib/mime/types/container.rb +30 -0
  37. data/gems/mime-types-3.1/lib/mime/types/deprecations.rb +32 -0
  38. data/gems/mime-types-3.1/lib/mime/types/full.rb +17 -0
  39. data/gems/mime-types-3.1/lib/mime/types/loader.rb +148 -0
  40. data/gems/mime-types-3.1/lib/mime/types/logger.rb +37 -0
  41. data/gems/mime-types-3.1/lib/mime/types/registry.rb +81 -0
  42. data/gems/mime-types-3.1/lib/mime/types.rb +228 -0
  43. data/gems/mime-types-3.1/lib/mime-types.rb +1 -0
  44. data/gems/mime-types-3.1/test/bad-fixtures/malformed +9 -0
  45. data/gems/mime-types-3.1/test/fixture/json.json +1 -0
  46. data/gems/mime-types-3.1/test/fixture/old-data +9 -0
  47. data/gems/mime-types-3.1/test/fixture/yaml.yaml +55 -0
  48. data/gems/mime-types-3.1/test/minitest_helper.rb +13 -0
  49. data/gems/mime-types-3.1/test/test_mime_type.rb +603 -0
  50. data/gems/mime-types-3.1/test/test_mime_types.rb +161 -0
  51. data/gems/mime-types-3.1/test/test_mime_types_cache.rb +109 -0
  52. data/gems/mime-types-3.1/test/test_mime_types_class.rb +155 -0
  53. data/gems/mime-types-3.1/test/test_mime_types_lazy.rb +43 -0
  54. data/gems/mime-types-3.1/test/test_mime_types_loader.rb +32 -0
  55. data/gems/mime-types-data-3.2016.0521/Code-of-Conduct.md +75 -0
  56. data/gems/mime-types-data-3.2016.0521/Contributing.md +157 -0
  57. data/gems/mime-types-data-3.2016.0521/History.md +351 -0
  58. data/gems/mime-types-data-3.2016.0521/Licence.md +25 -0
  59. data/gems/mime-types-data-3.2016.0521/Manifest.txt +18 -0
  60. data/gems/mime-types-data-3.2016.0521/README.md +61 -0
  61. data/gems/mime-types-data-3.2016.0521/Rakefile +80 -0
  62. data/gems/mime-types-data-3.2016.0521/data/mime-types.json +1 -0
  63. data/gems/mime-types-data-3.2016.0521/data/mime.content_type.column +1964 -0
  64. data/gems/mime-types-data-3.2016.0521/data/mime.docs.column +1964 -0
  65. data/gems/mime-types-data-3.2016.0521/data/mime.encoding.column +1964 -0
  66. data/gems/mime-types-data-3.2016.0521/data/mime.flags.column +1964 -0
  67. data/gems/mime-types-data-3.2016.0521/data/mime.friendly.column +1964 -0
  68. data/gems/mime-types-data-3.2016.0521/data/mime.pext.column +1964 -0
  69. data/gems/mime-types-data-3.2016.0521/data/mime.use_instead.column +1964 -0
  70. data/gems/mime-types-data-3.2016.0521/data/mime.xrefs.column +1964 -0
  71. data/gems/mime-types-data-3.2016.0521/lib/mime/types/data.rb +21 -0
  72. data/gems/mime-types-data-3.2016.0521/lib/mime-types-data.rb +3 -0
  73. data/gems/multipart-post-2.0.0/Gemfile +14 -0
  74. data/gems/multipart-post-2.0.0/History.txt +60 -0
  75. data/gems/multipart-post-2.0.0/Manifest.txt +9 -0
  76. data/gems/multipart-post-2.0.0/README.md +77 -0
  77. data/gems/multipart-post-2.0.0/Rakefile +9 -0
  78. data/gems/multipart-post-2.0.0/lib/composite_io.rb +108 -0
  79. data/gems/multipart-post-2.0.0/lib/multipart_post.rb +9 -0
  80. data/gems/multipart-post-2.0.0/lib/multipartable.rb +29 -0
  81. data/gems/multipart-post-2.0.0/lib/net/http/post/multipart.rb +27 -0
  82. data/gems/multipart-post-2.0.0/lib/parts.rb +96 -0
  83. data/gems/multipart-post-2.0.0/multipart-post.gemspec +22 -0
  84. data/gems/multipart-post-2.0.0/test/multibyte.txt +1 -0
  85. data/gems/multipart-post-2.0.0/test/net/http/post/test_multipart.rb +110 -0
  86. data/gems/multipart-post-2.0.0/test/test_composite_io.rb +115 -0
  87. data/gems/multipart-post-2.0.0/test/test_parts.rb +86 -0
  88. data/gems/parallel-1.12.1/MIT-LICENSE.txt +20 -0
  89. data/gems/parallel-1.12.1/lib/parallel/processor_count.rb +93 -0
  90. data/gems/parallel-1.12.1/lib/parallel/version.rb +3 -0
  91. data/gems/parallel-1.12.1/lib/parallel.rb +500 -0
  92. data/gems/ruby-progressbar-1.9.0/LICENSE.txt +19 -0
  93. data/gems/ruby-progressbar-1.9.0/README.md +38 -0
  94. data/gems/ruby-progressbar-1.9.0/Rakefile +2 -0
  95. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/base.rb +183 -0
  96. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/calculators/length.rb +99 -0
  97. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/calculators/running_average.rb +9 -0
  98. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/components/bar.rb +96 -0
  99. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/components/percentage.rb +29 -0
  100. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/components/rate.rb +43 -0
  101. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/components/time.rb +107 -0
  102. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/components/title.rb +13 -0
  103. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/components.rb +5 -0
  104. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/errors/invalid_progress_error.rb +4 -0
  105. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/format/formatter.rb +27 -0
  106. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/format/molecule.rb +59 -0
  107. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/format/string.rb +36 -0
  108. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/format.rb +3 -0
  109. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/output.rb +68 -0
  110. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/outputs/non_tty.rb +47 -0
  111. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/outputs/null.rb +33 -0
  112. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/outputs/tty.rb +32 -0
  113. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/progress.rb +118 -0
  114. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/refinements/enumerator.rb +25 -0
  115. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/refinements.rb +1 -0
  116. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/throttle.rb +25 -0
  117. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/time.rb +30 -0
  118. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/timer.rb +72 -0
  119. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar/version.rb +3 -0
  120. data/gems/ruby-progressbar-1.9.0/lib/ruby-progressbar.rb +18 -0
  121. data/gems/slugify-1.0.7/README +18 -0
  122. data/gems/slugify-1.0.7/lib/slugify.rb +1012 -0
  123. data/gems/slugify-1.0.7/lib/slugify_string.rb +11 -0
  124. data/gems/slugify-1.0.7/tests/slugify_test.rb +116 -0
  125. data/gems/slugify-1.0.7/tests/string_slugify_test.rb +23 -0
  126. data/gems/websocket-driver-0.6.5/CHANGELOG.md +123 -0
  127. data/gems/websocket-driver-0.6.5/LICENSE.md +22 -0
  128. data/gems/websocket-driver-0.6.5/README.md +369 -0
  129. data/gems/websocket-driver-0.6.5/examples/tcp_server.rb +28 -0
  130. data/gems/websocket-driver-0.6.5/ext/websocket-driver/Makefile +264 -0
  131. data/gems/websocket-driver-0.6.5/ext/websocket-driver/WebsocketMaskService.java +55 -0
  132. data/gems/websocket-driver-0.6.5/ext/websocket-driver/extconf.rb +4 -0
  133. data/gems/websocket-driver-0.6.5/ext/websocket-driver/websocket_mask.bundle +0 -0
  134. data/gems/websocket-driver-0.6.5/ext/websocket-driver/websocket_mask.c +41 -0
  135. data/gems/websocket-driver-0.6.5/ext/websocket-driver/websocket_mask.o +0 -0
  136. data/gems/websocket-driver-0.6.5/lib/websocket/driver/client.rb +140 -0
  137. data/gems/websocket-driver-0.6.5/lib/websocket/driver/draft75.rb +102 -0
  138. data/gems/websocket-driver-0.6.5/lib/websocket/driver/draft76.rb +96 -0
  139. data/gems/websocket-driver-0.6.5/lib/websocket/driver/event_emitter.rb +54 -0
  140. data/gems/websocket-driver-0.6.5/lib/websocket/driver/headers.rb +45 -0
  141. data/gems/websocket-driver-0.6.5/lib/websocket/driver/hybi/frame.rb +20 -0
  142. data/gems/websocket-driver-0.6.5/lib/websocket/driver/hybi/message.rb +31 -0
  143. data/gems/websocket-driver-0.6.5/lib/websocket/driver/hybi.rb +406 -0
  144. data/gems/websocket-driver-0.6.5/lib/websocket/driver/proxy.rb +68 -0
  145. data/gems/websocket-driver-0.6.5/lib/websocket/driver/server.rb +80 -0
  146. data/gems/websocket-driver-0.6.5/lib/websocket/driver/stream_reader.rb +55 -0
  147. data/gems/websocket-driver-0.6.5/lib/websocket/driver.rb +199 -0
  148. data/gems/websocket-driver-0.6.5/lib/websocket/http/headers.rb +112 -0
  149. data/gems/websocket-driver-0.6.5/lib/websocket/http/request.rb +45 -0
  150. data/gems/websocket-driver-0.6.5/lib/websocket/http/response.rb +29 -0
  151. data/gems/websocket-driver-0.6.5/lib/websocket/http.rb +15 -0
  152. data/gems/websocket-driver-0.6.5/lib/websocket/mask.rb +14 -0
  153. data/gems/websocket-driver-0.6.5/lib/websocket/websocket_mask.rb +2 -0
  154. data/gems/websocket-driver-0.6.5/lib/websocket_mask.bundle +0 -0
  155. data/gems/websocket-driver-0.6.5-java/CHANGELOG.md +123 -0
  156. data/gems/websocket-driver-0.6.5-java/LICENSE.md +22 -0
  157. data/gems/websocket-driver-0.6.5-java/README.md +369 -0
  158. data/gems/websocket-driver-0.6.5-java/examples/tcp_server.rb +28 -0
  159. data/gems/websocket-driver-0.6.5-java/ext/websocket-driver/WebsocketMaskService.java +55 -0
  160. data/gems/websocket-driver-0.6.5-java/ext/websocket-driver/extconf.rb +4 -0
  161. data/gems/websocket-driver-0.6.5-java/ext/websocket-driver/websocket_mask.c +41 -0
  162. data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/client.rb +140 -0
  163. data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/draft75.rb +102 -0
  164. data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/draft76.rb +96 -0
  165. data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/event_emitter.rb +54 -0
  166. data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/headers.rb +45 -0
  167. data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/hybi/frame.rb +20 -0
  168. data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/hybi/message.rb +31 -0
  169. data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/hybi.rb +406 -0
  170. data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/proxy.rb +68 -0
  171. data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/server.rb +80 -0
  172. data/gems/websocket-driver-0.6.5-java/lib/websocket/driver/stream_reader.rb +55 -0
  173. data/gems/websocket-driver-0.6.5-java/lib/websocket/driver.rb +199 -0
  174. data/gems/websocket-driver-0.6.5-java/lib/websocket/http/headers.rb +112 -0
  175. data/gems/websocket-driver-0.6.5-java/lib/websocket/http/request.rb +45 -0
  176. data/gems/websocket-driver-0.6.5-java/lib/websocket/http/response.rb +29 -0
  177. data/gems/websocket-driver-0.6.5-java/lib/websocket/http.rb +15 -0
  178. data/gems/websocket-driver-0.6.5-java/lib/websocket/mask.rb +14 -0
  179. data/gems/websocket-driver-0.6.5-java/lib/websocket/websocket_mask.rb +2 -0
  180. data/gems/websocket-driver-0.6.5-java/lib/websocket_mask.jar +0 -0
  181. data/gems/websocket-extensions-0.1.3/CHANGELOG.md +15 -0
  182. data/gems/websocket-extensions-0.1.3/LICENSE.md +20 -0
  183. data/gems/websocket-extensions-0.1.3/README.md +313 -0
  184. data/gems/websocket-extensions-0.1.3/lib/websocket/extensions/parser.rb +111 -0
  185. data/gems/websocket-extensions-0.1.3/lib/websocket/extensions.rb +181 -0
  186. data/lib/kinetic-sdk.rb +1 -0
  187. data/lib/kinetic_sdk/bridgehub/bridgehub-sdk.rb +80 -0
  188. data/lib/kinetic_sdk/bridgehub/lib/access_keys.rb +67 -0
  189. data/lib/kinetic_sdk/bridgehub/lib/bridge.rb +69 -0
  190. data/lib/kinetic_sdk/discussions/discussions-sdk.rb +165 -0
  191. data/lib/kinetic_sdk/discussions/lib/discussions.rb +107 -0
  192. data/lib/kinetic_sdk/discussions/lib/invitations.rb +120 -0
  193. data/lib/kinetic_sdk/discussions/lib/messages.rb +190 -0
  194. data/lib/kinetic_sdk/discussions/lib/meta.rb +14 -0
  195. data/lib/kinetic_sdk/discussions/lib/participants.rb +64 -0
  196. data/lib/kinetic_sdk/discussions/lib/related_items.rb +54 -0
  197. data/lib/kinetic_sdk/discussions/lib/websockets.rb +96 -0
  198. data/lib/kinetic_sdk/filehub/filehub-sdk.rb +80 -0
  199. data/lib/kinetic_sdk/filehub/lib/access_keys.rb +67 -0
  200. data/lib/kinetic_sdk/filehub/lib/filestores.rb +67 -0
  201. data/lib/kinetic_sdk/request_ce/lib/attribute_definitions.rb +153 -0
  202. data/lib/kinetic_sdk/request_ce/lib/bridges.rb +66 -0
  203. data/lib/kinetic_sdk/request_ce/lib/categories.rb +34 -0
  204. data/lib/kinetic_sdk/request_ce/lib/datastore_form.rb +110 -0
  205. data/lib/kinetic_sdk/request_ce/lib/datastore_submissions.rb +157 -0
  206. data/lib/kinetic_sdk/request_ce/lib/form.rb +99 -0
  207. data/lib/kinetic_sdk/request_ce/lib/form_types.rb +51 -0
  208. data/lib/kinetic_sdk/request_ce/lib/jwt.rb +55 -0
  209. data/lib/kinetic_sdk/request_ce/lib/kapp.rb +93 -0
  210. data/lib/kinetic_sdk/request_ce/lib/meta.rb +14 -0
  211. data/lib/kinetic_sdk/request_ce/lib/oauth.rb +37 -0
  212. data/lib/kinetic_sdk/request_ce/lib/security_policy_definitions.rb +157 -0
  213. data/lib/kinetic_sdk/request_ce/lib/space.rb +89 -0
  214. data/lib/kinetic_sdk/request_ce/lib/submissions.rb +215 -0
  215. data/lib/kinetic_sdk/request_ce/lib/system_api.rb +69 -0
  216. data/lib/kinetic_sdk/request_ce/lib/teams.rb +113 -0
  217. data/lib/kinetic_sdk/request_ce/lib/users.rb +245 -0
  218. data/lib/kinetic_sdk/request_ce/lib/webhook_jobs.rb +142 -0
  219. data/lib/kinetic_sdk/request_ce/lib/webhooks.rb +192 -0
  220. data/lib/kinetic_sdk/request_ce/request-ce-sdk.rb +153 -0
  221. data/lib/kinetic_sdk/task/lib/access_keys.rb +94 -0
  222. data/lib/kinetic_sdk/task/lib/categories.rb +190 -0
  223. data/lib/kinetic_sdk/task/lib/config.rb +202 -0
  224. data/lib/kinetic_sdk/task/lib/engine.rb +42 -0
  225. data/lib/kinetic_sdk/task/lib/environment.rb +14 -0
  226. data/lib/kinetic_sdk/task/lib/errors.rb +165 -0
  227. data/lib/kinetic_sdk/task/lib/groups.rb +112 -0
  228. data/lib/kinetic_sdk/task/lib/handlers.rb +105 -0
  229. data/lib/kinetic_sdk/task/lib/health.rb +28 -0
  230. data/lib/kinetic_sdk/task/lib/license.rb +52 -0
  231. data/lib/kinetic_sdk/task/lib/policy_rules.rb +166 -0
  232. data/lib/kinetic_sdk/task/lib/setup.rb +56 -0
  233. data/lib/kinetic_sdk/task/lib/sources.rb +134 -0
  234. data/lib/kinetic_sdk/task/lib/tasks.rb +17 -0
  235. data/lib/kinetic_sdk/task/lib/trees.rb +274 -0
  236. data/lib/kinetic_sdk/task/lib/users.rb +75 -0
  237. data/lib/kinetic_sdk/task/task-sdk.rb +92 -0
  238. data/lib/kinetic_sdk/utils/kinetic-http-headers.rb +150 -0
  239. data/lib/kinetic_sdk/utils/kinetic-http-response.rb +75 -0
  240. data/lib/kinetic_sdk/utils/kinetic-http.rb +552 -0
  241. data/lib/kinetic_sdk/utils/logger.rb +70 -0
  242. data/lib/kinetic_sdk/utils/random.rb +30 -0
  243. data/lib/kinetic_sdk/version.rb +7 -0
  244. data/lib/kinetic_sdk.rb +57 -0
  245. metadata +414 -0
@@ -0,0 +1,96 @@
1
+ module WebSocket
2
+ class Driver
3
+
4
+ class Draft76 < Draft75
5
+ BODY_SIZE = 8
6
+
7
+ def initialize(socket, options = {})
8
+ super
9
+ input = @socket.env['rack.input']
10
+ @stage = -1
11
+ @body = (input ? input.read : String.new('')).force_encoding(BINARY)
12
+
13
+ @headers.clear
14
+ @headers['Upgrade'] = 'WebSocket'
15
+ @headers['Connection'] = 'Upgrade'
16
+ @headers['Sec-WebSocket-Origin'] = @socket.env['HTTP_ORIGIN']
17
+ @headers['Sec-WebSocket-Location'] = @socket.url
18
+ end
19
+
20
+ def version
21
+ 'hixie-76'
22
+ end
23
+
24
+ def start
25
+ return false unless super
26
+ send_handshake_body
27
+ true
28
+ end
29
+
30
+ def close(reason = nil, code = nil)
31
+ return false if @ready_state == 3
32
+ @socket.write([0xFF, 0x00].pack('C*'))
33
+ @ready_state = 3
34
+ emit(:close, CloseEvent.new(nil, nil))
35
+ true
36
+ end
37
+
38
+ private
39
+
40
+ def handshake_response
41
+ env = @socket.env
42
+
43
+ key1 = env['HTTP_SEC_WEBSOCKET_KEY1']
44
+ number1 = number_from_key(key1)
45
+ spaces1 = spaces_in_key(key1)
46
+
47
+ key2 = env['HTTP_SEC_WEBSOCKET_KEY2']
48
+ number2 = number_from_key(key2)
49
+ spaces2 = spaces_in_key(key2)
50
+
51
+ if number1 % spaces1 != 0 or number2 % spaces2 != 0
52
+ emit(:error, ProtocolError.new('Client sent invalid Sec-WebSocket-Key headers'))
53
+ close
54
+ return nil
55
+ end
56
+
57
+ @key_values = [number1 / spaces1, number2 / spaces2]
58
+
59
+ start = 'HTTP/1.1 101 WebSocket Protocol Handshake'
60
+ headers = [start, @headers.to_s, '']
61
+ headers.join("\r\n")
62
+ end
63
+
64
+ def handshake_signature
65
+ return nil unless @body.bytesize >= BODY_SIZE
66
+
67
+ head = @body[0...BODY_SIZE]
68
+ Digest::MD5.digest((@key_values + [head]).pack('N2A*'))
69
+ end
70
+
71
+ def send_handshake_body
72
+ return unless signature = handshake_signature
73
+ @socket.write(signature)
74
+ @stage = 0
75
+ open
76
+ parse(@body[BODY_SIZE..-1]) if @body.bytesize > BODY_SIZE
77
+ end
78
+
79
+ def parse_leading_byte(octet)
80
+ return super unless octet == 0xFF
81
+ @closing = true
82
+ @length = 0
83
+ @stage = 1
84
+ end
85
+
86
+ def number_from_key(key)
87
+ key.scan(/[0-9]/).join('').to_i(10)
88
+ end
89
+
90
+ def spaces_in_key(key)
91
+ key.scan(/ /).size
92
+ end
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,54 @@
1
+ module WebSocket
2
+ class Driver
3
+
4
+ module EventEmitter
5
+ def initialize
6
+ @listeners = Hash.new { |h,k| h[k] = [] }
7
+ end
8
+
9
+ def add_listener(event, callable = nil, &block)
10
+ listener = callable || block
11
+ @listeners[event.to_s] << listener
12
+ listener
13
+ end
14
+
15
+ def on(event, callable = nil, &block)
16
+ if callable
17
+ add_listener(event, callable)
18
+ else
19
+ add_listener(event, &block)
20
+ end
21
+ end
22
+
23
+ def remove_listener(event, callable = nil, &block)
24
+ listener = callable || block
25
+ @listeners[event.to_s].delete(listener)
26
+ listener
27
+ end
28
+
29
+ def remove_all_listeners(event = nil)
30
+ if event
31
+ @listeners.delete(event.to_s)
32
+ else
33
+ @listeners.clear
34
+ end
35
+ end
36
+
37
+ def emit(event, *args)
38
+ @listeners[event.to_s].dup.each do |listener|
39
+ listener.call(*args)
40
+ end
41
+ end
42
+
43
+ def listener_count(event)
44
+ return 0 unless @listeners.has_key?(event.to_s)
45
+ @listeners[event.to_s].size
46
+ end
47
+
48
+ def listeners(event)
49
+ @listeners[event.to_s]
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,45 @@
1
+ module WebSocket
2
+ class Driver
3
+
4
+ class Headers
5
+ ALLOWED_DUPLICATES = %w[set-cookie set-cookie2 warning www-authenticate]
6
+
7
+ def initialize(received = {})
8
+ @raw = received
9
+ clear
10
+
11
+ @received = {}
12
+ @raw.each { |k,v| @received[HTTP.normalize_header(k)] = v }
13
+ end
14
+
15
+ def clear
16
+ @sent = Set.new
17
+ @lines = []
18
+ end
19
+
20
+ def [](name)
21
+ @received[HTTP.normalize_header(name)]
22
+ end
23
+
24
+ def []=(name, value)
25
+ return if value.nil?
26
+ key = HTTP.normalize_header(name)
27
+ return unless @sent.add?(key) or ALLOWED_DUPLICATES.include?(key)
28
+ @lines << "#{name.strip}: #{value.to_s.strip}\r\n"
29
+ end
30
+
31
+ def inspect
32
+ @raw.inspect
33
+ end
34
+
35
+ def to_h
36
+ @raw.dup
37
+ end
38
+
39
+ def to_s
40
+ @lines.join('')
41
+ end
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,20 @@
1
+ module WebSocket
2
+ class Driver
3
+ class Hybi
4
+
5
+ class Frame
6
+ attr_accessor :final,
7
+ :rsv1,
8
+ :rsv2,
9
+ :rsv3,
10
+ :opcode,
11
+ :masked,
12
+ :masking_key,
13
+ :length_bytes,
14
+ :length,
15
+ :payload
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ module WebSocket
2
+ class Driver
3
+ class Hybi
4
+
5
+ class Message
6
+ attr_accessor :rsv1,
7
+ :rsv2,
8
+ :rsv3,
9
+ :opcode,
10
+ :data
11
+
12
+ def initialize
13
+ @rsv1 = false
14
+ @rsv2 = false
15
+ @rsv3 = false
16
+ @opcode = nil
17
+ @data = String.new('').force_encoding(BINARY)
18
+ end
19
+
20
+ def <<(frame)
21
+ @rsv1 ||= frame.rsv1
22
+ @rsv2 ||= frame.rsv2
23
+ @rsv3 ||= frame.rsv3
24
+ @opcode ||= frame.opcode
25
+ @data << frame.payload
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,406 @@
1
+ module WebSocket
2
+ class Driver
3
+
4
+ class Hybi < Driver
5
+ root = File.expand_path('../hybi', __FILE__)
6
+
7
+ autoload :Frame, root + '/frame'
8
+ autoload :Message, root + '/message'
9
+
10
+ def self.generate_accept(key)
11
+ Base64.strict_encode64(Digest::SHA1.digest(key + GUID))
12
+ end
13
+
14
+ GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
15
+
16
+ BYTE = 0b11111111
17
+ FIN = MASK = 0b10000000
18
+ RSV1 = 0b01000000
19
+ RSV2 = 0b00100000
20
+ RSV3 = 0b00010000
21
+ OPCODE = 0b00001111
22
+ LENGTH = 0b01111111
23
+
24
+ OPCODES = {
25
+ :continuation => 0,
26
+ :text => 1,
27
+ :binary => 2,
28
+ :close => 8,
29
+ :ping => 9,
30
+ :pong => 10
31
+ }
32
+
33
+ OPCODE_CODES = OPCODES.values
34
+ MESSAGE_OPCODES = OPCODES.values_at(:continuation, :text, :binary)
35
+ OPENING_OPCODES = OPCODES.values_at(:text, :binary)
36
+
37
+ ERRORS = {
38
+ :normal_closure => 1000,
39
+ :going_away => 1001,
40
+ :protocol_error => 1002,
41
+ :unacceptable => 1003,
42
+ :encoding_error => 1007,
43
+ :policy_violation => 1008,
44
+ :too_large => 1009,
45
+ :extension_error => 1010,
46
+ :unexpected_condition => 1011
47
+ }
48
+
49
+ ERROR_CODES = ERRORS.values
50
+ DEFAULT_ERROR_CODE = 1000
51
+ MIN_RESERVED_ERROR = 3000
52
+ MAX_RESERVED_ERROR = 4999
53
+
54
+ PACK_FORMATS = {2 => 'n', 8 => 'Q>'}
55
+
56
+ def initialize(socket, options = {})
57
+ super
58
+
59
+ @extensions = ::WebSocket::Extensions.new
60
+ @stage = 0
61
+ @masking = options[:masking]
62
+ @protocols = options[:protocols] || []
63
+ @protocols = @protocols.strip.split(/ *, */) if String === @protocols
64
+ @require_masking = options[:require_masking]
65
+ @ping_callbacks = {}
66
+
67
+ @frame = @message = nil
68
+
69
+ return unless @socket.respond_to?(:env)
70
+
71
+ sec_key = @socket.env['HTTP_SEC_WEBSOCKET_KEY']
72
+ protos = @socket.env['HTTP_SEC_WEBSOCKET_PROTOCOL']
73
+
74
+ @headers['Upgrade'] = 'websocket'
75
+ @headers['Connection'] = 'Upgrade'
76
+ @headers['Sec-WebSocket-Accept'] = Hybi.generate_accept(sec_key)
77
+
78
+ if protos = @socket.env['HTTP_SEC_WEBSOCKET_PROTOCOL']
79
+ protos = protos.split(/ *, */) if String === protos
80
+ @protocol = protos.find { |p| @protocols.include?(p) }
81
+ @headers['Sec-WebSocket-Protocol'] = @protocol if @protocol
82
+ end
83
+ end
84
+
85
+ def version
86
+ "hybi-#{@socket.env['HTTP_SEC_WEBSOCKET_VERSION']}"
87
+ end
88
+
89
+ def add_extension(extension)
90
+ @extensions.add(extension)
91
+ true
92
+ end
93
+
94
+ def parse(chunk)
95
+ @reader.put(chunk)
96
+ buffer = true
97
+ while buffer
98
+ case @stage
99
+ when 0 then
100
+ buffer = @reader.read(1)
101
+ parse_opcode(buffer.getbyte(0)) if buffer
102
+
103
+ when 1 then
104
+ buffer = @reader.read(1)
105
+ parse_length(buffer.getbyte(0)) if buffer
106
+
107
+ when 2 then
108
+ buffer = @reader.read(@frame.length_bytes)
109
+ parse_extended_length(buffer) if buffer
110
+
111
+ when 3 then
112
+ buffer = @reader.read(4)
113
+ if buffer
114
+ @stage = 4
115
+ @frame.masking_key = buffer
116
+ end
117
+
118
+ when 4 then
119
+ buffer = @reader.read(@frame.length)
120
+
121
+ if buffer
122
+ @stage = 0
123
+ emit_frame(buffer)
124
+ end
125
+
126
+ else
127
+ buffer = nil
128
+ end
129
+ end
130
+ end
131
+
132
+ def binary(message)
133
+ frame(message, :binary)
134
+ end
135
+
136
+ def ping(message = '', &callback)
137
+ @ping_callbacks[message] = callback if callback
138
+ frame(message, :ping)
139
+ end
140
+
141
+ def pong(message = '')
142
+ frame(message, :pong)
143
+ end
144
+
145
+ def close(reason = nil, code = nil)
146
+ reason ||= ''
147
+ code ||= ERRORS[:normal_closure]
148
+
149
+ if @ready_state <= 0
150
+ @ready_state = 3
151
+ emit(:close, CloseEvent.new(code, reason))
152
+ true
153
+ elsif @ready_state == 1
154
+ frame(reason, :close, code)
155
+ @ready_state = 2
156
+ true
157
+ else
158
+ false
159
+ end
160
+ end
161
+
162
+ def frame(buffer, type = nil, code = nil)
163
+ return queue([buffer, type, code]) if @ready_state <= 0
164
+ return false unless @ready_state == 1
165
+
166
+ message = Message.new
167
+ frame = Frame.new
168
+ is_text = String === buffer
169
+
170
+ message.rsv1 = message.rsv2 = message.rsv3 = false
171
+ message.opcode = OPCODES[type || (is_text ? :text : :binary)]
172
+
173
+ payload = is_text ? buffer.bytes.to_a : buffer
174
+ payload = [code].pack(PACK_FORMATS[2]).bytes.to_a + payload if code
175
+ message.data = payload.pack('C*')
176
+
177
+ if MESSAGE_OPCODES.include?(message.opcode)
178
+ message = @extensions.process_outgoing_message(message)
179
+ end
180
+
181
+ frame.final = true
182
+ frame.rsv1 = message.rsv1
183
+ frame.rsv2 = message.rsv2
184
+ frame.rsv3 = message.rsv3
185
+ frame.opcode = message.opcode
186
+ frame.masked = !!@masking
187
+ frame.masking_key = SecureRandom.random_bytes(4) if frame.masked
188
+ frame.length = message.data.bytesize
189
+ frame.payload = message.data
190
+
191
+ send_frame(frame)
192
+ true
193
+
194
+ rescue ::WebSocket::Extensions::ExtensionError => error
195
+ fail(:extension_error, error.message)
196
+ end
197
+
198
+ private
199
+
200
+ def send_frame(frame)
201
+ length = frame.length
202
+ buffer = []
203
+ masked = frame.masked ? MASK : 0
204
+
205
+ buffer[0] = (frame.final ? FIN : 0) |
206
+ (frame.rsv1 ? RSV1 : 0) |
207
+ (frame.rsv2 ? RSV2 : 0) |
208
+ (frame.rsv3 ? RSV3 : 0) |
209
+ frame.opcode
210
+
211
+ if length <= 125
212
+ buffer[1] = masked | length
213
+ elsif length <= 65535
214
+ buffer[1] = masked | 126
215
+ buffer[2..3] = [length].pack(PACK_FORMATS[2]).bytes.to_a
216
+ else
217
+ buffer[1] = masked | 127
218
+ buffer[2..9] = [length].pack(PACK_FORMATS[8]).bytes.to_a
219
+ end
220
+
221
+ if frame.masked
222
+ buffer.concat(frame.masking_key.bytes.to_a)
223
+ buffer.concat(Mask.mask(frame.payload, frame.masking_key).bytes.to_a)
224
+ else
225
+ buffer.concat(frame.payload.bytes.to_a)
226
+ end
227
+
228
+ @socket.write(buffer.pack('C*'))
229
+ end
230
+
231
+ def handshake_response
232
+ begin
233
+ extensions = @extensions.generate_response(@socket.env['HTTP_SEC_WEBSOCKET_EXTENSIONS'])
234
+ rescue => error
235
+ fail(:protocol_error, error.message)
236
+ return nil
237
+ end
238
+
239
+ @headers['Sec-WebSocket-Extensions'] = extensions if extensions
240
+
241
+ start = 'HTTP/1.1 101 Switching Protocols'
242
+ headers = [start, @headers.to_s, '']
243
+ headers.join("\r\n")
244
+ end
245
+
246
+ def shutdown(code, reason, error = false)
247
+ @frame = @message = nil
248
+ @stage = 5
249
+ @extensions.close
250
+
251
+ frame(reason, :close, code) if @ready_state < 2
252
+ @ready_state = 3
253
+
254
+ emit(:error, ProtocolError.new(reason)) if error
255
+ emit(:close, CloseEvent.new(code, reason))
256
+ end
257
+
258
+ def fail(type, message)
259
+ return if @ready_state > 1
260
+ shutdown(ERRORS[type], message, true)
261
+ end
262
+
263
+ def parse_opcode(octet)
264
+ rsvs = [RSV1, RSV2, RSV3].map { |rsv| (octet & rsv) == rsv }
265
+
266
+ @frame = Frame.new
267
+
268
+ @frame.final = (octet & FIN) == FIN
269
+ @frame.rsv1 = rsvs[0]
270
+ @frame.rsv2 = rsvs[1]
271
+ @frame.rsv3 = rsvs[2]
272
+ @frame.opcode = (octet & OPCODE)
273
+
274
+ @stage = 1
275
+
276
+ unless @extensions.valid_frame_rsv?(@frame)
277
+ return fail(:protocol_error,
278
+ "One or more reserved bits are on: reserved1 = #{@frame.rsv1 ? 1 : 0}" +
279
+ ", reserved2 = #{@frame.rsv2 ? 1 : 0 }" +
280
+ ", reserved3 = #{@frame.rsv3 ? 1 : 0 }")
281
+ end
282
+
283
+ unless OPCODES.values.include?(@frame.opcode)
284
+ return fail(:protocol_error, "Unrecognized frame opcode: #{@frame.opcode}")
285
+ end
286
+
287
+ unless MESSAGE_OPCODES.include?(@frame.opcode) or @frame.final
288
+ return fail(:protocol_error, "Received fragmented control frame: opcode = #{@frame.opcode}")
289
+ end
290
+
291
+ if @message and OPENING_OPCODES.include?(@frame.opcode)
292
+ return fail(:protocol_error, 'Received new data frame but previous continuous frame is unfinished')
293
+ end
294
+ end
295
+
296
+ def parse_length(octet)
297
+ @frame.masked = (octet & MASK) == MASK
298
+ @frame.length = (octet & LENGTH)
299
+
300
+ if @frame.length >= 0 and @frame.length <= 125
301
+ @stage = @frame.masked ? 3 : 4
302
+ return unless check_frame_length
303
+ else
304
+ @stage = 2
305
+ @frame.length_bytes = (@frame.length == 126) ? 2 : 8
306
+ end
307
+
308
+ if @require_masking and not @frame.masked
309
+ return fail(:unacceptable, 'Received unmasked frame but masking is required')
310
+ end
311
+ end
312
+
313
+ def parse_extended_length(buffer)
314
+ @frame.length = buffer.unpack(PACK_FORMATS[buffer.bytesize]).first
315
+ @stage = @frame.masked ? 3 : 4
316
+
317
+ unless MESSAGE_OPCODES.include?(@frame.opcode) or @frame.length <= 125
318
+ return fail(:protocol_error, "Received control frame having too long payload: #{@frame.length}")
319
+ end
320
+
321
+ return unless check_frame_length
322
+ end
323
+
324
+ def check_frame_length
325
+ length = @message ? @message.data.bytesize : 0
326
+
327
+ if length + @frame.length > @max_length
328
+ fail(:too_large, 'WebSocket frame length too large')
329
+ false
330
+ else
331
+ true
332
+ end
333
+ end
334
+
335
+ def emit_frame(buffer)
336
+ frame = @frame
337
+ opcode = frame.opcode
338
+ payload = frame.payload = Mask.mask(buffer, @frame.masking_key)
339
+ bytesize = payload.bytesize
340
+ bytes = payload.bytes.to_a
341
+
342
+ @frame = nil
343
+
344
+ case opcode
345
+ when OPCODES[:continuation] then
346
+ return fail(:protocol_error, 'Received unexpected continuation frame') unless @message
347
+ @message << frame
348
+
349
+ when OPCODES[:text], OPCODES[:binary] then
350
+ @message = Message.new
351
+ @message << frame
352
+
353
+ when OPCODES[:close] then
354
+ code = (bytesize >= 2) ? payload.unpack(PACK_FORMATS[2]).first : nil
355
+ reason = (bytesize > 2) ? Driver.encode(bytes[2..-1] || [], UNICODE) : nil
356
+
357
+ unless (bytesize == 0) or
358
+ (code && code >= MIN_RESERVED_ERROR && code <= MAX_RESERVED_ERROR) or
359
+ ERROR_CODES.include?(code)
360
+ code = ERRORS[:protocol_error]
361
+ end
362
+
363
+ if bytesize > 125 or (bytesize > 2 and reason.nil?)
364
+ code = ERRORS[:protocol_error]
365
+ end
366
+
367
+ shutdown(code || DEFAULT_ERROR_CODE, reason || '')
368
+
369
+ when OPCODES[:ping] then
370
+ frame(payload, :pong)
371
+
372
+ when OPCODES[:pong] then
373
+ message = Driver.encode(payload, UNICODE)
374
+ callback = @ping_callbacks[message]
375
+ @ping_callbacks.delete(message)
376
+ callback.call if callback
377
+ end
378
+
379
+ emit_message if frame.final and MESSAGE_OPCODES.include?(opcode)
380
+ end
381
+
382
+ def emit_message
383
+ message = @extensions.process_incoming_message(@message)
384
+ @message = nil
385
+
386
+ payload = message.data
387
+
388
+ case message.opcode
389
+ when OPCODES[:text] then
390
+ payload = Driver.encode(payload, UNICODE)
391
+ when OPCODES[:binary]
392
+ payload = payload.bytes.to_a
393
+ end
394
+
395
+ if payload
396
+ emit(:message, MessageEvent.new(payload))
397
+ else
398
+ fail(:encoding_error, 'Could not decode a text frame as UTF-8')
399
+ end
400
+ rescue ::WebSocket::Extensions::ExtensionError => error
401
+ fail(:extension_error, error.message)
402
+ end
403
+ end
404
+
405
+ end
406
+ end