Class: Yarn::AbstractHandler

Inherits:
Object
  • Object
show all
Includes:
ErrorPage, Logging
Defined in:
lib/yarn/abstract_handler.rb

Direct Known Subclasses

RackHandler, RequestHandler

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ErrorPage

#serve_404_page, #serve_500_page

Methods included from Logging

#debug, #log, #output, #timestamp

Constructor Details

#initializeAbstractHandler

Returns a new instance of AbstractHandler.



17
18
19
20
# File 'lib/yarn/abstract_handler.rb', line 17

def initialize
  @parser = Parser.new
  @response = Response.new
end

Instance Attribute Details

#parserObject

Returns the value of attribute parser.



15
16
17
# File 'lib/yarn/abstract_handler.rb', line 15

def parser
  @parser
end

#requestObject

Returns the value of attribute request.



15
16
17
# File 'lib/yarn/abstract_handler.rb', line 15

def request
  @request
end

#responseObject

Returns the value of attribute response.



15
16
17
# File 'lib/yarn/abstract_handler.rb', line 15

def response
  @response
end

#sessionObject

Returns the value of attribute session.



15
16
17
# File 'lib/yarn/abstract_handler.rb', line 15

def session
  @session
end

Instance Method Details

#client_addressObject



112
113
114
# File 'lib/yarn/abstract_handler.rb', line 112

def client_address
  @session.peeraddr(:numeric)[2] if @session
end

#extract_pathObject



96
97
98
99
100
101
102
# File 'lib/yarn/abstract_handler.rb', line 96

def extract_path
  path = @request[:uri][:path].to_s
  if path[0] == "/" && path != "/"
    path = path[1..-1] 
  end
  path.gsub(/%20/, " ").strip
end

#parse_requestObject

Raises:



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/yarn/abstract_handler.rb', line 40

def parse_request
  raw_request = read_request
  raise EmptyRequestError if raw_request.empty?

  begin
    @request = @parser.run raw_request
  rescue Parslet::ParseFailed => e
    @response.status = 400
    debug "Parse failed: #{@request}"
  end
end

#persistent?Boolean

Returns:

  • (Boolean)


82
83
84
# File 'lib/yarn/abstract_handler.rb', line 82

def persistent?
  return @request[:headers]["Connection"] == "keep-alive"
end

#post_bodyObject



104
105
106
# File 'lib/yarn/abstract_handler.rb', line 104

def post_body
  @request ? @request[:body].to_s : ""
end

#prepare_responseObject



52
53
# File 'lib/yarn/abstract_handler.rb', line 52

def prepare_response
end

#read_requestObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/yarn/abstract_handler.rb', line 65

def read_request
  input = []
  while (line = @session.gets) do
    length = line.gsub(/\D/,"") if line =~ /Content-Length/
      if line == "\r\n"
        input << line
        input << @session.read(length.to_i) if length
        break
      else
        input << line
      end
  end

  debug "Done reading request"
  input.join
end

#request_pathObject



108
109
110
# File 'lib/yarn/abstract_handler.rb', line 108

def request_path
  @request[:uri][:path] if @request
end

#return_responseObject



55
56
57
58
59
60
61
62
63
# File 'lib/yarn/abstract_handler.rb', line 55

def return_response
  @session.puts "HTTP/1.1 #{@response.status} #{STATUS_CODES[@response.status]}"
  @session.puts @response.headers.map { |k,v| "#{k}: #{v}" }
  @session.puts ""

  @response.body.each do |line|
    @session.puts line
  end
end

#run(session) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/yarn/abstract_handler.rb', line 22

def run(session)
  set_common_headers
  @session = session
  begin
    parse_request
    debug "Request parsed, path: #{request_path}"
    prepare_response
    debug "Response prepared: #{@response.status}"
    return_response
    log "#{STATUS_CODES[@response.status]} #{client_address} #{request_path}"
  rescue EmptyRequestError
    log "Empty request from #{client_address}"
  ensure
    @session.close
    debug "Connection closed"
  end
end

#set_common_headersObject



86
87
88
89
90
91
92
93
94
# File 'lib/yarn/abstract_handler.rb', line 86

def set_common_headers
  @response.headers[:Server] = "Yarn webserver v#{VERSION}"

  # HTTP date format: Fri, 31 Dec 1999 23:59:59 GMT
  time ||= DateTime.now.new_offset(0)
  @response.headers[:Date] = time.strftime("%a, %d %b %Y %H:%M:%S GMT")
  # Close connection header ( until support for persistent connections )
  @response.headers[:Connection] = "Close"
end