Class: WEBrick::HTTPServer
- Inherits:
-
Object
- Object
- WEBrick::HTTPServer
- Defined in:
- lib/webtube/webrick.rb,
lib/webtube/webrick.rb
Instance Method Summary collapse
-
#accept_webtube(request, response, listener, session: nil, context: nil) ⇒ Object
Given a [[request]] and a [[response]] object, as prepared by a [[WEBrick::HTTPServer]] for processing in a portlet, attempt to accept the client’s request to establish a WebSocket connection.
-
#initialize(config = {}, default = Config::HTTP) ⇒ HTTPServer
constructor
A new instance of HTTPServer.
- #mount_webtube(dir, listener) ⇒ Object
-
#orig_initialize_before_webtube_integration ⇒ Object
Attach a [[Webtube::Vital_Statistics]] to new [[WEBrick::HTTPServer]] instances so that the live webtubes could be closed upon shutdown.
- #orig_shutdown_before_webtube_integration ⇒ Object
- #shutdown ⇒ Object
- #webtubes ⇒ Object
Constructor Details
#initialize(config = {}, default = Config::HTTP) ⇒ HTTPServer
Returns a new instance of HTTPServer.
30 31 32 33 34 |
# File 'lib/webtube/webrick.rb', line 30 def initialize config = {}, default = Config::HTTP orig_initialize_before_webtube_integration config, default @webtubes = Webtube::Vital_Statistics.new @logger return end |
Instance Method Details
#accept_webtube(request, response, listener, session: nil, context: nil) ⇒ Object
Given a [[request]] and a [[response]] object, as prepared by a [[WEBrick::HTTPServer]] for processing in a portlet, attempt to accept the client’s request to establish a WebSocket connection. The [[request]] must actually contain such a request; see [[websocket_upgrade_request?]].
The attempt will fail in the theoretical case the client and the server can’t agree on the protocol version to use. In such a case, [[accept_webtube]] will prepare a 426 ‘Upgrade required’ response, explaining in plain text what the problem is and advertising, using the
- [Sec-WebSocket-Version]
-
header field, the protocol
version (specifically, 13) it is prepared to speak. When this happens, the WebSocket session will never be set up and no [[listener]] events will be called.
Note that [[accept_webtube]] will manipulate [[response]] and return immediately. The actual WebSocket session will begin once WEBrick attempts to deliver the [[response]], and will be marked by the newly constructed [[Webtube]] instance delivering an [[onopen]] event to [[listener]].
Also note that the loop to process incoming WebSocket frames will hog the whole thread; in order to deliver asynchronous messages over the WebSocket,
- [Webtube#send_message]
-
needs to be called from another
thread. (For synchronous messages, it can safely be called from the handlers inside [[listener]].)
See [[Webtube#run]] for a list of the supported methods for the [[listener]].
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/webtube/webrick.rb', line 98 def accept_webtube request, response, listener, session: nil, context: nil # Check that the client speaks our version unless (request['Sec-WebSocket-Version'] || ''). strip.split(/\s*,\s*/). include? '13' then @logger.error "Sec-WebSocket-Version mismatch" response.status, response.reason_phrase = '426', 'Upgrade required' response['Content-type'] = 'text/plain' response['Sec-WebSocket-Version'] = '13' # advertise the version we speak response.body = "This WebSocket server only speaks " + "version 13 of the protocol, as specified by " + "RFC 6455.\n" else response.status, response.reason_phrase = '101', 'Hello WebSocket' response['Upgrade'] = 'websocket' response['Sec-WebSocket-Accept'] = OpenSSL::Digest::SHA1.base64digest( request['Sec-WebSocket-Key'] + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11') response['Sec-WebSocket-Version'] = '13' response.keep_alive = false # so that WEBrick will close the TCP socket when # we're done vital_statistics = self.webtubes (class << response; self; end).instance_eval do # We'll need to deliver the [[Connection: Upgrade]] # header; unfortunately, HTTPResponse#setup_header # would munge it if we set this header field in the # ordinary way. Accordingly, we'll have to override # the method. define_method :setup_header do || super() @header['connection'] = 'Upgrade' return end # Replace [[response.send_body]] with the WS engine. # WEBrick will call it automatically after sending the # response header. # # Also notify the server's attached # [[Webtube::Vital_Statistics]] instance so that # server shutdown could also close all pending # Webtubes. define_method :send_body do |socket| webtube = Webtube.new socket, true, close_socket: false begin vital_statistics.birth webtube webtube.header = request webtube.session = session webtube.context = context # Reassign us from the WEBrick's thread group to # the one maintained by # [[Webtube::Vital_Statistics]]. vital_statistics.thread_group.add Thread.current # And now, run! webtube.run listener ensure vital_statistics.death webtube end return end end end return end |
#mount_webtube(dir, listener) ⇒ Object
202 203 204 205 |
# File 'lib/webtube/webrick.rb', line 202 def mount_webtube dir, listener mount dir, HTTPServlet::WebtubeHandler.new(self, listener) return end |
#orig_initialize_before_webtube_integration ⇒ Object
Attach a [[Webtube::Vital_Statistics]] to new
- [WEBrick::HTTPServer]
-
instances so that the live
webtubes could be closed upon shutdown
29 |
# File 'lib/webtube/webrick.rb', line 29 alias orig_initialize_before_webtube_integration initialize |
#orig_shutdown_before_webtube_integration ⇒ Object
54 |
# File 'lib/webtube/webrick.rb', line 54 alias orig_shutdown_before_webtube_integration shutdown |
#shutdown ⇒ Object
55 56 57 58 59 60 61 62 63 64 |
# File 'lib/webtube/webrick.rb', line 55 def shutdown # We'll need to call the original shutdown code first, for # we want to stop accepting new Webtube connections before # 'close all Webtube connections' will have a proper, # thread-safe meaning. orig_shutdown_before_webtube_integration webtubes.close_all webtubes.thread_group.list.each &:join return end |
#webtubes ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/webtube/webrick.rb', line 36 def webtubes result = @webtubes # Usually, this should be it. if result.nil? then # ... but ... # Well, it would seem that our extended constructor was # not called. How could this have happened? result = @webtubes = Webtube::Vital_Statistics.new @logger.warn "@webtubes (in a WEBrick::HTTPServer) " + "has not been set up before accessing it. I " + "have attempted to correct this ex post facto, " + "but doing it now is a race condition, and I may " + "have lost track of some webtubes as a result. " + "The next time, please load webtube/webrick.rb " + "/before/ instantiating your WEBrick::HTTPServer." end return result end |