batman-rails-flo 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +29 -0
  3. data/Rakefile +2 -0
  4. data/lib/batman-rails-flo.rb +5 -0
  5. data/lib/batman_rails_flo/railtie.rb +9 -0
  6. data/lib/batman_rails_flo/tasks.rake +14 -0
  7. data/lib/batman_rails_flo/version.rb +3 -0
  8. data/vendor/assets/javascripts/batman_rails_flo/flo_server.js +67 -0
  9. data/vendor/assets/javascripts/batman_rails_flo/live_reload.js.coffee +129 -0
  10. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/CNAME +1 -0
  11. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/CONTRIBUTING.md +9 -0
  12. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/LICENSE +22 -0
  13. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/README +50 -0
  14. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/bin/cake +7 -0
  15. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/bin/coffee +7 -0
  16. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/browser.js +134 -0
  17. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/cake.js +112 -0
  18. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/coffee-script.js +335 -0
  19. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/command.js +569 -0
  20. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/grammar.js +631 -0
  21. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/helpers.js +252 -0
  22. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/index.js +11 -0
  23. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/lexer.js +926 -0
  24. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/nodes.js +3158 -0
  25. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/optparse.js +139 -0
  26. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/parser.js +724 -0
  27. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/register.js +66 -0
  28. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/repl.js +163 -0
  29. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/rewriter.js +475 -0
  30. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/scope.js +146 -0
  31. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/sourcemap.js +161 -0
  32. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/LICENSE +21 -0
  33. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/examples/pow.js +6 -0
  34. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/index.js +82 -0
  35. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/package.json +34 -0
  36. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/readme.markdown +63 -0
  37. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/chmod.js +38 -0
  38. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/clobber.js +37 -0
  39. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/mkdirp.js +28 -0
  40. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/perm.js +32 -0
  41. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/perm_sync.js +39 -0
  42. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/race.js +41 -0
  43. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/rel.js +32 -0
  44. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/return.js +25 -0
  45. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/return_sync.js +24 -0
  46. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/root.js +18 -0
  47. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/sync.js +32 -0
  48. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/umask.js +28 -0
  49. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/umask_sync.js +32 -0
  50. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/package.json +50 -0
  51. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/register.js +1 -0
  52. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/LICENSE +30 -0
  53. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/PATENTS +23 -0
  54. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/README.md +124 -0
  55. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/bin/flo +26 -0
  56. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/configure/configure.html +57 -0
  57. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/configure/configure.js +205 -0
  58. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/configure/style.css +334 -0
  59. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/connection.js +235 -0
  60. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/devtools.html +12 -0
  61. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/index.js +323 -0
  62. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/logger.js +42 -0
  63. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/logo.png +0 -0
  64. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/manifest.json +13 -0
  65. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/session.js +305 -0
  66. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/index.js +10 -0
  67. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/lib/flo.js +226 -0
  68. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/lib/server.js +94 -0
  69. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/README.md +66 -0
  70. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/index.js +437 -0
  71. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/LICENSE +23 -0
  72. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/README.md +218 -0
  73. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/minimatch.js +1055 -0
  74. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/CONTRIBUTORS +14 -0
  75. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/LICENSE +23 -0
  76. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/README.md +97 -0
  77. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js +252 -0
  78. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/package.json +33 -0
  79. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/test/basic.js +369 -0
  80. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/test/foreach.js +52 -0
  81. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js +50 -0
  82. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/sigmund/LICENSE +27 -0
  83. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/sigmund/README.md +53 -0
  84. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/sigmund/bench.js +283 -0
  85. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/sigmund/package.json +42 -0
  86. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/sigmund/sigmund.js +39 -0
  87. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/sigmund/test/basic.js +24 -0
  88. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/package.json +40 -0
  89. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/test/basic.js +399 -0
  90. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/test/brace-expand.js +33 -0
  91. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/test/caching.js +14 -0
  92. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/test/defaults.js +274 -0
  93. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/test/extglob-ending-with-state-char.js +8 -0
  94. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/lib/walker.js +111 -0
  95. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/license +13 -0
  96. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/node_modules/makeerror/lib/makeerror.js +87 -0
  97. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/node_modules/makeerror/node_modules/tmpl/lib/tmpl.js +17 -0
  98. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/node_modules/makeerror/node_modules/tmpl/package.json +31 -0
  99. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/node_modules/makeerror/node_modules/tmpl/readme.md +10 -0
  100. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/node_modules/makeerror/package.json +34 -0
  101. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/node_modules/makeerror/readme.md +77 -0
  102. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/package.json +36 -0
  103. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/readme.md +52 -0
  104. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/LICENSE +55 -0
  105. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/main.js +128 -0
  106. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/package.json +34 -0
  107. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/readme.mkd +72 -0
  108. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/test/d/d/t +0 -0
  109. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/test/d/t +0 -0
  110. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/test/test_monitor.js +31 -0
  111. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/test/test_monitorRootDirectory.js +28 -0
  112. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/test/test_watchTree.js +20 -0
  113. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/package.json +45 -0
  114. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/test/test.js +243 -0
  115. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/CHANGELOG.md +81 -0
  116. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/LICENSE +177 -0
  117. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/Makefile +11 -0
  118. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/README.md +245 -0
  119. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/binding.gyp +14 -0
  120. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/Makefile +355 -0
  121. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/Release/linker.lock +0 -0
  122. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/Release/obj.target/validation/src/validation.o +0 -0
  123. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/Release/obj.target/xor/src/xor.o +0 -0
  124. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/Release/validation.node +0 -0
  125. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/Release/xor.node +0 -0
  126. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/binding.Makefile +6 -0
  127. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/config.gypi +115 -0
  128. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/gyp-mac-tool +512 -0
  129. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/validation.target.mk +154 -0
  130. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/xor.target.mk +154 -0
  131. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/index.js +1 -0
  132. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/install.js +31 -0
  133. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/Constants.js +23 -0
  134. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/Deprecation.js +38 -0
  135. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/Validation.fallback.js +12 -0
  136. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/Validation.js +18 -0
  137. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketClient.js +359 -0
  138. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketConnection.js +717 -0
  139. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketFrame.js +282 -0
  140. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketRequest.js +478 -0
  141. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketRouter.js +154 -0
  142. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketRouterRequest.js +59 -0
  143. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketServer.js +216 -0
  144. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/utils.js +7 -0
  145. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/websocket.js +11 -0
  146. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/xor.fallback.js +13 -0
  147. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/xor.js +18 -0
  148. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/package.json +43 -0
  149. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/src/validation.cc +144 -0
  150. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/src/xor.cpp +86 -0
  151. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/vendor/FastBufferList.js +192 -0
  152. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/vendor/node-ctype/LICENSE +18 -0
  153. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/vendor/node-ctype/ctio-faster.js +1126 -0
  154. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/package.json +25 -0
  155. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/test/client/browser_websocket.js +63 -0
  156. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/test/client/connection_test.js +57 -0
  157. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/test/client/logger_mock.js +15 -0
  158. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/test/client/session_test.js +194 -0
  159. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/test/server/flo_test.js +211 -0
  160. data/vendor/assets/javascripts/batman_rails_flo/package.json +15 -0
  161. data/vendor/assets/javascripts/batman_rails_flo/reload_event_handler.js.coffee +56 -0
  162. metadata +232 -0
