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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
# Donated by Florian Gross
require 'webrick'
require 'cgi'
require 'stringio'
include WEBrick
ABSOLUTE_RAILS_ROOT = File.expand_path(RAILS_ROOT)
class CGI
def stdinput
@stdin || $stdin
end
def stdinput=(input)
@stdin = input
end
def env_table
@env_table || ENV
end
def env_table=(table)
@env_table = table
end
end
class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
REQUEST_MUTEX = Mutex.new
def self.dispatch(options = {})
Socket.do_not_reverse_lookup = true # patch for OS X
server = WEBrick::HTTPServer.new(:Port => options[:port].to_i, :ServerType => options[:server_type], :BindAddress => options[:ip])
server.mount('/', DispatchServlet, options)
trap("INT") { server.shutdown }
require File.join(@server_options[:server_root], "..", "config", "environment") unless defined?(RAILS_ROOT)
require "dispatcher"
server.start
end
def initialize(server, options)
@server_options = options
@file_handler = WEBrick::HTTPServlet::FileHandler.new(server, options[:server_root])
Dir.chdir(ABSOLUTE_RAILS_ROOT)
super
end
def service(req, res)
begin
unless handle_file(req, res)
REQUEST_MUTEX.lock unless RAILS_ENV == 'production'
unless handle_dispatch(req, res)
raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
end
end
ensure
unless RAILS_ENV == 'production'
REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked?
end
end
end
def handle_file(req, res)
begin
req = req.dup
path = req.path.dup
# Add .html if the last path piece has no . in it
path << '.html' if path != '/' && (%r{(^|/)[^./]+$} =~ path)
path.gsub!('+', ' ') # Unescape + since FileHandler doesn't do so.
req.instance_variable_set(:@path_info, path) # Set the modified path...
@file_handler.send(:service, req, res)
return true
rescue HTTPStatus::PartialContent, HTTPStatus::NotModified => err
res.set_error(err)
return true
rescue => err
return false
end
end
def handle_dispatch(req, res, origin = nil)
data = StringIO.new
Dispatcher.dispatch(create_cgi(req, origin), ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, data)
header, body = extract_header_and_body(data)
assign_status(res, header)
res.cookies.concat(header.delete('set-cookie'))
header.each { |key, val| res[key] = val.join(", ") }
res.body = body
return true
rescue => err
p err, err.backtrace
return false
end
private
def create_cgi(req, origin)
cgi = CGI.new
cgi.env_table = create_env_table(req, origin)
cgi.stdinput = req.body || ""
return cgi
end
def create_env_table(req, origin)
env = req.meta_vars.clone
env.delete "SCRIPT_NAME"
env["QUERY_STRING"] = req.request_uri.query
env["REQUEST_URI"] = origin if origin
return env
end
def extract_header_and_body(data)
data.rewind
data = data.read
raw_header, body = *data.split(/^[\xd\xa]+/on, 2)
header = WEBrick::HTTPUtils::parse_header(raw_header)
return header, body
end
def assign_status(res, header)
if /^(\d+)/ =~ header['status'][0]
res.status = $1.to_i
header.delete('status')
end
end
end
|