Class: Merb::Request

Inherits:
Object show all
Includes:
ControllerExceptions
Defined in:
lib/merb-core/dispatch/request.rb,
lib/merb-core/dispatch/dispatcher.rb

Direct Known Subclasses

Test::RequestHelper::FakeRequest

Constant Summary collapse

METHODS =
%w{get post put delete head options}
@@mutex =
Mutex.new

Constants included from ControllerExceptions

ControllerExceptions::STATUS_CODES

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rack_env) ⇒ Request

Initialize the request object.

Parameters

http_request<~params:~[], ~body:IO>

An object like an HTTP Request.

:api: private



36
37
38
39
40
# File 'lib/merb-core/dispatch/request.rb', line 36

def initialize(rack_env)      
  @env  = rack_env
  @body = rack_env[Merb::Const::RACK_INPUT]
  @route_params = {}
end

Instance Attribute Details

#envObject

:api: private



8
9
10
# File 'lib/merb-core/dispatch/request.rb', line 8

def env
  @env
end

#routeObject

:api: private



8
9
10
# File 'lib/merb-core/dispatch/request.rb', line 8

def route
  @route
end

#route_paramsObject (readonly)

:api: private



10
11
12
# File 'lib/merb-core/dispatch/request.rb', line 10

def route_params
  @route_params
end

#startObject (readonly)

Returns the value of attribute start.



39
40
41
# File 'lib/merb-core/dispatch/dispatcher.rb', line 39

def start
  @start
end

Class Method Details

.new(env, *args) ⇒ Object

Memoizes the new request object into env so we can memoize things into ivars in the request

Parameters

env<Hash>

A rack environment

*args<Array>

Other arguments passed to the superclass

Returns

Merb::Request

The new Merb::Request

:api: public



53
54
55
56
57
58
59
# File 'lib/merb-core/dispatch/request.rb', line 53

def self.new(env, *args)
  if self == Merb::Request
    env["merb.request"] ||= super
  else
    super
  end
end

Instance Method Details

#_process_block_return(retval) ⇒ Object

Notes

Processes the return value of a deferred router block and returns the current route params for the current request evaluation

:api: private



147
148
149
150
151
152
153
154
# File 'lib/merb-core/dispatch/request.rb', line 147

def _process_block_return(retval)
  # If the return value is an array, then it is a redirect
  # so we must set the request as a redirect and extract
  # the redirect params and return it as a hash so that the
  # dispatcher can handle it
  matched! if retval.is_a?(Array)
  retval
end

#acceptObject

Returns

String

The accepted response types. Defaults to “/”.

:api: private



512
513
514
# File 'lib/merb-core/dispatch/request.rb', line 512

def accept
  @env[Merb::Const::HTTP_ACCEPT].blank? ? "*/*" : @env[Merb::Const::HTTP_ACCEPT]
end

#accept_charsetObject

Returns

String

The accepted character sets.

:api: public



488
489
490
# File 'lib/merb-core/dispatch/request.rb', line 488

def accept_charset
  @env[Merb::Const::HTTP_ACCEPT_CHARSET]
end

#accept_encodingObject

Returns

String

The accepted encodings.

:api: private



440
441
442
# File 'lib/merb-core/dispatch/request.rb', line 440

def accept_encoding
  @env[Merb::Const::HTTP_ACCEPT_ENCODING]
end

#accept_languageObject

Returns

String

The accepted language.

:api: public



464
465
466
# File 'lib/merb-core/dispatch/request.rb', line 464

def accept_language
  @env[Merb::Const::HTTP_ACCEPT_LANGUAGE]
end

#cache_controlObject

Returns

String

HTTP cache control.

:api: public



456
457
458
# File 'lib/merb-core/dispatch/request.rb', line 456

def cache_control
  @env[Merb::Const::HTTP_CACHE_CONTROL]
end

#connectionObject

Returns

String

The HTTP connection.

:api: private



520
521
522
# File 'lib/merb-core/dispatch/request.rb', line 520

def connection
  @env[Merb::Const::HTTP_CONNECTION]
end

#content_lengthObject

Returns

Fixnum

The request content length.

:api: public



544
545
546
# File 'lib/merb-core/dispatch/request.rb', line 544

def content_length
  @content_length ||= @env[Merb::Const::CONTENT_LENGTH].to_i
end

