volt-sockjs 0.3.4.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.
- checksums.yaml +7 -0
- data/LICENCE +19 -0
- data/README.textile +118 -0
- data/lib/meta-state.rb +151 -0
- data/lib/rack/sockjs.rb +173 -0
- data/lib/sockjs.rb +59 -0
- data/lib/sockjs/callbacks.rb +19 -0
- data/lib/sockjs/connection.rb +45 -0
- data/lib/sockjs/delayed-response-body.rb +99 -0
- data/lib/sockjs/duck-punch-rack-mount.rb +12 -0
- data/lib/sockjs/duck-punch-thin-response.rb +15 -0
- data/lib/sockjs/examples/protocol_conformance_test.rb +73 -0
- data/lib/sockjs/faye.rb +18 -0
- data/lib/sockjs/protocol.rb +97 -0
- data/lib/sockjs/servers/request.rb +137 -0
- data/lib/sockjs/servers/response.rb +170 -0
- data/lib/sockjs/session.rb +492 -0
- data/lib/sockjs/transport.rb +357 -0
- data/lib/sockjs/transports/eventsource.rb +30 -0
- data/lib/sockjs/transports/htmlfile.rb +73 -0
- data/lib/sockjs/transports/iframe.rb +68 -0
- data/lib/sockjs/transports/info.rb +48 -0
- data/lib/sockjs/transports/jsonp.rb +84 -0
- data/lib/sockjs/transports/websocket.rb +198 -0
- data/lib/sockjs/transports/welcome_screen.rb +17 -0
- data/lib/sockjs/transports/xhr.rb +75 -0
- data/lib/sockjs/version.rb +13 -0
- data/spec/sockjs/protocol_spec.rb +49 -0
- data/spec/sockjs/session_spec.rb +51 -0
- data/spec/sockjs/transport_spec.rb +73 -0
- data/spec/sockjs/transports/eventsource_spec.rb +56 -0
- data/spec/sockjs/transports/htmlfile_spec.rb +72 -0
- data/spec/sockjs/transports/iframe_spec.rb +66 -0
- data/spec/sockjs/transports/jsonp_spec.rb +252 -0
- data/spec/sockjs/transports/websocket_spec.rb +101 -0
- data/spec/sockjs/transports/welcome_screen_spec.rb +36 -0
- data/spec/sockjs/transports/xhr_spec.rb +314 -0
- data/spec/sockjs/version_spec.rb +18 -0
- data/spec/sockjs_spec.rb +8 -0
- data/spec/spec_helper.rb +121 -0
- data/spec/support/async-test.rb +42 -0
- metadata +154 -0
| @@ -0,0 +1,68 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "digest/md5"
         | 
| 4 | 
            +
            require "sockjs/transport"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module SockJS
         | 
| 7 | 
            +
              module Transports
         | 
| 8 | 
            +
                class IFrame < Endpoint
         | 
| 9 | 
            +
                  register 'GET', %r{/iframe[^/]*[.]html}
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  BODY = <<-EOB.freeze
         | 
| 12 | 
            +
            <!DOCTYPE html>
         | 
| 13 | 
            +
            <html>
         | 
| 14 | 
            +
            <head>
         | 
| 15 | 
            +
              <meta http-equiv="X-UA-Compatible" content="IE=edge" />
         | 
| 16 | 
            +
              <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
         | 
| 17 | 
            +
              <script>
         | 
| 18 | 
            +
                document.domain = document.domain;
         | 
| 19 | 
            +
                _sockjs_onload = function(){SockJS.bootstrap_iframe();};
         | 
| 20 | 
            +
              </script>
         | 
| 21 | 
            +
              <script src="{{ sockjs_url }}"></script>
         | 
| 22 | 
            +
            </head>
         | 
| 23 | 
            +
            <body>
         | 
| 24 | 
            +
              <h2>Don't panic!</h2>
         | 
