module Thin # Raise when we require the server to stop class StopServer < Exception; end # The Thin HTTP server used to served request. # It listen for incoming request on a given port # and forward all request to +app+. # # Based on HTTP 1.1 protocol specs: # http://www.w3.org/Protocols/rfc2616/rfc2616.html class Server include Logging include Daemonizable # Address and port on which the server is listening for connections. attr_accessor :port, :host # UNIX domain socket on which the server is listening for connections. attr_accessor :socket # App called with the request that produces the response. attr_accessor :app # Maximum time for incoming data to arrive attr_accessor :timeout # Creates a new server bound to host:port # or to +socket+ that will pass request to +app+. # If +host_or_socket+ contains a / it is assumed # to be a UNIX domain socket filename. # If a block is passed, a Rack::Builder instance # will be passed to build the +app+. # # Server.new '0.0.0.0', 3000 do # use Rack::CommonLogger # use Rack::ShowExceptions # map "/lobster" do # use Rack::Lint # run Rack::Lobster.new # end # end.start # def initialize(host_or_socket, port=3000, app=nil, &block) if host_or_socket.include?('/') @socket = host_or_socket else @host = host_or_socket @port = port.to_i end @app = app @timeout = 60 # sec @app = Rack::Builder.new(&block).to_app if block end def self.start(*args, &block) new(*args, &block).start! end # Start the server and listen for connections def start raise ArgumentError, "app required" unless @app trap('INT') { stop } trap('TERM') { stop! } # See http://rubyeventmachine.com/pub/rdoc/files/EPOLL.html EventMachine.epoll log ">> Thin web server (v#{VERSION::STRING} codename #{VERSION::CODENAME})" trace ">> Tracing ON" EventMachine.run do begin start_server rescue StopServer stop end end end alias :start! :start # Stops the server by stopping the listening loop. def stop EventMachine.stop_event_loop rescue warn "Error stopping : #{$!}" end # Stops the server by raising an error. def stop! raise StopServer end protected def start_server if @socket start_server_on_socket else start_server_on_host end end def start_server_on_host log ">> Listening on #{@host}:#{@port}, CTRL+C to stop" EventMachine.start_server(@host, @port, Connection, &method(:initialize_connection)) end def start_server_on_socket log ">> Listening on #{@socket}, CTRL+C to stop" EventMachine.start_unix_domain_server(@socket, Connection, &method(:initialize_connection)) end def initialize_connection(connection) connection.comm_inactivity_timeout = @timeout connection.app = @app connection.silent = @silent connection.unix_socket = !@socket.nil? end end end