Class: Reel::Rack::Server

Inherits:
Server::HTTP
  • Object
show all
Includes:
Celluloid::Logger
Defined in:
lib/reel/rack/server.rb

Constant Summary collapse

CONTENT_LENGTH_HEADER =

Compile the regex once

%r{^content-length$}i
NO_PREFIX_HEADERS =

Those headers must not start with ‘HTTP_’.

%w[CONTENT_TYPE CONTENT_LENGTH].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, options) ⇒ Server

Returns a new instance of Server.

Raises:

  • (ArgumentError)


13
14
15
16
17
18
19
20
21
22
# File 'lib/reel/rack/server.rb', line 13

def initialize(app, options)
  raise ArgumentError, "no host given" unless options[:Host]
  raise ArgumentError, "no port given" unless options[:Port]

  info  "A Reel good HTTP server! (Codename \"#{::Reel::CODENAME}\")"
  info "Listening on http://#{options[:Host]}:#{options[:Port]}"

  super(options[:Host], options[:Port], &method(:on_connection))
  @app = app
end

Instance Attribute Details

#appObject (readonly)

Returns the value of attribute app.



11
12
13
# File 'lib/reel/rack/server.rb', line 11

def app
  @app
end

Instance Method Details

#convert_headers(headers) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
# File 'lib/reel/rack/server.rb', line 69

def convert_headers(headers)
  Hash[headers.map { |key, value|
    header = key.upcase.gsub('-','_')

    if NO_PREFIX_HEADERS.member?(header)
      [header, value]
    else
      ['HTTP_' + header, value]
    end
  }]
end

#on_connection(connection) ⇒ Object



24
25
26
27
28
29
30
31
32
# File 'lib/reel/rack/server.rb', line 24

def on_connection(connection)
  connection.each_request do |request|
    if request.websocket?
      request.respond :bad_request, "WebSockets not supported"
    else
      route_request request
    end
  end
end

#route_request(request) ⇒ Object



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
# File 'lib/reel/rack/server.rb', line 37

def route_request(request)
  options = {
    :method       => request.method,
    :input        => request.body.to_s,
    "REMOTE_ADDR" => request.remote_addr
  }.merge(convert_headers(request.headers))
   
  status, headers, body = app.call ::Rack::MockRequest.env_for(request.url, options)

  if body.respond_to? :each
    # If Content-Length was specified we can send the response all at once
    if headers.keys.detect { |h| h =~ CONTENT_LENGTH_HEADER }
      # Can't use collect here because Rack::BodyProxy/Rack::Lint isn't a real Enumerable
      full_body = ''
      body.each { |b| full_body << b }
      request.respond status_symbol(status), headers, full_body
    else
      request.respond status_symbol(status), headers.merge(:transfer_encoding => :chunked)
      body.each { |chunk| request << chunk }
      request.finish_response
    end
  else
    Logger.error("don't know how to render: #{body.inspect}")
    request.respond :internal_server_error, "An error occurred processing your request"
  end

  body.close if body.respond_to? :close
end

#status_symbol(status) ⇒ Object



81
82
83
84
85
86
87
# File 'lib/reel/rack/server.rb', line 81

def status_symbol(status)
  if status.is_a?(Fixnum)
    Http::Response::STATUS_CODES[status].downcase.gsub(/\s|-/, '_').to_sym
  else
    status.to_sym
  end
end