| 25 | 
            +
              <p>This is a SockJS hidden iframe. It's used for cross domain magic.</p>
         | 
| 26 | 
            +
            </body>
         | 
| 27 | 
            +
            </html>
         | 
| 28 | 
            +
                  EOB
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def setup_response(request, response)
         | 
| 31 | 
            +
                    SockJS.debug("body: #{@body.inspect}")
         | 
| 32 | 
            +
                    response.status = 200
         | 
| 33 | 
            +
                    response.set_header("ETag", self.etag)
         | 
| 34 | 
            +
                    response.set_cache_control
         | 
| 35 | 
            +
                    response
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def body
         | 
| 39 | 
            +
                    @body ||= BODY.gsub("{{ sockjs_url }}", options[:sockjs_url])
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  def digest
         | 
| 43 | 
            +
                    @digest ||= Digest::MD5.new
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def etag
         | 
| 47 | 
            +
                    '"' + digest.hexdigest(body) + '"'
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  # Handler.
         | 
| 51 | 
            +
                  def handle_request(request)
         | 
| 52 | 
            +
                    if request.fresh?(etag)
         | 
| 53 | 
            +
                      response = build_response(request)
         | 
| 54 | 
            +
                      response.status = 304
         | 
| 55 | 
            +
                      response.finish
         | 
| 56 | 
            +
                      return response
         | 
| 57 | 
            +
                    else
         | 
| 58 | 
            +
                      SockJS.debug "Deferring to Transport"
         | 
| 59 | 
            +
                      response = build_response(request)
         | 
| 60 | 
            +
                      response.set_content_type(:html)
         | 
| 61 | 
            +
                      response.write(body)
         | 
| 62 | 
            +
                      response.finish
         | 
| 63 | 
            +
                      return response
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
            end
         | 
| @@ -0,0 +1,48 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "sockjs/transport"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module SockJS
         | 
| 6 | 
            +
              module Transports
         | 
| 7 | 
            +
                class Info
         | 
| 8 | 
            +
                  class Get < Endpoint
         | 
| 9 | 
            +
                    register 'GET', "info"
         | 
| 10 | 
            +
                    # Handler.
         | 
| 11 | 
            +
                    def setup_response(request, response)
         | 
| 12 | 
            +
                      response.status = 200
         | 
| 13 | 
            +
                      response.set_content_type(:json)
         | 
| 14 | 
            +
                      response.set_access_control(request.origin)
         | 
| 15 | 
            +
                      response.set_allow_options_post
         | 
| 16 | 
            +
                      response.set_no_cache
         | 
| 17 | 
            +
                      response.write(self.info.to_json)
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    def info
         | 
| 21 | 
            +
                      {
         | 
| 22 | 
            +
                        websocket: @options[:websocket],
         | 
| 23 | 
            +
                        origins: ["*:*"], # As specified by the spec, currently ignored.
         | 
| 24 | 
            +
                        cookie_needed: @options[:cookie_needed],
         | 
| 25 | 
            +
                        entropy: self.entropy
         | 
| 26 | 
            +
                      }
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    def entropy
         | 
| 30 | 
            +
                      rand(1 << 32)
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  class Options < Endpoint
         | 
| 35 | 
            +
                    register 'OPTIONS', 'info'
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    def setup_response(request, response)
         | 
| 38 | 
            +
                      response.status = 204
         | 
| 39 | 
            +
                      response.set_allow_options_get
         | 
| 40 | 
            +
                      response.set_cache_control
         | 
| 41 | 
            +
                      response.set_access_control(request.origin)
         | 
| 42 | 
            +
                      response.set_session_id(request.session_id)
         | 
| 43 | 
            +
                      response.write_head
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
            end
         | 
| @@ -0,0 +1,84 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "sockjs/transport"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module SockJS
         | 
| 6 | 
            +
              module Transports
         | 
| 7 | 
            +
                class JSONP < PollingConsumingTransport
         | 