@@ -0,0 +1,282 @@
1
+ /************************************************************************
2
+ * Copyright 2010-2011 Worlize Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ ***********************************************************************/
16
+
17
+ var ctio = require('../vendor/node-ctype/ctio-faster');
18
+ var xor = require('./xor').xor;
19
+
20
+ const DECODE_HEADER = 1;
21
+ const WAITING_FOR_16_BIT_LENGTH = 2;
22
+ const WAITING_FOR_64_BIT_LENGTH = 3;
23
+ const WAITING_FOR_MASK_KEY = 4;
24
+ const WAITING_FOR_PAYLOAD = 5;
25
+ const COMPLETE = 6;
26
+
27
+ // WebSocketConnection will pass shared buffer objects for maskBytes and
28
+ // frameHeader into the constructor to avoid tons of small memory allocations
29
+ // for each frame we have to parse. This is only used for parsing frames
30
+ // we receive off the wire.
31
+ function WebSocketFrame(maskBytes, frameHeader, config) {
32
+ this.maskBytes = maskBytes;
33
+ this.frameHeader = frameHeader;
34
+ this.config = config;
35
+ this.maxReceivedFrameSize = config.maxReceivedFrameSize;
36
+ this.protocolError = false;
37
+ this.frameTooLarge = false;
38
+ this.invalidCloseFrameLength = false;
39
+ this.parseState = DECODE_HEADER;
40
+ this.closeStatus = -1;
41
+ }
42
+
43
+ WebSocketFrame.prototype.addData = function(bufferList, fragmentationType) {
44
+ var temp;
45
+ if (this.parseState === DECODE_HEADER) {
46
+ if (bufferList.length >= 2) {
47
+ bufferList.joinInto(this.frameHeader, 0, 0, 2);
48
+ bufferList.advance(2);
49
+ var firstByte = this.frameHeader[0];
50
+ var secondByte = this.frameHeader[1];
51
+
52
+ this.fin = Boolean(firstByte & 0x80);
53
+ this.rsv1 = Boolean(firstByte & 0x40);
54
+ this.rsv2 = Boolean(firstByte & 0x20);
55
+ this.rsv3 = Boolean(firstByte & 0x10);
56
+ this.mask = Boolean(secondByte & 0x80);
57
+
58
+ this.opcode = firstByte & 0x0F;
59
+ this.length = secondByte & 0x7F;
60
+
61
+ // Control frame sanity check
62
+ if (this.opcode >= 0x08) {
63
+ if (this.length > 125) {
64
+ this.protocolError = true;
65
+ this.dropReason = "Illegal control frame longer than 125 bytes.";
66
+ return true;
67
+ }
68
+ if (!this.fin) {
69
+ this.protocolError = true;
70
+ this.dropReason = "Control frames must not be fragmented.";
71
+ return true;
72
+ }
73
+ }
74
+
75
+ if (this.length === 126) {
76
+ this.parseState = WAITING_FOR_16_BIT_LENGTH;
77
+ }
78
+ else if (this.length === 127) {
79
+ this.parseState = WAITING_FOR_64_BIT_LENGTH;
80
+ }
81
+ else {
82
+ this.parseState = WAITING_FOR_MASK_KEY;
83
+ }
84
+ }
85
+ }
86
+ if (this.parseState === WAITING_FOR_16_BIT_LENGTH) {
87
+ if (bufferList.length >= 2) {
88
+ bufferList.joinInto(this.frameHeader, 2, 0, 2);
89
+ bufferList.advance(2);
90
+ this.length = ctio.ruint16(this.frameHeader, 'big', 2);
91
+ this.parseState = WAITING_FOR_MASK_KEY;
92
+ }
93
+ }
94
+ else if (this.parseState === WAITING_FOR_64_BIT_LENGTH) {
95
+ if (bufferList.length >= 8) {
96
+ bufferList.joinInto(this.frameHeader, 2, 0, 8);
97
+ bufferList.advance(8);
98
+ var lengthPair = ctio.ruint64(this.frameHeader, 'big', 2);
99
+ if (lengthPair[0] !== 0) {
100
+ this.protocolError = true;
101
+ this.dropReason = "Unsupported 64-bit length frame received";
102
+ return true;
103
+ }
104
+ this.length = lengthPair[1];
105
+ this.parseState = WAITING_FOR_MASK_KEY;
106
+ }
107
+ }
108
+
109
+ if (this.parseState === WAITING_FOR_MASK_KEY) {
110
+ if (this.mask) {
111
+ if (bufferList.length >= 4) {
112
+ bufferList.joinInto(this.maskBytes, 0, 0, 4);
113
+ bufferList.advance(4);
114
+ this.parseState = WAITING_FOR_PAYLOAD;
115
+ }
116
+ }
117
+ else {
118
+ this.parseState = WAITING_FOR_PAYLOAD;
119
+ }
120
+ }
121
+
122
+ if (this.parseState === WAITING_FOR_PAYLOAD) {
123
+ if (this.length > this.maxReceivedFrameSize) {
124
+ this.frameTooLarge = true;
125
+ this.dropReason = "Frame size of " + this.length.toString(10) +
126
+ " bytes exceeds maximum accepted frame size";
127
+ return true;
128
+ }
129
+
130
+ if (this.length === 0) {
131
+ this.binaryPayload = new Buffer(0);
132
+ this.parseState = COMPLETE;
133
+ return true;
134
+ }
135
+ if (bufferList.length >= this.length) {
136
+ this.binaryPayload = bufferList.take(this.length);
137
+ bufferList.advance(this.length);
138
+ if (this.mask) {
139
+ xor(this.binaryPayload, this.maskBytes, 0);
140
+ }
141
+
142
+ if (this.opcode === 0x08) { // WebSocketOpcode.CONNECTION_CLOSE
143
+ if (this.length === 1) {
144
+ // Invalid length for a close frame. Must be zero or at least two.
145
+ this.binaryPayload = new Buffer(0);
146
+ this.invalidCloseFrameLength = true;
147
+ }
148
+ if (this.length >= 2) {
149
+ this.closeStatus = ctio.ruint16(this.binaryPayload, 'big', 0);
150
+ this.binaryPayload = this.binaryPayload.slice(2);
151
+ }
152
+ }
153
+
154
+ this.parseState = COMPLETE;
155
+ return true;
156
+ }
157
+ }
158
+ return false;
159
+ };
160
+
161
+ WebSocketFrame.prototype.throwAwayPayload = function(bufferList) {
162
+ if (bufferList.length >= this.length) {
163
+ bufferList.advance(this.length);
164
+ this.parseState = COMPLETE;
165
+ return true;
166
+ }
167
+ return false;
168
+ };
169
+
170
+ WebSocketFrame.prototype.toBuffer = function(nullMask) {
171
+ var maskKey;
172
+ var headerLength = 2;
173
+ var data;
174
+ var outputPos;
175
+ var firstByte = 0x00;
176
+ var secondByte = 0x00;
177
+
178
+ if (this.fin) {
179
+ firstByte |= 0x80;
180
+ }
181
+ if (this.rsv1) {
182
+ firstByte |= 0x40;
183
+ }
184
+ if (this.rsv2) {
185
+ firstByte |= 0x20;
186
+ }
187
+ if (this.rsv3) {
188
+ firstByte |= 0x10;
189
+ }
190
+ if (this.mask) {
191
+ secondByte |= 0x80;
192
+ }
193
+
194
+ firstByte |= (this.opcode & 0x0F);
195
+
196
+ // the close frame is a special case because the close reason is
197
+ // prepended to the payload data.
198
+ if (this.opcode === 0x08) {
199
+ this.length = 2;
200
+ if (this.binaryPayload) {
201
+ this.length += this.binaryPayload.length;
202
+ }
203
+ data = new Buffer(this.length);
204
+ ctio.wuint16(this.closeStatus, 'big', data, 0);
205
+ if (this.length > 2) {
206
+ this.binaryPayload.copy(data, 2);
207
+ }
208
+ }
209
+ else if (this.binaryPayload) {
210
+ data = this.binaryPayload;
211
+ this.length = data.length;
212
+ }
213
+ else {
214
+ this.length = 0;
215
+ }
216
+
217
+ if (this.length <= 125) {
218
+ // encode the length directly into the two-byte frame header
219
+ secondByte |= (this.length & 0x7F);
220
+ }
221
+ else if (this.length > 125 && this.length <= 0xFFFF) {
222
+ // Use 16-bit length
223
+ secondByte |= 126;
224
+ headerLength += 2;
225
+ }
226
+ else if (this.length > 0xFFFF) {
227
+ // Use 64-bit length
228
+ secondByte |= 127;
229
+ headerLength += 8;
230
+ }
231
+
232
+ var output = new Buffer(this.length + headerLength + (this.mask ? 4 : 0));
233
+
234
+ // write the frame header
235
+ output[0] = firstByte;
236
+ output[1] = secondByte;
237
+
238
+ outputPos = 2;
239
+
240
+ if (this.length > 125 && this.length <= 0xFFFF) {
241
+ // write 16-bit length
242
+ ctio.wuint16(this.length, 'big', output, outputPos);
243
+ outputPos += 2;
244
+ }
245
+ else if (this.length > 0xFFFF) {
246
+ // write 64-bit length
247
+ ctio.wuint64([0x00000000, this.length], 'big', output, outputPos);
248
+ outputPos += 8;
249
+ }
250
+
251
+ if (this.length > 0) {
252
+ if (this.mask) {
253
+ if (!nullMask) {
254
+ // Generate a mask key
255
+ maskKey = parseInt(Math.random()*0xFFFFFFFF);
256
+ }
257
+ else {
258
+ maskKey = 0x00000000;
259
+ }
260
+ ctio.wuint32(maskKey, 'big', this.maskBytes, 0);
261
+
262
+ // write the mask key
263
+ this.maskBytes.copy(output, outputPos);
264
+ outputPos += 4;
265
+
266
+ data.copy(output, outputPos);
267
+ xor(output.slice(outputPos), this.maskBytes, 0);
268
+ }
269
+ else {
270
+ data.copy(output, outputPos);
271
+ }
272
+ }
273
+
274
+ return output;
275
+ };
276
+
277
+ WebSocketFrame.prototype.toString = function() {
278
+ return "Opcode: " + this.opcode + ", fin: " + this.fin + ", length: " + this.length + ", hasPayload: " + Boolean(this.binaryPayload) + ", masked: " + this.mask;
279
+ };
280
+
281
+
282
+ module.exports = WebSocketFrame;
@@ -0,0 +1,478 @@
1
+ /************************************************************************
2
+ * Copyright 2010-2011 Worlize Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ ***********************************************************************/
16
+
17
+ var deprecation = require('./Deprecation');
18
+
19
+ var crypto = require('crypto');
20
+ var util = require('util');
21
+ var url = require('url');
22
+ var EventEmitter = require('events').EventEmitter;
23
+ var WebSocketConnection = require('./WebSocketConnection');
24
+ var Constants = require('./Constants');
25
+
26
+ var headerValueSplitRegExp = /,\s*/;
27
+ var headerParamSplitRegExp = /;\s*/;
28
+ var headerSanitizeRegExp = /[\r\n]/g;
29
+ var separators = [
30
+ "(", ")", "<", ">", "@",
31
+ ",", ";", ":", "\\", "\"",
32
+ "/", "[", "]", "?", "=",
33
+ "{", "}", " ", String.fromCharCode(9)
34
+ ];
35
+ var controlChars = [String.fromCharCode(127) /* DEL */];
36
+ for (var i=0; i < 31; i ++) {
37
+ /* US-ASCII Control Characters */
38
+ controlChars.push(String.fromCharCode(i));
39
+ }
40
+
41
+ var cookieNameValidateRegEx = /([\x00-\x20\x22\x28\x29\x2c\x2f\x3a-\x3f\x40\x5b-\x5e\x7b\x7d\x7f])/;
42
+ var cookieValueValidateRegEx = /[^\x21\x23-\x2b\x2d-\x3a\x3c-\x5b\x5d-\x7e]/;
43
+ var cookieValueDQuoteValidateRegEx = /^"[^"]*"$/;
44
+ var controlCharsAndSemicolonRegEx = /[\x00-\x20\x3b]/g;
45
+
46
+ var cookieSeparatorRegEx = /[;,] */;
47
+
48
+ var httpStatusDescriptions = {
49
+ 100: "Continue",
50
+ 101: "Switching Protocols",
51
+ 200: "OK",
52
+ 201: "Created",
53
+ 203: "Non-Authoritative Information",
54
+ 204: "No Content",
55
+ 205: "Reset Content",
56
+ 206: "Partial Content",
57
+ 300: "Multiple Choices",
58
+ 301: "Moved Permanently",
59
+ 302: "Found",
60
+ 303: "See Other",
61
+ 304: "Not Modified",
62
+ 305: "Use Proxy",
63
+ 307: "Temporary Redirect",
64
+ 400: "Bad Request",
65
+ 401: "Unauthorized",
66
+ 402: "Payment Required",
67
+ 403: "Forbidden",
68
+ 404: "Not Found",
69
+ 406: "Not Acceptable",
70
+ 407: "Proxy Authorization Required",
71
+ 408: "Request Timeout",
72
+ 409: "Conflict",
73
+ 410: "Gone",
74
+ 411: "Length Required",
75
+ 412: "Precondition Failed",
76
+ 413: "Request Entity Too Long",
77
+ 414: "Request-URI Too Long",
78
+ 415: "Unsupported Media Type",
79
+ 416: "Requested Range Not Satisfiable",
80
+ 417: "Expectation Failed",
81
+ 426: "Upgrade Required",
82
+ 500: "Internal Server Error",
83
+ 501: "Not Implemented",
84
+ 502: "Bad Gateway",
85
+ 503: "Service Unavailable",
86
+ 504: "Gateway Timeout",
87
+ 505: "HTTP Version Not Supported"
88
+ };
89
+
90
+ function WebSocketRequest(socket, httpRequest, serverConfig) {
91
+ this.socket = socket;
92
+ this.httpRequest = httpRequest;
93
+ this.resource = httpRequest.url;
94
+ this.remoteAddress = socket.remoteAddress;
95
+ this.serverConfig = serverConfig;
96
+ }
97
+
98
+ util.inherits(WebSocketRequest, EventEmitter);
99
+
100
+ WebSocketRequest.prototype.readHandshake = function() {
101
+ var self = this;
102
+ var request = this.httpRequest;
103
+
104
+ // Decode URL
105
+ this.resourceURL = url.parse(this.resource, true);
106
+
107
+ this.host = request.headers['host'];
108
+ if (!this.host) {
109
+ throw new Error("Client must provide a Host header.");
110
+ }
111
+
112
+ this.key = request.headers['sec-websocket-key'];
113
+ if (!this.key) {
114
+ throw new Error("Client must provide a value for Sec-WebSocket-Key.");
115
+ }
116
+
117
+ this.webSocketVersion = parseInt(request.headers['sec-websocket-version'], 10);
118
+ // Deprecated websocketVersion (proper casing...)
119
+ Object.defineProperty(this, "websocketVersion", {
120
+ get: function() {
121
+ deprecation.warn('websocketVersion');
122
+ return this.webSocketVersion;
123
+ }
124
+ });
125
+
126
+ if (!this.webSocketVersion || isNaN(this.webSocketVersion)) {
127
+ throw new Error("Client must provide a value for Sec-WebSocket-Version.");
128
+ }
129
+
130
+ switch (this.webSocketVersion) {
131
+ case 8:
132
+ case 13:
133
+ break;
134
+ default:
135
+ var e = new Error("Unsupported websocket client version: " + this.webSocketVersion +
136
+ "Only versions 8 and 13 are supported.");
137
+ e.httpCode = 426;
138
+ e.headers = {
139
+ "Sec-WebSocket-Version": "13"
140
+ };
141
+ throw e;
142
+ }
143
+
144
+ if (this.webSocketVersion === 13) {
145
+ this.origin = request.headers['origin'];
146
+ }
147
+ else if (this.webSocketVersion === 8) {
148
+ this.origin = request.headers['sec-websocket-origin'];
149
+ }
150
+
151
+ // Protocol is optional.
152
+ var protocolString = request.headers['sec-websocket-protocol'];
153
+ this.protocolFullCaseMap = {};
154
+ this.requestedProtocols = [];
155
+ if (protocolString) {
156
+ var requestedProtocolsFullCase = protocolString.split(headerValueSplitRegExp);
157
+ requestedProtocolsFullCase.forEach(function(protocol) {
158
+ var lcProtocol = protocol.toLocaleLowerCase();
159
+ self.requestedProtocols.push(lcProtocol);
160
+ self.protocolFullCaseMap[lcProtocol] = protocol;
161
+ });
162
+ }
163
+
164
+ if (request.headers['x-forwarded-for']) {
165
+ this.remoteAddress = request.headers['x-forwarded-for'].split(', ')[0];
166
+ }
167
+
168
+ // Extensions are optional.
169
+ var extensionsString = request.headers['sec-websocket-extensions'];
170
+ this.requestedExtensions = this.parseExtensions(extensionsString);
171
+
172
+ // Cookies are optional
173
+ var cookieString = request.headers['cookie'];
174
+ this.cookies = this.parseCookies(cookieString);
175
+ };
176
+
177
+ WebSocketRequest.prototype.parseExtensions = function(extensionsString) {
178
+ if (!extensionsString || extensionsString.length === 0) {
179
+ return [];
180
+ }
181
+ extensions = extensionsString.toLocaleLowerCase().split(headerValueSplitRegExp);
182
+ extensions.forEach(function(extension, index, array) {
183
+ var params = extension.split(headerParamSplitRegExp);
184
+ var extensionName = params[0];
185
+ var extensionParams = params.slice(1);
186
+ extensionParams.forEach(function(rawParam, index, array) {
187
+ var arr = rawParam.split('=');
188
+ var obj = {
189
+ name: arr[0],
190
+ value: arr[1]
191
+ };
192
+ array.splice(index, 1, obj);
193
+ });
194
+ var obj = {
195
+ name: extensionName,
196
+ params: extensionParams
197
+ };
198
+ array.splice(index, 1, obj);
199
+ });
200
+ return extensions;
201
+ };
202
+
203
+ // This function adapted from node-cookie
204
+ // https://github.com/shtylman/node-cookie
205
+ WebSocketRequest.prototype.parseCookies = function(str) {
206
+ // Sanity Check
207
+ if (!str || typeof(str) !== 'string') {
208
+ return [];
209
+ }
210
+
211
+ var cookies = [];
212
+ var pairs = str.split(cookieSeparatorRegEx);
213
+
214
+ pairs.forEach(function(pair) {
215
+ var eq_idx = pair.indexOf('=');
216
+ if (eq_idx === -1) {
217
+ cookies.push({
218
+ name: pair,
219
+ value: null
220
+ });
221
+ return;
222
+ }
223
+
224
+ var key = pair.substr(0, eq_idx).trim();
225
+ var val = pair.substr(++eq_idx, pair.length).trim();
226
+
227
+ // quoted values
228
+ if ('"' == val[0]) {
229
+ val = val.slice(1, -1);
230
+ }
231
+
232
+ cookies.push({
233
+ name: key,
234
+ value: decodeURIComponent(val)
235
+ });
236
+ });
237
+
238
+ return cookies;
239
+ };
240
+
241
+ WebSocketRequest.prototype.accept = function(acceptedProtocol, allowedOrigin, cookies) {
242
+ // TODO: Handle extensions
243
+ if (acceptedProtocol) {
244
+ var protocolFullCase = this.protocolFullCaseMap[acceptedProtocol.toLocaleLowerCase()];
245
+ if (typeof(protocolFullCase) === 'undefined') {
246
+ protocolFullCase = acceptedProtocol;
247
+ }
248
+ }
249
+ else {
250
+ protocolFullCase = acceptedProtocol;
251
+ }
252
+ this.protocolFullCaseMap = null;
253
+
254
+ var connection = new WebSocketConnection(this.socket, [], acceptedProtocol, false, this.serverConfig);
255
+
256
+ connection.webSocketVersion = this.webSocketVersion;
257
+ // Deprecated websocketVersion (proper casing...)
258
+ Object.defineProperty(connection, "websocketVersion", {
259
+ get: function() {
260
+ deprecation.warn('websocketVersion');
261
+ return this.webSocketVersion;
262
+ }
263
+ });
264
+ connection.remoteAddress = this.remoteAddress;
265
+
266
+ // Create key validation hash
267
+ var sha1 = crypto.createHash('sha1');
268
+ sha1.update(this.key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
269
+ var acceptKey = sha1.digest('base64');
270
+
271
+ var response = "HTTP/1.1 101 Switching Protocols\r\n" +
272
+ "Upgrade: websocket\r\n" +
273
+ "Connection: Upgrade\r\n" +
274
+ "Sec-WebSocket-Accept: " + acceptKey + "\r\n";
275
+
276
+ if (protocolFullCase) {
277
+ // validate protocol
278
+ for (var i=0; i < protocolFullCase.length; i++) {
279
+ var charCode = protocolFullCase.charCodeAt(i);
280
+ var character = protocolFullCase.charAt(i);
281
+ if (charCode < 0x21 || charCode > 0x7E || separators.indexOf(character) !== -1) {
282
+ this.reject(500);
283
+ throw new Error("Illegal character '" + String.fromCharCode(character) + "' in subprotocol.");
284
+ }
285
+ }
286
+ if (this.requestedProtocols.indexOf(acceptedProtocol) === -1) {
287
+ this.reject(500);
288
+ throw new Error("Specified protocol was not requested by the client.");
289
+ }
290
+
291
+ protocolFullCase = protocolFullCase.replace(headerSanitizeRegExp, '');
292
+ response += "Sec-WebSocket-Protocol: " + protocolFullCase + "\r\n";
293
+ }
294
+ this.requestedProtocols = null;
295
+
296
+ if (allowedOrigin) {
297
+ allowedOrigin = allowedOrigin.replace(headerSanitizeRegExp, '');
298
+ if (this.webSocketVersion === 13) {
299
+ response += "Origin: " + allowedOrigin + "\r\n";
300
+ }
301
+ else if (this.webSocketVersion === 8) {
302
+ response += "Sec-WebSocket-Origin: " + allowedOrigin + "\r\n";
303
+ }
304
+ }
305
+
306
+ if (cookies) {
307
+ if (!Array.isArray(cookies)) {
308
+ this.reject(500);
309
+ throw new Error("Value supplied for 'cookies' argument must be an array.");
310
+ }
311
+ var seenCookies = {};
312
+ cookies.forEach(function(cookie) {
313
+ if (!cookie.name || !cookie.value) {
314
+ this.reject(500);
315
+ throw new Error("Each cookie to set must at least provide a 'name' and 'value'");
316
+ }
317
+
318
+ // Make sure there are no \r\n sequences inserted
319
+ cookie.name = cookie.name.replace(controlCharsAndSemicolonRegEx, '');
320
+ cookie.value = cookie.value.replace(controlCharsAndSemicolonRegEx, '');
321
+
322
+ if (seenCookies[cookie.name]) {
323
+ this.reject(500);
324
+ throw new Error("You may not specify the same cookie name twice.");
325
+ }
326
+ seenCookies[cookie.name] = true;
327
+
328
+ // token (RFC 2616, Section 2.2)
329
+ var invalidChar = cookie.name.match(cookieNameValidateRegEx);
330
+ if (invalidChar) {
331
+ this.reject(500);
332
+ throw new Error("Illegal character " + invalidChar[0] + " in cookie name");
333
+ }
334
+
335
+ // RFC 6265, Section 4.1.1
336
+ // *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) | %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
337
+ if (cookie.value.match(cookieValueDQuoteValidateRegEx)) {
338
+ invalidChar = cookie.value.slice(1, -1).match(cookieValueValidateRegEx);
339
+ } else {
340
+ invalidChar = cookie.value.match(cookieValueValidateRegEx);
341
+ }
342
+ if (invalidChar) {
343
+ this.reject(500);
344
+ throw new Error("Illegal character " + invalidChar[0] + " in cookie value");
345
+ }
346
+
347
+ var cookieParts = [cookie.name + "=" + cookie.value];
348
+
349
+ // RFC 6265, Section 4.1.1
350
+ // "Path=" path-value | <any CHAR except CTLs or ";">
351
+ if(cookie.path){
352
+ invalidChar = cookie.path.match(controlCharsAndSemicolonRegEx);
353
+ if (invalidChar) {
354
+ this.reject(500);
355
+ throw new Error("Illegal character " + invalidChar[0] + " in cookie path");
356
+ }
357
+ cookieParts.push("Path=" + cookie.path);
358
+ }
359
+
360
+ // RFC 6265, Section 4.1.2.3
361
+ // "Domain=" subdomain
362
+ if (cookie.domain) {
363
+ if (typeof(cookie.domain) !== 'string') {
364
+ this.reject(500);
365
+ throw new Error("Domain must be specified and must be a string.");
366
+ }
367
+ var domain = cookie.domain.toLowerCase();
368
+ invalidChar = cookie.domain.match(controlCharsAndSemicolonRegEx);
369
+ if (invalidChar) {
370
+ this.reject(500);
371
+ throw new Error("Illegal character " + invalidChar[0] + " in cookie domain");
372
+ }
373
+ cookieParts.push("Domain=" + cookie.domain.toLowerCase());
374
+ }
375
+
376
+ // RFC 6265, Section 4.1.1
377
+ //"Expires=" sane-cookie-date | Force Date object requirement by using only epoch
378
+ if (cookie.expires) {
379
+ if (!(cookie.expires instanceof Date)){
380
+ this.reject(500);
381
+ throw new Error("Value supplied for cookie 'expires' must be a vaild date object");
382
+ }
383
+ cookieParts.push("Expires=" + cookie.expires.toGMTString());
384
+ }
385
+
386
+ // RFC 6265, Section 4.1.1
387
+ //"Max-Age=" non-zero-digit *DIGIT
388
+ if (cookie.maxage) {
389
+ var maxage = cookie.maxage;
390
+ if (typeof(maxage) === 'string') {
391
+ maxage = parseInt(maxage, 10);
392
+ }
393
+ if (isNaN(maxage) || maxage <= 0 ) {
394
+ this.reject(500);
395
+ throw new Error("Value supplied for cookie 'maxage' must be a non-zero number");
396
+ }
397
+ maxage = Math.round(maxage);
398
+ cookieParts.push("Max-Age=" + maxage.toString(10));
399
+ }
400
+
401
+ // RFC 6265, Section 4.1.1
402
+ //"Secure;"
403
+ if (cookie.secure) {
404
+ if (typeof(cookie.secure) !== "boolean") {
405
+ this.reject(500);
406
+ throw new Error("Value supplied for cookie 'secure' must be of type boolean");
407
+ }
408
+ cookieParts.push("Secure");
409
+ }
410
+
411
+ // RFC 6265, Section 4.1.1
412
+ //"HttpOnly;"
413
+ if (cookie.httponly) {
414
+ if (typeof(cookie.httponly) !== "boolean") {
415
+ this.reject(500);
416
+ throw new Error("Value supplied for cookie 'httponly' must be of type boolean");
417
+ }
418
+ cookieParts.push("HttpOnly");
419
+ }
420
+
421
+ response += ("Set-Cookie: " + cookieParts.join(';') + "\r\n");
422
+ }.bind(this));
423
+ }
424
+
425
+ // TODO: handle negotiated extensions
426
+ // if (negotiatedExtensions) {
427
+ // response += "Sec-WebSocket-Extensions: " + negotiatedExtensions.join(", ") + "\r\n";
428
+ // }
429
+
430
+ response += "\r\n";
431
+ try {
432
+ this.socket.write(response, 'ascii');
433
+ }
434
+ catch(e) {
435
+ if (Constants.DEBUG) {
436
+ console.log("Error Writing to Socket: " + e.toString());
437
+ }
438
+ // Since we have to return a connection object even if the socket is
439
+ // already dead in order not to break the API, we schedule a 'close'
440
+ // event on the connection object to occur immediately.
441
+ process.nextTick(function() {
442
+ // WebSocketConnection.CLOSE_REASON_ABNORMAL = 1006
443
+ // Third param: Skip sending the close frame to a dead socket
444
+ connection.drop(1006, "TCP connection lost before handshake completed.", true);
445
+ });
446
+ }
447
+
448
+ this.emit('requestAccepted', connection);
449
+
450
+ return connection;
451
+ };
452
+
453
+ WebSocketRequest.prototype.reject = function(status, reason, extraHeaders) {
454
+ if (typeof(status) !== 'number') {
455
+ status = 403;
456
+ }
457
+ var response = "HTTP/1.1 " + status + " " + httpStatusDescriptions[status] + "\r\n" +
458
+ "Connection: close\r\n";
459
+ if (reason) {
460
+ reason = reason.replace(headerSanitizeRegExp, '');
461
+ response += "X-WebSocket-Reject-Reason: " + reason + "\r\n";
462
+ }
463
+
464
+ if (extraHeaders) {
465
+ for (var key in extraHeaders) {
466
+ var sanitizedValue = extraHeaders[key].toString().replace(headerSanitizeRegExp, '');
467
+ var sanitizedKey = key.replace(headerSanitizeRegExp, '');
468
+ response += (sanitizedKey + ": " + sanitizedValue + "\r\n");
469
+ }
470
+ }
471
+
472
+ response += "\r\n";
473
+ this.socket.end(response, 'ascii');
474
+
475
+ this.emit('requestRejected', this);
476
+ };
477
+
478
+ module.exports = WebSocketRequest;