File: webserver.rb

package info (click to toggle)
ruby-ftw 0.0.49-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 548 kB
  • sloc: ruby: 1,922; makefile: 5
file content (107 lines) | stat: -rw-r--r-- 2,791 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
require "ftw"
require "ftw/protocol"
require "ftw/crlf"
require "socket"
require "cabin"

# An attempt to invent a simple FTW web server.
class FTW::WebServer
  include FTW::Protocol
  include FTW::CRLF

  def initialize(host, port, &block)
    @host = host
    @port = port
    @handler = block

    @logger = Cabin::Channel.get
    @threads = []
  end # def initialize

  # Run the server.
  #
  # Connections are farmed out to threads.
  def run
    logger.info("Starting server", :config => @config)
    @server = FTW::Server.new([@host, @port].join(":"))
    @server.each_connection do |connection|
      @threads << Thread.new do
        handle_connection(connection)
      end
    end
  end # def run

  def stop
    @server.stop unless @server.nil?
    @threads.each(&:join)
  end # def stop

  # Handle a new connection.
  #
  # This method parses http requests and passes them on to #handle_request
  #
  # @param connection The FTW::Connection being handled.
  def handle_connection(connection)
    while true
      begin
        request = read_http_message(connection)
      rescue EOFError, Errno::EPIPE, Errno::ECONNRESET, HTTP::Parser::Error, IOError
        # Connection EOF'd or errored before we finished reading a full HTTP
        # message, shut it down.
        break
      rescue FTW::HTTP::Message::UnsupportedHTTPVersion
        break
      end

      if request["Content-Length"] || request["Transfer-Encoding"]
        request.body = connection
      end

      begin
        handle_request(request, connection)
      rescue => e
        puts e.inspect
        puts e.backtrace
        raise e
      end
    end
    connection.disconnect("Fun")
  end # def handle_connection

  # Handle a request. This will set up the rack 'env' and invoke the
  # application associated with this handler.
  def handle_request(request, connection)
    response = FTW::Response.new
    response.version = request.version
    response["Connection"] = request.headers["Connection"] || "close"

    # Process this request with the handler
    @handler.call(request, response, connection)

    # Write the response
    begin
      connection.write(response.to_s + CRLF)
      if response.body?
        write_http_body(response.body, connection,
                        response["Transfer-Encoding"] == "chunked") 
      end
    rescue => e
      @logger.error(e)
      connection.disconnect(e.inspect)
    end

    if response["Connection"] == "close" or response["Connection"].nil?
      connection.disconnect("'Connection' header was close or nil")
    end
  end # def handle_request

  # Get the logger.
  def logger
    if @logger.nil?
      @logger = Cabin::Channel.get
    end
    return @logger
  end # def logger

  public(:run, :initialize, :stop)
end # class FTW::WebServer