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

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



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

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

#exceptionsObject

:api: public



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

def exceptions
  @exceptions
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



12
13
14
# File 'lib/merb-core/dispatch/request.rb', line 12

def route_params
  @route_params
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



126
127
128
129
130
131
132
133
# File 'lib/merb-core/dispatch/request.rb', line 126

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



491
492
493
# File 'lib/merb-core/dispatch/request.rb', line 491

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

#accept_charsetObject

Returns

String

The accepted character sets.

:api: public



467
468
469
# File 'lib/merb-core/dispatch/request.rb', line 467

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

#accept_encodingObject

Returns

String

The accepted encodings.

:api: private



419
420
421
# File 'lib/merb-core/dispatch/request.rb', line 419

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

#accept_languageObject

Returns

String

The accepted language.

:api: public



443
444
445
# File 'lib/merb-core/dispatch/request.rb', line 443

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

#cache_controlObject

Returns

String

HTTP cache control.

:api: public



435
436
437
# File 'lib/merb-core/dispatch/request.rb', line 435

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

#connectionObject

Returns

String

The HTTP connection.

:api: private



499
500
501
# File 'lib/merb-core/dispatch/request.rb', line 499

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

#content_lengthObject

Returns

Fixnum

The request content length.

:api: public



523
524
525
# File 'lib/merb-core/dispatch/request.rb', line 523

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

#content_typeObject

Returns

String

The request content type.

:api: private



515
516
517
# File 'lib/merb-core/dispatch/request.rb', line 515

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



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/merb-core/dispatch/request.rb', line 52

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



589
590
591
# File 'lib/merb-core/dispatch/request.rb', line 589

def domain(tld_length = 1)
  host.split(Merb::Const::DOT).last(1 + tld_length).join(Merb::Const::DOT).sub(/:\d+$/,'')
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



115
116
117
118
# File 'lib/merb-core/dispatch/request.rb', line 115

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



387
388
389
# File 'lib/merb-core/dispatch/request.rb', line 387

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

#gatewayObject

Returns

String

The gateway.

:api: public



483
484
485
# File 'lib/merb-core/dispatch/request.rb', line 483

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

#handleObject

Handles request routing and action dispatch.

Returns

Merb::Controller

the controller that handled the action dispatch.

:api: private



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

def handle
  start = Time.now
  Merb.logger.info { "Started request handling: #{start.to_s}" }
  
  find_route!
  return rack_response if handled?
  
  klass = controller
  Merb.logger.debug { "Routed to: #{params.inspect}" }
  
  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
  
  if klass.abstract?
    raise NotFound, "The '#{klass}' controller has no public actions"
  end
  
  controller = dispatch_action(klass, params[:action])
  controller._benchmarks[:dispatch_time] = Time.now - start
  Merb.logger.info { controller._benchmarks.inspect }
  Merb.logger.flush
  controller.rack_response
rescue Object => exception
  dispatch_exception(exception).rack_response
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)


170
171
172
# File 'lib/merb-core/dispatch/request.rb', line 170

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

#hostObject

Returns

String

The full hostname including the port.

:api: public



561
562
563
564
# File 'lib/merb-core/dispatch/request.rb', line 561

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



605
606
607
608
609
# File 'lib/merb-core/dispatch/request.rb', line 605

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



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

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

#keep_aliveObject

Returns

String

Value of HTTP_KEEP_ALIVE.

:api: public



459
460
461
# File 'lib/merb-core/dispatch/request.rb', line 459

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



139
140
141
# File 'lib/merb-core/dispatch/request.rb', line 139

def matched!
  @matched = true
end

#matched?Boolean

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

:api: private

Returns:

  • (Boolean)


146
147
148
# File 'lib/merb-core/dispatch/request.rb', line 146

def matched?
  @matched
end

#messageObject

Returns

String

Returns the redirect message Base64 unencoded.

:api: public



303
304
305
306
307
308
309
310
# File 'lib/merb-core/dispatch/request.rb', line 303

def message
  return {} unless params[:_message]
  begin
    Marshal.load(Merb::Parse.unescape(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



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/merb-core/dispatch/request.rb', line 84

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



289
290
291
292
293
294
295
296
297
# File 'lib/merb-core/dispatch/request.rb', line 289

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



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

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



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

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

#portObject

Returns

Fixnum

The server port.

:api: public



553
554
555
# File 'lib/merb-core/dispatch/request.rb', line 553

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



363
364
365
# File 'lib/merb-core/dispatch/request.rb', line 363

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

#query_stringObject

Returns

String

The query string.

:api: private



507
508
509
# File 'lib/merb-core/dispatch/request.rb', line 507

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



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

def rack_response
  @route_params
end

#raw_postObject

Returns

String

The raw post.

:api: private



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

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

#refererObject

Returns

String

The HTTP referer.

:api: public



379
380
381
# File 'lib/merb-core/dispatch/request.rb', line 379

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

#remote_ipObject

Returns

String

The remote IP address.

:api: public



343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'lib/merb-core/dispatch/request.rb', line 343

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



316
317
318
# File 'lib/merb-core/dispatch/request.rb', line 316

def reset_params!
  @params = nil
end

#script_nameObject

Returns

String

The script name.

:api: public



427
428
429
# File 'lib/merb-core/dispatch/request.rb', line 427

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

#server_nameObject

Returns

String

The server name.

:api: public



411
412
413
# File 'lib/merb-core/dispatch/request.rb', line 411

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

#server_softwareObject

Returns

String

The server software.

:api: public



451
452
453
# File 'lib/merb-core/dispatch/request.rb', line 451

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)


371
372
373
# File 'lib/merb-core/dispatch/request.rb', line 371

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



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

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



395
396
397
# File 'lib/merb-core/dispatch/request.rb', line 395

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



403
404
405
# File 'lib/merb-core/dispatch/request.rb', line 403

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

#versionObject

Returns

String

The HTTP version

:api: private



475
476
477
# File 'lib/merb-core/dispatch/request.rb', line 475

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)


333
334
335
# File 'lib/merb-core/dispatch/request.rb', line 333

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