#content_typeObject

Returns

String

The request content type.

:api: private



536
537
538
# File 'lib/merb-core/dispatch/request.rb', line 536

def content_type
  @env[Merb::Const::UPCASE_CONTENT_TYPE]
end

#controllerObject

Returns the controller object for initialization and dispatching the request.

Returns

Class

The controller class matching the routed request,

e.g. Posts.

:api: private



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/merb-core/dispatch/request.rb', line 69

def controller
  unless params[:controller]
    raise ControllerExceptions::NotFound,
      "Route matched, but route did not specify a controller.\n" +
      "Did you forgot to add :controller => \"people\" or :controller " +
      "segment to route definition?\nHere is what's specified:\n" +
      route.inspect
  end
  path = [params[:namespace], params[:controller]].compact.join(Merb::Const::SLASH)
  controller = path.snake_case.to_const_string

  begin
    Object.full_const_get(controller)
  rescue NameError => e
    msg = "Controller class not found for controller `#{path}'"
    Merb.logger.warn!(msg)
    raise ControllerExceptions::NotFound, msg
  end
end

#domain(tld_length = 1) ⇒ Object

Parameters

tld_length<Fixnum>

Number of domains levels to inlclude in the top level domain. Defaults to 1.

Returns

String

The full domain name without the port number.

:api: public



610
611
612
# File 'lib/merb-core/dispatch/request.rb', line 610

def domain(tld_length = 1)
  host.split(Merb::Const::DOT).last(1 + tld_length).join(Merb::Const::DOT).sub(/:\d+$/,'')
end

#exceptionsObject



89
90
91
# File 'lib/merb-core/dispatch/request.rb', line 89

def exceptions
  env["merb.exceptions"]
end

#find_route!Object

Notes

Find route using requested URI and merges route parameters (:action, :controller and named segments) into request params hash.

:api: private



136
137
138
139
# File 'lib/merb-core/dispatch/request.rb', line 136

def find_route!
  @route, @route_params = Merb::Router.route_for(self)
  params.merge! @route_params if @route_params.is_a?(Hash)
end

#full_uriObject

Returns

String

The full URI, including protocol and host

:api: public



408
409
410
# File 'lib/merb-core/dispatch/request.rb', line 408

def full_uri
  protocol + "://" + host + uri
end

#gatewayObject

Returns

String

The gateway.

:api: public



504
505
506
# File 'lib/merb-core/dispatch/request.rb', line 504

def gateway
  @env[Merb::Const::GATEWAY_INTERFACE]
end

#handleArray[Integer, Hash, #each]

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Handles request routing and action dispatch



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
# File 'lib/merb-core/dispatch/dispatcher.rb', line 46

def handle
  @start = env["merb.request_start"] = Time.now
  Merb.logger.info { "Started request handling: #{start.to_s}" }

  find_route!
  return rack_response if handled?

  klass = controller

  unless klass < Controller
    raise NotFound,
      "Controller '#{klass}' not found.\n" \
      "If Merb tries to find a controller for static files, " \
      "you may need to check your Rackup file, see the Problems " \
      "section at: http://wiki.merbivore.com/pages/rack-middleware"
  end

  Merb.logger.debug { "Routed to: #{klass::_filter_params(params).inspect}" }

  if klass.abstract?
    raise NotFound, "The '#{klass}' controller has no public actions"
  end

  dispatch_action(klass, params[:action])
rescue Object => exception
  dispatch_exception(exception)
end

#handled?Boolean

If @route_params is an Array, then it will be the rack response. In this case, the request is considered handled.

Returns

Boolean

true if @route_params is an Array, false otherwise.

:api: private



191
192
193
# File 'lib/merb-core/dispatch/request.rb', line 191

def handled?
  @route_params.is_a?(Array)
end

#hostObject

Returns

String

The full hostname including the port.

:api: public



582
583
584
585
# File 'lib/merb-core/dispatch/request.rb', line 582

def host
  @env[Merb::Const::HTTP_X_FORWARDED_HOST] || @env[Merb::Const::HTTP_HOST] ||
    @env[Merb::Const::SERVER_NAME]
end

#if_modified_sinceObject

Returns

Value of If-Modified-Since request header.

:api: private



626
627
628
629
630
# File 'lib/merb-core/dispatch/request.rb', line 626

