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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
|
module ActionController
# These methods are available in both the production and test Request objects.
class AbstractRequest
cattr_accessor :relative_url_root
# Returns both GET and POST parameters in a single hash.
def parameters
@parameters ||= request_parameters.merge(query_parameters).merge(path_parameters).with_indifferent_access
end
# Returns the HTTP request method as a lowercase symbol (:get, for example)
def method
env['REQUEST_METHOD'].downcase.to_sym
end
# Is this a GET request? Equivalent to request.method == :get
def get?
method == :get
end
# Is this a POST request? Equivalent to request.method == :post
def post?
method == :post
end
# Is this a PUT request? Equivalent to request.method == :put
def put?
method == :put
end
# Is this a DELETE request? Equivalent to request.method == :delete
def delete?
method == :delete
end
# Is this a HEAD request? Equivalent to request.method == :head
def head?
method == :head
end
# Determine whether the body of a POST request is URL-encoded (default),
# XML, or YAML by checking the Content-Type HTTP header:
#
# Content-Type Post Format
# application/xml :xml
# text/xml :xml
# application/x-yaml :yaml
# text/x-yaml :yaml
# * :url_encoded
#
# For backward compatibility, the post format is extracted from the
# X-Post-Data-Format HTTP header if present.
def post_format
@post_format ||=
if env['HTTP_X_POST_DATA_FORMAT']
env['HTTP_X_POST_DATA_FORMAT'].downcase.to_sym
else
case env['CONTENT_TYPE'].to_s.downcase
when 'application/xml', 'text/xml' then :xml
when 'application/x-yaml', 'text/x-yaml' then :yaml
else :url_encoded
end
end
end
# Is this a POST request formatted as XML or YAML?
def formatted_post?
post? && (post_format == :xml || post_format == :yaml)
end
# Is this a POST request formatted as XML?
def xml_post?
post? && post_format == :xml
end
# Is this a POST request formatted as YAML?
def yaml_post?
post? && post_format == :yaml
end
# Returns true if the request's "X-Requested-With" header contains
# "XMLHttpRequest". (The Prototype Javascript library sends this header with
# every Ajax request.)
def xml_http_request?
not /XMLHttpRequest/i.match(env['HTTP_X_REQUESTED_WITH']).nil?
end
alias xhr? :xml_http_request?
# Determine originating IP address. REMOTE_ADDR is the standard
# but will fail if the user is behind a proxy. HTTP_CLIENT_IP and/or
# HTTP_X_FORWARDED_FOR are set by proxies so check for these before
# falling back to REMOTE_ADDR. HTTP_X_FORWARDED_FOR may be a comma-
# delimited list in the case of multiple chained proxies; the first is
# the originating IP.
def remote_ip
return env['HTTP_CLIENT_IP'] if env.include? 'HTTP_CLIENT_IP'
if env.include? 'HTTP_X_FORWARDED_FOR' then
remote_ips = env['HTTP_X_FORWARDED_FOR'].split(',').reject do |ip|
ip =~ /^unknown$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
end
return remote_ips.first.strip unless remote_ips.empty?
end
env['REMOTE_ADDR']
end
# Returns the domain part of a host, such as rubyonrails.org in "www.rubyonrails.org". You can specify
# a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
def domain(tld_length = 1)
return nil if !/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/.match(host).nil? or host.nil?
host.split('.').last(1 + tld_length).join('.')
end
# Returns all the subdomains as an array, so ["dev", "www"] would be returned for "dev.www.rubyonrails.org".
# You can specify a different <tt>tld_length</tt>, such as 2 to catch ["www"] instead of ["www", "rubyonrails"]
# in "www.rubyonrails.co.uk".
def subdomains(tld_length = 1)
return [] unless host
parts = host.split('.')
parts[0..-(tld_length+2)]
end
# Receive the raw post data.
# This is useful for services such as REST, XMLRPC and SOAP
# which communicate over HTTP POST but don't use the traditional parameter format.
def raw_post
env['RAW_POST_DATA']
end
# Returns the request URI correctly, taking into account the idiosyncracies
# of the various servers.
def request_uri
if uri = env['REQUEST_URI']
(%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri # Remove domain, which webrick puts into the request_uri.
else # REQUEST_URI is blank under IIS - get this from PATH_INFO and SCRIPT_NAME
script_filename = env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
uri = env['PATH_INFO']
uri = uri.sub(/#{script_filename}\//, '') unless script_filename.nil?
unless (env_qs = env['QUERY_STRING']).nil? || env_qs.empty?
uri << '?' << env_qs
end
uri
end
end
# Return 'https://' if this is an SSL request and 'http://' otherwise.
def protocol
ssl? ? 'https://' : 'http://'
end
# Is this an SSL request?
def ssl?
env['HTTPS'] == 'on'
end
# Returns the interpreted path to requested resource after all the installation directory of this application was taken into account
def path
path = (uri = request_uri) ? uri.split('?').first : ''
# Cut off the path to the installation directory if given
root = relative_url_root
path[0, root.length] = '' if root
path || ''
end
# Returns the path minus the web server relative installation directory.
# This method returns nil unless the web server is apache.
def relative_url_root
@@relative_url_root ||= server_software == 'apache' ? File.dirname(env["SCRIPT_NAME"].to_s).gsub(/(^\.$|^\/$)/, '') : ''
end
# Returns the port number of this request as an integer.
def port
@port_as_int ||= env['SERVER_PORT'].to_i
end
# Returns the standard port number for this request's protocol
def standard_port
case protocol
when 'https://' then 443
else 80
end
end
# Returns a port suffix like ":8080" if the port number of this request
# is not the default HTTP port 80 or HTTPS port 443.
def port_string
(port == standard_port) ? '' : ":#{port}"
end
# Returns a host:port string for this request, such as example.com or
# example.com:8080.
def host_with_port
host + port_string
end
def path_parameters=(parameters)
@path_parameters = parameters
@symbolized_path_parameters = @parameters = nil
end
def symbolized_path_parameters
@symbolized_path_parameters ||= path_parameters.symbolize_keys
end
def path_parameters
@path_parameters ||= {}
end
# Returns the lowercase name of the HTTP server software.
def server_software
(env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ env['SERVER_SOFTWARE']) ? $1.downcase : nil
end
#--
# Must be implemented in the concrete request
#++
def query_parameters #:nodoc:
end
def request_parameters #:nodoc:
end
def env #:nodoc:
end
def host #:nodoc:
end
def cookies #:nodoc:
end
def session #:nodoc:
end
def reset_session #:nodoc:
end
end
end
|