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

Returns:

  • (Array[Integer, Hash, #each])

    A Rack response


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

Returns:

  • (Boolean)

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

Returns:

  • (Boolean)

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

Returns:

  • (Boolean)

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

Returns:

  • (Boolean)

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