| 8 | 
            +
                  register 'GET', 'jsonp'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def error_content_type
         | 
| 11 | 
            +
                    :html
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def setup_response(request, response)
         | 
| 15 | 
            +
                    response.status = 200
         | 
| 16 | 
            +
                    response.set_content_type(:javascript)
         | 
| 17 | 
            +
                    response.set_access_control(request.origin)
         | 
| 18 | 
            +
                    response.set_no_cache
         | 
| 19 | 
            +
                    response.set_session_id(request.session_id)
         | 
| 20 | 
            +
                    return response
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def get_session(response)
         | 
| 24 | 
            +
                    if response.request.callback
         | 
| 25 | 
            +
                      super
         | 
| 26 | 
            +
                    else
         | 
| 27 | 
            +
                      raise HttpError.new(500, '"callback" parameter required')
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  def format_frame(response, payload)
         | 
| 32 | 
            +
                    raise TypeError.new("Payload must not be nil!") if payload.nil?
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    # Yes, JSONed twice, there isn't a better way, we must pass
         | 
| 35 | 
            +
                    # a string back, and the script, will be evaled() by the browser.
         | 
| 36 | 
            +
                    "#{response.request.callback}(#{super.chomp.to_json});\r\n"
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                class JSONPSend < DeliveryTransport
         | 
| 41 | 
            +
                  register 'POST', 'jsonp_send'
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  # Handler.
         | 
| 44 | 
            +
                  def extract_message(request)
         | 
| 45 | 
            +
                    if request.content_type == "application/x-www-form-urlencoded"
         | 
| 46 | 
            +
                      raw_data = request.data.read || empty_payload
         | 
| 47 | 
            +
                      begin
         | 
| 48 | 
            +
                        data = Hash[URI.decode_www_form(raw_data)]
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                        data = data.fetch("d")
         | 
| 51 | 
            +
                      rescue KeyError
         | 
| 52 | 
            +
                        empty_payload
         | 
| 53 | 
            +
                      end
         | 
| 54 | 
            +
                    else
         | 
| 55 | 
            +
                      data = request.data.read
         | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    if data.nil? or data.empty?
         | 
| 59 | 
            +
                      empty_payload
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
                    data
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  def setup_response(request, response)
         | 
| 65 | 
            +
                    response.status = 200
         | 
| 66 | 
            +
                    response.set_content_type(:plain)
         | 
| 67 | 
            +
                    response.set_session_id(request.session_id)
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  def successful_response(response)
         | 
| 71 | 
            +
                    response.write("ok")
         | 
| 72 | 
            +
                    response.finish
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  def error_content_type
         | 
| 76 | 
            +
                    :html
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  def empty_payload
         | 
| 80 | 
            +
                    raise SockJS::HttpError.new(500, "Payload expected.")
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
            end
         | 
| @@ -0,0 +1,198 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
             | 
| 3 | 
            +
            def activate
         | 
| 4 | 
            +
            end# encoding: utf-8
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            require "forwardable"
         | 
| 7 | 
            +
            require "sockjs/faye"
         | 
| 8 | 
            +
            require "sockjs/transport"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            # Raw WebSocket url: /websocket
         | 
| 11 | 
            +
            # -------------------------------
         | 
| 12 | 
            +
            #
         | 
| 13 | 
            +
            # SockJS protocol defines a bit of higher level framing. This is okay
         | 
| 14 | 
            +
            # when the browser using SockJS-client establishes the connection, but
         | 
| 15 | 
            +
            # it's not really appropriate when the connection is being established
         | 
| 16 | 
            +
            # from another program. Although SockJS focuses on server-browser
         | 
| 17 | 
            +
            # communication, it should be straightforward to connect to SockJS
         | 
| 18 | 
            +
            # from command line or some any programming language.
         | 
| 19 | 
            +
            #
         | 
