Class: FTW::WebServer

Inherits:
Object
  • Object
show all
Includes:
CRLF, Protocol
Defined in:
lib/ftw/webserver.rb

Overview

An attempt to invent a simple FTW web server.

Constant Summary

Constants included from CRLF

CRLF::CRLF

Instance Method Summary collapse

Methods included from Protocol

#discard_body, #encode_chunked, #read_body, #read_http_body, #read_http_body_chunked, #read_http_body_length, #read_http_message, #write_all, #write_http_body, #write_http_body_chunked, #write_http_body_normal

Constructor Details

#initialize(host, port, &block) ⇒ WebServer



12
13
14
15
16
17
18
19
# File 'lib/ftw/webserver.rb', line 12

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

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

Instance Method Details

#handle_connection(connection) ⇒ Object

Handle a new connection.

This method parses http requests and passes them on to #handle_request



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/ftw/webserver.rb', line 44

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
    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

#handle_request(request, connection) ⇒ Object

Handle a request. This will set up the rack ‘env’ and invoke the application associated with this handler.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/ftw/webserver.rb', line 71

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

#loggerObject

Get the logger.



97
98
99
100
101
102
# File 'lib/ftw/webserver.rb', line 97

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

#runObject

Run the server.

Connections are farmed out to threads.



24
25
26
27
28
29
30
31
32
# File 'lib/ftw/webserver.rb', line 24

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

#stopObject

def run



34
35
36
37
# File 'lib/ftw/webserver.rb', line 34

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