Class: Merb::Request
Constants
| Name | Value |
| METHODS |
%w{get post put delete head} |
| NAME_REGEX |
/Content-Disposition:.* name="?([^\";]*)"?/ni.freeze |
| CONTENT_TYPE_REGEX |
/Content-Type: (.*)\r\n/ni.freeze |
| FILENAME_REGEX |
/Content-Disposition:.* filename="?([^\";]*)"?/ni.freeze |
| CRLF |
"\r\n".freeze |
| EOL |
CRLF |
Attributes
| Name | Read/write? |
| env |
RW |
| route_params |
RW |
| session |
RW |
Public Class Methods
Parameters
returns
Show source...
407: def escape(s)
408: s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
409: '%'+$1.unpack('H2'*$1.size).join('%').upcase
410: }.tr(' ', '+')
411: end
Initial the request object.
Parameters
| http_request<~params:~[], ~body:IO>: | An object like an HTTP Request.
|
Show source...
18: def initialize(rack_env)
19: @env = rack_env
20: @body = rack_env['rack.input']
21: @route_params = {}
22: end
Converts a query string snippet to a hash and adds it to existing
parameters.
Parameters
| parms<Hash>: | Parameters to add the normalized parameters to.
|
| name<String>: | The key of the parameter to normalize.
|
| val<String>: | The value of the parameter.
|
Returns
| Hash: | Normalized parameters
|
Show source...
543: def normalize_params(parms, name, val=nil)
544: name =~ %r([\[\]]*([^\[\]]+)\]*)
545: key = $1 || ''
546: after = $' || ''
547:
548: if after == ""
549: parms[key] = val
550: elsif after == "[]"
551: (parms[key] ||= []) << val
552: else
553: parms[key] ||= {}
554: parms[key] = normalize_params(parms[key], after, val)
555: end
556: parms
557: end
Parameters
| value<Array, Hash, ~to_s>: | The value for the query string.
|
| prefix<~to_s>: | The prefix to add to the query string keys.
|
Returns
Alternatives
If the value is a string, the prefix will be used as the key.
Examples
params_to_query_string(10, "page")
# => "page=10"
params_to_query_string({ :page => 10, :word => "ruby" })
# => "page=10&word=ruby"
params_to_query_string({ :page => 10, :word => "ruby" }, "search")
# => "search[page]=10&search[word]=ruby"
params_to_query_string([ "ice-cream", "cake" ], "shopping_list")
# => "shopping_list[]=ice-cream&shopping_list[]=cake"
Show source...
387: def params_to_query_string(value, prefix = nil)
388: case value
389: when Array
390: value.map { |v|
391: params_to_query_string(v, "#{prefix}[]")
392: } * "&"
393: when Hash
394: value.map { |k, v|
395: params_to_query_string(v, prefix ? "#{prefix}[#{Merb::Request.escape(k)}]" : Merb::Request.escape(k))
396: } * "&"
397: else
398: "#{prefix}=#{Merb::Request.escape(value)}"
399: end
400: end
Parameters
| request<IO>: | The raw request.
|
| boundary<String>: | The boundary string.
|
| content_length<Fixnum>: | The length of the content.
|
Raises
| ControllerExceptions::MultiPartParseError: | Failed to parse request.
|
Returns
Show source...
457: def parse_multipart(request, boundary, content_length)
458: boundary = "--#{boundary}"
459: paramhsh = {}
460: buf = ""
461: input = request
462: input.binmode if defined? input.binmode
463: boundary_size = boundary.size + EOL.size
464: bufsize = 16384
465: content_length -= boundary_size
466: status = input.read(boundary_size)
467: raise ControllerExceptions::MultiPartParseError, "bad content body:\n'#{status}' should == '#{boundary + EOL}'" unless status == boundary + EOL
468: rx = /(?:#{EOL})?#{Regexp.quote(boundary,'n')}(#{EOL}|--)/
469: loop {
470: head = nil
471: body = ''
472: filename = content_type = name = nil
473: read_size = 0
474: until head && buf =~ rx
475: i = buf.index("\r\n\r\n")
476: if( i == nil && read_size == 0 && content_length == 0 )
477: content_length = -1
478: break
479: end
480: if !head && i
481: head = buf.slice!(0, i+2)
482: buf.slice!(0, 2)
483: filename = head[FILENAME_REGEX, 1]
484: content_type = head[CONTENT_TYPE_REGEX, 1]
485: name = head[NAME_REGEX, 1]
486:
487: if filename && !filename.empty?
488: body = Tempfile.new(:Merb)
489: body.binmode if defined? body.binmode
490: end
491: next
492: end
493:
494:
495: if head && (boundary_size+4 < buf.size)
496: body << buf.slice!(0, buf.size - (boundary_size+4))
497: end
498:
499: read_size = bufsize < content_length ? bufsize : content_length
500: if( read_size > 0 )
501: c = input.read(read_size)
502: raise ControllerExceptions::MultiPartParseError, "bad content body" if c.nil? || c.empty?
503: buf << c
504: content_length -= c.size
505: end
506: end
507:
508:
509: if i = buf.index(rx)
510: body << buf.slice!(0, i)
511: buf.slice!(0, boundary_size+2)
512:
513: content_length = -1 if $1 == "--"
514: end
515:
516: if filename && !filename.empty?
517: body.rewind
518: data = {
519: :filename => File.basename(filename),
520: :content_type => content_type,
521: :tempfile => body,
522: :size => File.size(body.path)
523: }
524: else
525: data = body
526: end
527: paramhsh = normalize_params(paramhsh,name,data)
528: break if buf.empty? || content_length == -1
529: }
530: paramhsh
531: end
Parameters
| qs<String>: | The query string.
|
| d<String>: | The query string divider. Defaults to "&".
|
Returns
| Mash: | The parsed query string.
|
Examples
query_parse("bar=nik&post[body]=heya")
# => { :bar => "nik", :post => { :body => "heya" } }
Show source...
434: def query_parse(qs, d = '&;')
435: (qs||'').split(/[#{d}] */n).inject({}) { |h,p|
436: key, value = unescape(p).split('=',2)
437: normalize_params(h, key, value)
438: }.to_mash
439: end
Parameter
returns
Show source...
418: def unescape(s)
419: s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
420: [$1.delete('%')].pack('H*')
421: }
422: end
Public Instance Methods
Returns
| String: | The accepted response types. Defaults to "*/*".
|
Show source...
287: def accept
288: @env['HTTP_ACCEPT'].blank? ? "*/*" : @env['HTTP_ACCEPT']
289: end
Returns
| String: | The accepted character sets.
|
Show source...
269: def accept_charset
270: @env['HTTP_ACCEPT_CHARSET']
271: end
Returns
| String: | The accepted encodings.
|
Show source...
233: def accept_encoding
234: @env['HTTP_ACCEPT_ENCODING']
235: end
Returns
Show source...
251: def accept_language
252: @env['HTTP_ACCEPT_LANGUAGE']
253: end
Alias for xml_http_request?
Returns
Show source...
245: def cache_control
246: @env['HTTP_CACHE_CONTROL']
247: end
Returns
Show source...
293: def connection
294: @env['HTTP_CONNECTION']
295: end
Returns
| Fixnum: | The request content length.
|
Show source...
311: def content_length
312: @content_length ||= @env[Merb::Const::CONTENT_LENGTH].to_i
313: end
Returns
| String: | The request content type.
|
Show source...
305: def content_type
306: @env['CONTENT_TYPE']
307: end
Returns
Show source...
158: def cookies
159: @cookies ||= self.class.query_parse(@env[Merb::Const::HTTP_COOKIE], ';,')
160: end
Parameters
| tld_length<Fixnum>: | Number of domains levels to inlclude in the top level domain. Defaults to 1.
|
Returns
Show source...
362: def domain(tld_length = 1)
363: host.split('.').last(1 + tld_length).join('.').sub(/:\d+$/,'')
364: end
Returns
Show source...
281: def gateway
282: @env['GATEWAY_INTERFACE']
283: end
Returns
Show source...
339: def host
340: @env['HTTP_X_FORWARDED_HOST'] || @env['HTTP_HOST']
341: end
Returns
| String: | Value of HTTP_KEEP_ALIVE.
|
Show source...
263: def keep_alive
264: @env['HTTP_KEEP_ALIVE']
265: end
Returns
| Symbol: | The name of the request method, e.g.
:get.
|
Notes
If the method is post, then the
_method param will be checked for masquerading method.
Show source...
32: def method
33: @method ||= begin
34: request_method = @env['REQUEST_METHOD'].downcase.to_sym
35: case request_method
36: when :get, :head, :put, :delete
37: request_method
38: when :post
39: if self.class.parse_multipart_params
40: m = body_and_query_params.merge(multipart_params)['_method']
41: else
42: m = body_and_query_params['_method']
43: end
44: m.downcase! if m
45: METHODS.include?(m) ? m.to_sym : :post
46: else
47: raise "Unknown REQUEST_METHOD: #{@env['REQUEST_METHOD']}"
48: end
49: end
50: end
Returns
| Hash: | All request parameters.
|
Notes
The order of precedence for the params
is XML, JSON, multipart, body and request string.
Show source...
141: def params
142: @params ||= begin
143: h = body_and_query_params.merge(route_params)
144: h.merge!(multipart_params) if self.class.parse_multipart_params && multipart_params
145: h.merge!(json_params) if self.class.parse_json_params && json_params
146: h.merge!(xml_params) if self.class.parse_xml_params && xml_params
147: h
148: end
149: end
Returns
| String: | The URI without the query string. Strips trailing "/" and reduces
duplicate "/" to a single "/".
|
Show source...
319: def path
320: path = (uri.empty? ? '/' : uri.split('?').first).squeeze("/")
321: path = path[0..-2] if (path[-1] == ?/) && path.size > 1
322: path
323: end
Returns
Show source...
327: def path_info
328: @path_info ||= self.class.unescape(@env['PATH_INFO'])
329: end
Returns
Show source...
333: def port
334: @env['SERVER_PORT'].to_i
335: end
Returns
| String: | The protocol, i.e. either
"https://" or "http://" depending on the HTTPS header.
|
Show source...
197: def protocol
198: ssl? ? 'https://' : 'http://'
199: end
Returns
Show source...
299: def query_string
300: @env['QUERY_STRING']
301: end
Returns
Show source...
164: def raw_post
165: @body.rewind if @body.respond_to?(:rewind)
166: @raw_post ||= @body.read
167: end
Returns
Show source...
209: def referer
210: @env['HTTP_REFERER']
211: end
Returns
Show source...
179: def remote_ip
180: return @env['HTTP_CLIENT_IP'] if @env.include?('HTTP_CLIENT_IP')
181:
182: if @env.include?(Merb::Const::HTTP_X_FORWARDED_FOR) then
183: remote_ips = @env[Merb::Const::HTTP_X_FORWARDED_FOR].split(',').reject do |ip|
184: ip =~ /^unknown$|^(127|10|172\.16|192\.168)\./i
185: end
186:
187: return remote_ips.first.strip unless remote_ips.empty?
188: end
189:
190: return @env[Merb::Const::REMOTE_ADDR]
191: end
Returns
Show source...
239: def script_name
240: @env['SCRIPT_NAME']
241: end
Returns
Show source...
227: def server_name
228: @env['SERVER_NAME']
229: end
Returns
Show source...
257: def server_software
258: @env['SERVER_SOFTWARE']
259: end
Returns
| Boolean:: | True if the request is an SSL request.
|
Show source...
203: def ssl?
204: @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
205: end
Parameters
| tld_length<Fixnum>: | Number of domains levels to inlclude in the top level domain. Defaults to 1.
|
Returns
| Array: | All the subdomain parts of the host.
|
Show source...
350: def subdomains(tld_length = 1)
351: parts = host.split('.')
352: parts[0..-(tld_length+2)]
353: end
Returns
Show source...
215: def uri
216: @env['REQUEST_URI'] || @env['REQUEST_PATH']
217: end
Returns
Show source...
221: def user_agent
222: @env['HTTP_USER_AGENT']
223: end
Returns
Show source...
275: def version
276: @env['HTTP_VERSION']
277: end
Alias for xml_http_request?
Returns
| Boolean: | If the request is an XML HTTP request.
|
Show source...
171: def xml_http_request?
172: not /XMLHttpRequest/i.match(@env['HTTP_X_REQUESTED_WITH']).nil?
173: end