def if_modified_since
  if time = @env[Merb::Const::HTTP_IF_MODIFIED_SINCE]
    Time.rfc2822(time)
  end
end

#if_none_matchObject

Returns

Value of If-None-Match request header.

:api: private



618
619
620
# File 'lib/merb-core/dispatch/request.rb', line 618

def if_none_match
  @env[Merb::Const::HTTP_IF_NONE_MATCH]
end

#keep_aliveObject

Returns

String

Value of HTTP_KEEP_ALIVE.

:api: public



480
481
482
# File 'lib/merb-core/dispatch/request.rb', line 480

def keep_alive
  @env[Merb::Const::HTTP_KEEP_ALIVE]
end

#matched!Object

Sets the request as matched. This will abort evaluating any further deferred procs.

:api: private



160
161
162
# File 'lib/merb-core/dispatch/request.rb', line 160

def matched!
  @matched = true
end

#matched?Boolean

Checks whether or not the request has been matched to a route.

:api: private



167
168
169
# File 'lib/merb-core/dispatch/request.rb', line 167

def matched?
  @matched
end

#messageObject

Returns

String

Returns the redirect message Base64 unencoded.

:api: public



324
325
326
327
328
329
330
331
# File 'lib/merb-core/dispatch/request.rb', line 324

def message
  return {} unless params[:_message]
  begin
    Marshal.load(params[:_message].unpack("m").first)
  rescue ArgumentError, TypeError
    {}
  end
end

#methodObject

Returns

Symbol

The name of the request method, e.g. :get.

Notes

If the method is post, then the blocks specified in http_method_overrides will be checked for the masquerading method. The block will get the controller yielded to it. The first matching workaround wins. To disable this behavior, set http_method_overrides = []

:api: public



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/merb-core/dispatch/request.rb', line 105

def method
  @method ||= begin
    request_method = @env[Merb::Const::REQUEST_METHOD].downcase.to_sym
    case request_method
    when :get, :head, :put, :delete, :options
      request_method
    when :post
      m = nil
      self.class.http_method_overrides.each do |o|
        m ||= o.call(self); break if m
      end
      m.downcase! if m
      METHODS.include?(m) ? m.to_sym : :post
    else
      raise "Unknown REQUEST_METHOD: #{@env[Merb::Const::REQUEST_METHOD]}"
    end
  end
end

#paramsObject

Returns

Mash

All request parameters.

Notes

The order of precedence for the params is XML, JSON, multipart, body and request string.

:api: public



310
311
312
313
314
315
316
317
318
# File 'lib/merb-core/dispatch/request.rb', line 310

def params
  @params ||= begin
    h = body_and_query_params.merge(route_params)
    h.merge!(multipart_params) if self.class.parse_multipart_params && multipart_params
    h.merge!(json_params) if self.class.parse_json_params && json_params
    h.merge!(xml_params) if self.class.parse_xml_params && xml_params
    h
  end
end

#pathObject

Returns

String

The URI without the query string. Strips trailing “/” and reduces duplicate “/” to a single “/”.

:api: public



554
555
556
557
558
559
560
# File 'lib/merb-core/dispatch/request.rb', line 554

def path
  # Merb::Const::SLASH is /
  # Merb::Const::QUESTION_MARK is ?
  path = (uri.empty? ? Merb::Const::SLASH : uri.split(Merb::Const::QUESTION_MARK).first).squeeze(Merb::Const::SLASH)
  path = path[0..-2] if (path[-1] == ?/) && path.size > 1
  path
end

#path_infoObject

Returns

String

The path info.

:api: public



566
567
568
# File 'lib/merb-core/dispatch/request.rb', line 566

def path_info
  @path_info ||= Merb::Parse.unescape(@env[Merb::Const::PATH_INFO])
end

#portObject

Returns

Fixnum

The server port.

:api: public



574
575
576
# File 'lib/merb-core/dispatch/request.rb', line 574

def port
  @env[Merb::Const::SERVER_PORT].to_i
end

#protocolObject

Returns

String

The protocol, i.e. either “https” or “http” depending on the HTTPS header.

:api: public



384
385
386
# File 'lib/merb-core/dispatch/request.rb', line 384

def protocol
  ssl? ? Merb::Const::HTTPS : Merb::Const::HTTP
end

#query_stringObject

Returns

String

The query string.

:api: private



