root/trunk/vendor/rails/railties/lib/webrick_server.rb @ 58

Revision 58, 4.6 KB (checked in by dema, 7 years ago)

Updating to Rails 1.1.2

Line 
1# Donated by Florian Gross
2
3require 'webrick'
4require 'cgi'
5require 'stringio'
6
7include WEBrick
8
9ABSOLUTE_RAILS_ROOT = File.expand_path(RAILS_ROOT)
10
11class CGI #:nodoc:
12  def stdinput
13    @stdin || $stdin
14  end
15 
16  def env_table
17    @env_table || ENV
18  end
19 
20  def initialize(type = "query", table = nil, stdin = nil)
21    @env_table, @stdin = table, stdin
22
23    if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE")
24      Apache.request.setup_cgi_env
25    end
26
27    extend QueryExtension
28    @multipart = false
29    if defined?(CGI_PARAMS)
30      warn "do not use CGI_PARAMS and CGI_COOKIES"
31      @params = CGI_PARAMS.dup
32      @cookies = CGI_COOKIES.dup
33    else
34      initialize_query()  # set @params, @cookies
35    end
36    @output_cookies = nil
37    @output_hidden = nil
38  end
39end
40
41# A custom dispatch servlet for use with WEBrick. It dispatches requests
42# (using the Rails Dispatcher) to the appropriate controller/action. By default,
43# it restricts WEBrick to a managing a single Rails request at a time, but you
44# can change this behavior by setting ActionController::Base.allow_concurrency
45# to true.
46class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
47  REQUEST_MUTEX = Mutex.new
48
49  # Start the WEBrick server with the given options, mounting the
50  # DispatchServlet at <tt>/</tt>.
51  def self.dispatch(options = {})
52    Socket.do_not_reverse_lookup = true # patch for OS X
53
54    params = { :Port        => options[:port].to_i,
55               :ServerType  => options[:server_type],
56               :BindAddress => options[:ip] }
57    params[:MimeTypes] = options[:mime_types] if options[:mime_types]
58
59    server = WEBrick::HTTPServer.new(params)
60    server.mount('/', DispatchServlet, options)
61
62    trap("INT") { server.shutdown }
63
64    require File.join(@server_options[:server_root], "..", "config", "environment") unless defined?(RAILS_ROOT)
65    require "dispatcher"
66
67    server.start
68  end
69
70  def initialize(server, options) #:nodoc:
71    @server_options = options
72    @file_handler = WEBrick::HTTPServlet::FileHandler.new(server, options[:server_root])
73    Dir.chdir(ABSOLUTE_RAILS_ROOT)
74    super
75  end
76
77  def service(req, res) #:nodoc:
78    unless handle_file(req, res)
79      begin
80        REQUEST_MUTEX.lock unless ActionController::Base.allow_concurrency
81        unless handle_dispatch(req, res)
82          raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
83        end
84      ensure
85        unless ActionController::Base.allow_concurrency
86          REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked?
87        end
88      end
89    end
90  end
91
92  def handle_file(req, res) #:nodoc:
93    begin
94      req = req.dup
95      path = req.path.dup
96
97      # Add .html if the last path piece has no . in it
98      path << '.html' if path != '/' && (%r{(^|/)[^./]+$} =~ path) 
99      path.gsub!('+', ' ') # Unescape + since FileHandler doesn't do so.
100
101      req.instance_variable_set(:@path_info, path) # Set the modified path...
102
103      @file_handler.send(:service, req, res)     
104      return true
105    rescue HTTPStatus::PartialContent, HTTPStatus::NotModified => err
106      res.set_error(err)
107      return true
108    rescue => err
109      return false
110    end
111  end
112
113  def handle_dispatch(req, res, origin = nil) #:nodoc:
114    data = StringIO.new
115    Dispatcher.dispatch(
116      CGI.new("query", create_env_table(req, origin), StringIO.new(req.body || "")), 
117      ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, 
118      data
119    )
120
121    header, body = extract_header_and_body(data)
122
123    set_charset(header)
124    assign_status(res, header)
125    res.cookies.concat(header.delete('set-cookie') || [])
126    header.each { |key, val| res[key] = val.join(", ") }
127   
128    res.body = body
129    return true
130  rescue => err
131    p err, err.backtrace
132    return false
133  end
134 
135  private
136    def create_env_table(req, origin)
137      env = req.meta_vars.clone
138      env.delete "SCRIPT_NAME"
139      env["QUERY_STRING"] = req.request_uri.query
140      env["REQUEST_URI"]  = origin if origin
141      return env
142    end
143   
144    def extract_header_and_body(data)
145      data.rewind
146      data = data.read
147
148      raw_header, body = *data.split(/^[\xd\xa]+/on, 2)
149      header = WEBrick::HTTPUtils::parse_header(raw_header)
150     
151      return header, body
152    end
153   
154    def set_charset(header)
155      ct = header["content-type"]
156      if ct.any? { |x| x =~ /^text\// } && ! ct.any? { |x| x =~ /charset=/ }
157        ch = @server_options[:charset] || "UTF-8"
158        ct.find { |x| x =~ /^text\// } << ("; charset=" + ch)
159      end
160    end
161
162    def assign_status(res, header)
163      if /^(\d+)/ =~ header['status'][0]
164        res.status = $1.to_i
165        header.delete('status')
166      end
167    end
168end
Note: See TracBrowser for help on using the browser.