| 20 | 
            +
            # In order to make writing command-line clients easier, we define this
         | 
| 21 | 
            +
            # `/websocket` entry point. This entry point is special and doesn't
         | 
| 22 | 
            +
            # use any additional custom framing, no open frame, no
         | 
| 23 | 
            +
            # heartbeats. Only raw WebSocket protocol.
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            module SockJS
         | 
| 26 | 
            +
              module Transports
         | 
| 27 | 
            +
                module WSDebuggingMixin
         | 
| 28 | 
            +
                  def send_data(*args)
         | 
| 29 | 
            +
                    if args.length == 1
         | 
| 30 | 
            +
                      data = args.first
         | 
| 31 | 
            +
                    else
         | 
| 32 | 
            +
                      data = fix_buggy_input(*args)
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    SockJS.debug "WS#send #{data.inspect}"
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    super(data)
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  def fix_buggy_input(*args)
         | 
| 41 | 
            +
                    data = 'c[3000,"Go away!"]'
         | 
| 42 | 
            +
                    SockJS.debug "[ERROR] Incorrect input: #{args.inspect}, changing to #{data} for now"
         | 
| 43 | 
            +
                    return data
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def close(*args)
         | 
| 47 | 
            +
                    SockJS.debug "WS#close(#{args.inspect[1..-2]})"
         | 
| 48 | 
            +
                    super(*args)
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                class WebSocket < ConsumingTransport
         | 
| 53 | 
            +
                  register 'GET', 'websocket'
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  def disabled?
         | 
| 56 | 
            +
                    !options[:websocket]
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  def session_key(ws)
         | 
| 60 | 
            +
                    ws.object_id.to_s
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  def handle_request(request)
         | 
| 64 | 
            +
                    if not @options[:websocket]
         | 
| 65 | 
            +
                      raise HttpError.new(404, "WebSockets Are Disabled")
         | 
| 66 | 
            +
                    elsif request.env["HTTP_UPGRADE"].to_s.downcase != "websocket"
         | 
| 67 | 
            +
                      SockJS.debug("Worng headers! HTTP_UPGRADE = #{request.env["HTTP_UPGRADE"].to_s}")
         | 
| 68 | 
            +
                      raise HttpError.new(400, 'Can "Upgrade" only to "WebSocket".')
         | 
| 69 | 
            +
                    elsif not ["Upgrade", "keep-alive, Upgrade"].include?(request.env["HTTP_CONNECTION"])
         | 
| 70 | 
            +
                      SockJS.debug("Worng headers! HTTP_CONNECTION = #{request.env["HTTP_CONNECTION"].to_s}")
         | 
| 71 | 
            +
                      raise HttpError.new(400, '"Connection" must be "Upgrade".')
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                    super
         | 
| 75 | 
            +
                  end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  def build_response(request)
         | 
| 78 | 
            +
                    SockJS.debug "Upgrading to WebSockets ..."
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                    web_socket = Faye::WebSocket.new(request.env)
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                    web_socket.extend(WSDebuggingMixin)
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                    return web_socket
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  def build_error_response(request)
         | 
| 88 | 
            +
                    response = response_class.new(request)
         | 
| 89 | 
            +
                  end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  def process_session(session, web_socket)
         | 
| 92 | 
            +
                    #XXX Facade around websocket?
         | 
| 93 | 
            +
                    @session = session
         | 
| 94 | 
            +
                    web_socket.on :open do |event|
         | 
| 95 | 
            +
                      begin
         | 
| 96 | 
            +
                        SockJS.debug "Attaching consumer"
         | 
| 97 | 
            +
                        session.attach_consumer(web_socket, self)
         | 
| 98 | 
            +
                      rescue Object => ex
         | 
| 99 | 
            +
                        SockJS::debug "Error opening (#{event.inspect[0..40]}) websocket: #{ex.inspect}"
         | 
| 100 | 
            +
                      end
         | 
