Class Bcat::Server
In: lib/bcat/server.rb
Parent: Object

Simple Rack handler based largely on Scott Chacon‘s kidgloves library: github.com/schacon/kidgloves

Methods

bind   listen   log   new   process_request   run   status_message  

Attributes

app  [RW] 

Public Class methods

[Source]

    # File lib/bcat/server.rb, line 15
15:     def initialize(app, options={})
16:       @app = app
17:       @host = options[:Host] || '0.0.0.0'
18:       @port = options[:Port] || 8089
19:     end

[Source]

    # File lib/bcat/server.rb, line 11
11:     def self.run(app, options={}, &block)
12:       new(app, options).listen(&block)
13:     end

Public Instance methods

[Source]

    # File lib/bcat/server.rb, line 21
21:     def bind(host, port)
22:       TCPServer.new(host, port)
23:     rescue Errno::EADDRINUSE
24:       port += 1
25:       retry
26:     end

[Source]

    # File lib/bcat/server.rb, line 28
28:     def listen
29:       server = TCPServer.new(@host, @port)
30: 
31:       yield server if block_given?
32: 
33:       loop do
34:         socket = server.accept
35:         socket.sync = true
36:         log "#{socket.peeraddr[2]} (#{socket.peeraddr[3]})"
37:         begin
38:           req = {}
39: 
40:           # parse the request line
41:           request = socket.gets
42:           method, path, version = request.split(" ", 3)
43:           req["REQUEST_METHOD"] = method
44:           info, query = path.split("?")
45:           req["PATH_INFO"] = info
46:           req["QUERY_STRING"] = query
47: 
48:           # parse the headers
49:           while (line = socket.gets)
50:             line.strip!
51:             break if line.size == 0
52:             key, val = line.split(": ")
53:             key = key.upcase.gsub('-', '_')
54:             key = "HTTP_#{key}" if !%w[CONTENT_TYPE CONTENT_LENGTH].include?(key)
55:             req[key] = val
56:           end
57: 
58:           # parse the body
59:           body =
60:             if len = req['CONTENT_LENGTH']
61:               socket.read(len.to_i)
62:             else
63:               ''
64:             end
65: 
66:           # process the request
67:           process_request(req, body, socket)
68:         ensure
69:           socket.close if not socket.closed?
70:         end
71:       end
72:     end

[Source]

    # File lib/bcat/server.rb, line 74
74:     def log(message)
75:       # $stderr.puts message
76:     end

[Source]

     # File lib/bcat/server.rb, line 82
 82:     def process_request(request, input_body, socket)
 83:       env = {}.replace(request)
 84:       env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
 85:       env["QUERY_STRING"] ||= ""
 86:       env["SCRIPT_NAME"] = ""
 87: 
 88:       rack_input = StringIO.new(input_body)
 89:       rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
 90: 
 91:       env.update(
 92:         "rack.version"      => [1,0],
 93:         "rack.input"        => rack_input,
 94:         "rack.errors"       => $stderr,
 95:         "rack.multithread"  => true,
 96:         "rack.multiprocess" => true,
 97:         "rack.run_once"     => false,
 98:         "rack.url_scheme"   => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http"
 99:       )
100:       status, headers, body = app.call(env)
101:       begin
102:         socket.write("HTTP/1.1 #{status} #{status_message(status)}\r\n")
103:         headers.each do |k, vs|
104:           vs.split("\n").each { |v| socket.write("#{k}: #{v}\r\n")}
105:         end
106:         socket.write("\r\n")
107:         body.each { |s| socket.write(s) }
108:       ensure
109:         body.close if body.respond_to? :close
110:       end
111:     end

[Source]

    # File lib/bcat/server.rb, line 78
78:     def status_message(code)
79:       Rack::Utils::HTTP_STATUS_CODES[code]
80:     end

[Validate]