528
529
530
# File 'lib/merb-core/dispatch/request.rb', line 528

def query_string
  @env[Merb::Const::QUERY_STRING]
end

#rack_responseObject

Returns

(Array, Hash)

the route params for the matched route.

Notes

If the response is an Array then it is considered a direct Rack response to be sent back as a response. Otherwise, the route_params is a Hash with routing data (controller, action, et al).

:api: private



180
181
182
# File 'lib/merb-core/dispatch/request.rb', line 180

def rack_response
  @route_params
end

#raw_postObject

Returns

String

The raw post.

:api: private



345
346
347
348
# File 'lib/merb-core/dispatch/request.rb', line 345

def raw_post
  @body.rewind if @body.respond_to?(:rewind)
  @raw_post ||= @body.read
end

#refererObject

Returns

String

The HTTP referer.

:api: public



400
401
402
# File 'lib/merb-core/dispatch/request.rb', line 400

def referer
  @env[Merb::Const::HTTP_REFERER]
end

#remote_ipObject

Returns

String

The remote IP address.

:api: public



364
365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/merb-core/dispatch/request.rb', line 364

def remote_ip
  return @env[Merb::Const::HTTP_CLIENT_IP] if @env.include?(Merb::Const::HTTP_CLIENT_IP)

  if @env.include?(Merb::Const::HTTP_X_FORWARDED_FOR) then
    remote_ips = @env[Merb::Const::HTTP_X_FORWARDED_FOR].split(',').reject do |ip|
      ip =~ Merb::Const::LOCAL_IP_REGEXP
    end

    return remote_ips.first.strip unless remote_ips.empty?
  end

  return @env[Merb::Const::REMOTE_ADDR]
end

#reset_params!Object

Notes

Resets the params to a nil value.

:api: private



337
338
339
# File 'lib/merb-core/dispatch/request.rb', line 337

def reset_params!
  @params = nil
end

#script_nameObject

Returns

String

The script name.

:api: public



448
449
450
# File 'lib/merb-core/dispatch/request.rb', line 448

def script_name
  @env[Merb::Const::SCRIPT_NAME]
end

#server_nameObject

Returns

String

The server name.

:api: public



432
433
434
# File 'lib/merb-core/dispatch/request.rb', line 432

def server_name
  @env[Merb::Const::SERVER_NAME]
end

#server_softwareObject

Returns

String

The server software.

:api: public



472
473
474
# File 'lib/merb-core/dispatch/request.rb', line 472

def server_software
  @env[Merb::Const::SERVER_SOFTWARE]
end

#ssl?Boolean

Returns

Boolean:

True if the request is an SSL request.

:api: public



392
393
394
# File 'lib/merb-core/dispatch/request.rb', line 392

def ssl?
  @env[Merb::Const::UPCASE_HTTPS] == 'on' || @env[Merb::Const::HTTP_X_FORWARDED_PROTO] == Merb::Const::HTTPS
end

#subdomains(tld_length = 1) ⇒ Object

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.

:api: public



596
597
598
599
# File 'lib/merb-core/dispatch/request.rb', line 596

def subdomains(tld_length = 1)
  parts = host.split(Merb::Const::DOT)
  parts[0..-(tld_length+2)]
end

#uriObject

Returns

String

The request URI.

:api: public



416
417
418
# File 'lib/merb-core/dispatch/request.rb', line 416

def uri
  @env[Merb::Const::REQUEST_PATH] || @env[Merb::Const::REQUEST_URI] || path_info
end

#user_agentObject

Returns

String

The HTTP user agent.

:api: public



424
425
426
# File 'lib/merb-core/dispatch/request.rb', line 424

def user_agent
  @env[Merb::Const::HTTP_USER_AGENT]
end

#versionObject

Returns

String

The HTTP version

:api: private



496
497
498
# File 'lib/merb-core/dispatch/request.rb', line 496

def version
  @env[Merb::Const::HTTP_VERSION]
end

#xml_http_request?Boolean Also known as: xhr?, ajax?

Returns

Boolean

If the request is an XML HTTP request.

:api: public



354
355
356
# File 'lib/merb-core/dispatch/request.rb', line 354

def xml_http_request?
  not Merb::Const::XML_HTTP_REQUEST_REGEXP.match(@env[Merb::Const::HTTP_X_REQUESTED_WITH]).nil?
end