| 101 | 
            +
                    end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                    web_socket.on :message do |event|
         | 
| 104 | 
            +
                      begin
         | 
| 105 | 
            +
                        session.receive_message(extract_message(event))
         | 
| 106 | 
            +
                      rescue Object => ex
         | 
| 107 | 
            +
                        SockJS::debug "Error receiving message on websocket (#{event.inspect[0..40]}): #{ex.inspect}"
         | 
| 108 | 
            +
                        web_socket.close
         | 
| 109 | 
            +
                      end
         | 
| 110 | 
            +
                    end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                    web_socket.on :close do |event|
         | 
| 113 | 
            +
                      begin
         | 
| 114 | 
            +
                        session.close(1000, "Session finished")
         | 
| 115 | 
            +
                      rescue Object => ex
         | 
| 116 | 
            +
                        SockJS::debug "Error closing websocket (#{event.inspect[0..40]}): #{ex.inspect} \n#{ex.message} \n#{ex.backtrace.join("\n")}"
         | 
| 117 | 
            +
                      end
         | 
| 118 | 
            +
                    end
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  def format_frame(response, frame)
         | 
| 122 | 
            +
                    frame.to_s
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                  def send_data(web_socket, data)
         | 
| 126 | 
            +
                    web_socket.send(data)
         | 
| 127 | 
            +
                    return data.length
         | 
| 128 | 
            +
                  end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                  def finish_response(web_socket)
         | 
| 131 | 
            +
                    SockJS.debug "Finishing response"
         | 
| 132 | 
            +
                    web_socket.close
         | 
| 133 | 
            +
                  end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                  def extract_message(event)
         | 
| 136 | 
            +
                    SockJS.debug "Received message event: #{event.data.inspect}"
         | 
| 137 | 
            +
                    event.data
         | 
| 138 | 
            +
                  end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                  def heartbeat_frame(web_socket)
         | 
| 141 | 
            +
                    @pong = true if @pong.nil?
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                    #no replay from last connection - susspend session
         | 
| 144 | 
            +
                    if !@pong
         | 
| 145 | 
            +
                      @session.suspend if @session
         | 
| 146 | 
            +
                    end
         | 
| 147 | 
            +
                    @pong = false
         | 
| 148 | 
            +
                    web_socket.ping("ping") do
         | 
| 149 | 
            +
                      SockJS.debug "pong"
         | 
| 150 | 
            +
                      @pong = true
         | 
| 151 | 
            +
                      @session.activate
         | 
| 152 | 
            +
                    end
         | 
| 153 | 
            +
                    super
         | 
| 154 | 
            +
                  end
         | 
| 155 | 
            +
                end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                class RawWebSocket < WebSocket
         | 
| 158 | 
            +
                  register 'GET', 'websocket'
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                  def handle_request(request)
         | 
| 161 | 
            +
                    ver = request.env["sec-websocket-version"] || ""
         | 
| 162 | 
            +
                    unless ['8', '13'].include?(ver)
         | 
| 163 | 
            +
                      raise HttpError.new(400, 'Only supported WebSocket protocol is RFC 6455.')
         | 
| 164 | 
            +
                    end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                    super
         | 
| 167 | 
            +
                  end
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                  def self.routing_prefix
         | 
| 170 | 
            +
                    "/" + self.prefix
         | 
| 171 | 
            +
                  end
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                  def opening_frame(response)
         | 
| 174 | 
            +
                  end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                  def heartbeat_frame(response)
         | 
| 177 | 
            +
                  end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                  def extract_message(event)
         | 
| 180 | 
            +
                    SockJS.debug "Received message event: #{event.data.inspect}"
         | 
| 181 | 
            +
                    event.data.to_json
         | 
| 182 | 
            +
                  end
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                  def messages_frame(websocket, messages)
         | 
| 185 | 
            +
                    messages.inject(0) do |sent_count, data|
         | 
