Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/branches/1-2-stable/actionpack/lib/action_controller/request.rb

Revision 5897, 8.6 kB (checked in by bitsweat, 2 years ago)

Merge [5895], [5896] from trunk. References #6891.

  • Property svn:executable set to *
Line 
1 module ActionController
2   # Subclassing AbstractRequest makes these methods available to the request objects used in production and testing,
3   # CgiRequest and TestRequest
4   class AbstractRequest
5     cattr_accessor :relative_url_root
6
7     # Returns the hash of environment variables for this request,
8     # such as { 'RAILS_ENV' => 'production' }.
9     attr_reader :env
10
11     # Returns both GET and POST parameters in a single hash.
12     def parameters
13       @parameters ||= request_parameters.update(query_parameters).update(path_parameters).with_indifferent_access
14     end
15
16     # Returns the HTTP request method as a lowercase symbol (:get, for example). Note, HEAD is returned as :get
17     # since the two are supposedly to be functionaly equivilent for all purposes except that HEAD won't return a response
18     # body (which Rails also takes care of elsewhere).
19     def method
20       @request_method ||= (!parameters[:_method].blank? && @env['REQUEST_METHOD'] == 'POST') ?
21         parameters[:_method].to_s.downcase.to_sym :
22         @env['REQUEST_METHOD'].downcase.to_sym
23      
24       @request_method == :head ? :get : @request_method
25     end
26
27     # Is this a GET (or HEAD) request?  Equivalent to request.method == :get
28     def get?
29       method == :get
30     end
31
32     # Is this a POST request?  Equivalent to request.method == :post
33     def post?
34       method == :post
35     end
36
37     # Is this a PUT request?  Equivalent to request.method == :put
38     def put?
39       method == :put
40     end
41
42     # Is this a DELETE request?  Equivalent to request.method == :delete
43     def delete?
44       method == :delete
45     end
46
47     # Is this a HEAD request?  HEAD is mapped as :get for request.method, so here we ask the
48     # REQUEST_METHOD header directly. Thus, for head, both get? and head? will return true.
49     def head?
50       @env['REQUEST_METHOD'].downcase.to_sym == :head
51     end
52
53     # Determine whether the body of a HTTP call is URL-encoded (default)
54     # or matches one of the registered param_parsers.
55     #
56     # For backward compatibility, the post format is extracted from the
57     # X-Post-Data-Format HTTP header if present.
58     def content_type
59       @content_type ||=
60         begin
61           content_type = @env['CONTENT_TYPE'].to_s.downcase
62          
63           if x_post_format = @env['HTTP_X_POST_DATA_FORMAT']
64             case x_post_format.to_s.downcase
65             when 'yaml'
66               content_type = 'application/x-yaml'
67             when 'xml'
68               content_type = 'application/xml'
69             end
70           end
71          
72           Mime::Type.lookup(content_type)
73         end
74     end
75
76     # Returns the accepted MIME type for the request
77     def accepts
78       @accepts ||=
79         if @env['HTTP_ACCEPT'].to_s.strip.empty?
80           [ content_type, Mime::ALL ]
81         else
82           Mime::Type.parse(@env['HTTP_ACCEPT'])
83         end
84     end
85
86     # Returns true if the request's "X-Requested-With" header contains
87     # "XMLHttpRequest". (The Prototype Javascript library sends this header with
88     # every Ajax request.)
89     def xml_http_request?
90       not /XMLHttpRequest/i.match(@env['HTTP_X_REQUESTED_WITH']).nil?
91     end
92     alias xhr? :xml_http_request?
93
94     # Determine originating IP address.  REMOTE_ADDR is the standard
95     # but will fail if the user is behind a proxy.  HTTP_CLIENT_IP and/or
96     # HTTP_X_FORWARDED_FOR are set by proxies so check for these before
97     # falling back to REMOTE_ADDR.  HTTP_X_FORWARDED_FOR may be a comma-
98     # delimited list in the case of multiple chained proxies; the first is
99     # the originating IP.
100     def remote_ip
101       return @env['HTTP_CLIENT_IP'] if @env.include? 'HTTP_CLIENT_IP'
102
103       if @env.include? 'HTTP_X_FORWARDED_FOR' then
104         remote_ips = @env['HTTP_X_FORWARDED_FOR'].split(',').reject do |ip|
105             ip =~ /^unknown$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
106         end
107
108         return remote_ips.first.strip unless remote_ips.empty?
109       end
110
111       @env['REMOTE_ADDR']
112     end
113
114     # Returns the domain part of a host, such as rubyonrails.org in "www.rubyonrails.org". You can specify
115     # a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
116     def domain(tld_length = 1)
117       return nil if !/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/.match(host).nil? or host.nil?
118
119       host.split('.').last(1 + tld_length).join('.')
120     end
121
122     # Returns all the subdomains as an array, so ["dev", "www"] would be returned for "dev.www.rubyonrails.org".
123     # You can specify a different <tt>tld_length</tt>, such as 2 to catch ["www"] instead of ["www", "rubyonrails"]
124     # in "www.rubyonrails.co.uk".
125     def subdomains(tld_length = 1)
126       return [] unless host
127       parts = host.split('.')
128       parts[0..-(tld_length+2)]
129     end
130
131     # Receive the raw post data.
132     # This is useful for services such as REST, XMLRPC and SOAP
133     # which communicate over HTTP POST but don't use the traditional parameter format.
134     def raw_post
135       @env['RAW_POST_DATA']
136     end
137
138     # Return the request URI, accounting for server idiosyncracies.
139     # WEBrick includes the full URL. IIS leaves REQUEST_URI blank.
140     def request_uri
141       if uri = @env['REQUEST_URI']
142         # Remove domain, which webrick puts into the request_uri.
143         (%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri
144       else
145         # Construct IIS missing REQUEST_URI from SCRIPT_NAME and PATH_INFO.
146         script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
147         uri = @env['PATH_INFO']
148         uri = uri.sub(/#{script_filename}\//, '') unless script_filename.nil?
149         unless (env_qs = @env['QUERY_STRING']).nil? || env_qs.empty?
150           uri << '?' << env_qs
151         end
152         @env['REQUEST_URI'] = uri
153       end
154     end
155
156     # Return 'https://' if this is an SSL request and 'http://' otherwise.
157     def protocol
158       ssl? ? 'https://' : 'http://'
159     end
160
161     # Is this an SSL request?
162     def ssl?
163       @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
164     end
165
166     # Returns the interpreted path to requested resource after all the installation directory of this application was taken into account
167     def path
168       path = (uri = request_uri) ? uri.split('?').first : ''
169
170       # Cut off the path to the installation directory if given
171       path.sub!(%r/^#{relative_url_root}/, '')
172       path || ''     
173     end
174    
175     # Returns the path minus the web server relative installation directory.
176     # This can be set with the environment variable RAILS_RELATIVE_URL_ROOT.
177     # It can be automatically extracted for Apache setups. If the server is not
178     # Apache, this method returns an empty string.
179     def relative_url_root
180       @@relative_url_root ||= case
181         when @env["RAILS_RELATIVE_URL_ROOT"]
182           @env["RAILS_RELATIVE_URL_ROOT"]
183         when server_software == 'apache'
184           @env["SCRIPT_NAME"].to_s.sub(/\/dispatch\.(fcgi|rb|cgi)$/, '')
185         else
186           ''
187       end
188     end
189
190     # Returns the port number of this request as an integer.
191     def port
192       @port_as_int ||= @env['SERVER_PORT'].to_i
193     end
194
195     # Returns the standard port number for this request's protocol
196     def standard_port
197       case protocol
198         when 'https://' then 443
199         else 80
200       end
201     end
202
203     # Returns a port suffix like ":8080" if the port number of this request
204     # is not the default HTTP port 80 or HTTPS port 443.
205     def port_string
206       (port == standard_port) ? '' : ":#{port}"
207     end
208
209     # Returns a host:port string for this request, such as example.com or
210     # example.com:8080.
211     def host_with_port
212       host + port_string
213     end
214
215     def path_parameters=(parameters) #:nodoc:
216       @path_parameters = parameters
217       @symbolized_path_parameters = @parameters = nil
218     end
219
220     # The same as <tt>path_parameters</tt> with explicitly symbolized keys
221     def symbolized_path_parameters
222       @symbolized_path_parameters ||= path_parameters.symbolize_keys
223     end
224
225     # Returns a hash with the parameters used to form the path of the request
226     #
227     # Example:
228     #
229     #   {:action => 'my_action', :controller => 'my_controller'}
230     def path_parameters
231       @path_parameters ||= {}
232     end
233
234     # Returns the lowercase name of the HTTP server software.
235     def server_software
236       (@env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ @env['SERVER_SOFTWARE']) ? $1.downcase : nil
237     end
238
239     #--
240     # Must be implemented in the concrete request
241     #++
242     def query_parameters #:nodoc:
243     end
244
245     def request_parameters #:nodoc:
246     end
247
248     # Returns the host for this request, such as example.com.
249     def host
250     end
251
252     def cookies #:nodoc:
253     end
254
255     def session #:nodoc:
256     end
257
258     def session=(session) #:nodoc:
259       @session = session
260     end
261
262     def reset_session #:nodoc:
263     end
264   end
265 end
Note: See TracBrowser for help on using the browser.