| 186 | 
            +
                      send_data(websocket, data)
         | 
| 187 | 
            +
                      sent_count + data.length
         | 
| 188 | 
            +
                    end
         | 
| 189 | 
            +
                  rescue Object => ex
         | 
| 190 | 
            +
                    SockJS::debug "Error delivering messages to raw websocket: #{messages.inspect} #{ex.inspect}"
         | 
| 191 | 
            +
                  end
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                  def closing_frame(response, status, message)
         | 
| 194 | 
            +
                    finish_response(response)
         | 
| 195 | 
            +
                  end
         | 
| 196 | 
            +
                end
         | 
| 197 | 
            +
              end
         | 
| 198 | 
            +
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "sockjs/transport"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module SockJS
         | 
| 6 | 
            +
              module Transports
         | 
| 7 | 
            +
                class WelcomeScreen < Endpoint
         | 
| 8 | 
            +
                  register 'GET', ''
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def setup_response(request, response)
         | 
| 11 | 
            +
                    response.set_content_type(:plain)
         | 
| 12 | 
            +
                    response.status = 200
         | 
| 13 | 
            +
                    response.write("Welcome to SockJS!\n")
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,75 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "sockjs/transport"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module SockJS
         | 
| 6 | 
            +
              module Transports
         | 
| 7 | 
            +
                class XHROptions < SessionEndpoint
         | 
| 8 | 
            +
                  register 'OPTIONS', 'xhr'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def setup_response(request, response)
         | 
| 11 | 
            +
                    response.status = 204
         | 
| 12 | 
            +
                    response.set_allow_options_post
         | 
| 13 | 
            +
                    response.set_cache_control
         | 
| 14 | 
            +
                    response.set_access_control(request.origin)
         | 
| 15 | 
            +
                    response.set_session_id(request.session_id)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                class XHRSendOptions < XHROptions
         | 
| 20 | 
            +
                  register 'OPTIONS', 'xhr_send'
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                class XHRStreamingOptions < XHROptions
         | 
| 24 | 
            +
                  register 'OPTIONS', 'xhr_streaming'
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                class XHRSendPost < DeliveryTransport
         | 
| 28 | 
            +
                  register 'POST', 'xhr_send'
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def setup_response(request, response)
         | 
| 31 | 
            +
                    response.status = 204
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    response.set_content_type(:plain)
         | 
| 34 | 
            +
                    response.set_access_control(request.origin)
         | 
| 35 | 
            +
                    response.set_session_id(request.session_id)
         | 
| 36 | 
            +
                    response
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                class XHRPost < PollingConsumingTransport
         | 
| 41 | 
            +
                  register 'POST', 'xhr'
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  def setup_response(request, response)
         | 
| 44 | 
            +
                    response.status = 200
         | 
| 45 | 
            +
                    response.set_content_type(:javascript)
         | 
| 46 | 
            +
                    response.set_access_control(request.origin)
         | 
| 47 | 
            +
                    response.set_session_id(request.session_id)
         | 
| 48 | 
            +
                    response
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                class XHRStreamingPost < ConsumingTransport
         | 
| 53 | 
            +
                  PREAMBLE ||= "h" * 2048 + "\n"
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  register 'POST', 'xhr_streaming'
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def setup_response(request, response)
         | 
| 58 | 
            +
                    response.status = 200
         | 
| 59 | 
            +
                    response.set_content_type(:javascript)
         | 
| 60 | 
            +
                    response.set_access_control(request.origin)
         | 
| 61 | 
            +
                    response.set_session_id(request.session_id)
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  def response_beginning(response)
         | 
| 65 | 
            +
                    response.write_head
         | 
| 66 | 
            +
                    response.write(PREAMBLE)
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  def handle_session_unavailable(error, response)
         | 
| 70 | 
            +
                    response.write(PREAMBLE)
         | 
| 71 | 
            +
                    super(error, response)
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
            end
         |