Class | Merb::Request |
In: |
merb-core/lib/merb-core/dispatch/request.rb
merb-core/lib/merb-core/dispatch/dispatcher.rb |
Parent: | Object |
METHODS | = | %w{get post put delete head options} |
env | [RW] | :api: private |
exceptions | [RW] | :api: public |
route | [RW] | :api: private |
route_params | [R] | :api: private |
Initialize the request object.
http_request<~params:~[], ~body:IO>: | An object like an HTTP Request. |
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 38 38: def initialize(rack_env) 39: @env = rack_env 40: @body = rack_env[Merb::Const::RACK_INPUT] 41: @route_params = {} 42: end
Processes the return value of a deferred router block and returns the current route params for the current request evaluation
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 126 126: def _process_block_return(retval) 127: # If the return value is an array, then it is a redirect 128: # so we must set the request as a redirect and extract 129: # the redirect params and return it as a hash so that the 130: # dispatcher can handle it 131: matched! if retval.is_a?(Array) 132: retval 133: end
String: | The HTTP connection. |
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 499 499: def connection 500: @env[Merb::Const::HTTP_CONNECTION] 501: end
Fixnum: | The request content length. |
:api: public
# File merb-core/lib/merb-core/dispatch/request.rb, line 523 523: def content_length 524: @content_length ||= @env[Merb::Const::CONTENT_LENGTH].to_i 525: end
Returns the controller object for initialization and dispatching the request.
Class: | The controller class matching the routed request, |
e.g. Posts.
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 52 52: def controller 53: unless params[:controller] 54: raise ControllerExceptions::NotFound, 55: "Route matched, but route did not specify a controller.\n" + 56: "Did you forgot to add :controller => \"people\" or :controller " + 57: "segment to route definition?\nHere is what's specified:\n" + 58: route.inspect 59: end 60: path = [params[:namespace], params[:controller]].compact.join(Merb::Const::SLASH) 61: controller = path.snake_case.to_const_string 62: 63: begin 64: Object.full_const_get(controller) 65: rescue NameError => e 66: msg = "Controller class not found for controller `#{path}'" 67: Merb.logger.warn!(msg) 68: raise ControllerExceptions::NotFound, msg 69: end 70: end
tld_length<Fixnum>: | Number of domains levels to inlclude in the top level domain. Defaults to 1. |
String: | The full domain name without the port number. |
:api: public
# File merb-core/lib/merb-core/dispatch/request.rb, line 589 589: def domain(tld_length = 1) 590: host.split(Merb::Const::DOT).last(1 + tld_length).join(Merb::Const::DOT).sub(/:\d+$/,'') 591: end
Find route using requested URI and merges route parameters (:action, :controller and named segments) into request params hash.
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 115 115: def find_route! 116: @route, @route_params = Merb::Router.route_for(self) 117: params.merge! @route_params if @route_params.is_a?(Hash) 118: end
Handles request routing and action dispatch.
Merb::Controller: | the controller that handled the action dispatch. |
:api: private
# File merb-core/lib/merb-core/dispatch/dispatcher.rb, line 52 52: def handle 53: start = Time.now 54: Merb.logger.info { "Started request handling: #{start.to_s}" } 55: 56: find_route! 57: return rack_response if handled? 58: 59: klass = controller 60: Merb.logger.debug { "Routed to: #{params.inspect}" } 61: 62: unless klass < Controller 63: raise NotFound, 64: "Controller '#{klass}' not found.\n" \ 65: "If Merb tries to find a controller for static files, " \ 66: "you may need to check your Rackup file, see the Problems " \ 67: "section at: http://wiki.merbivore.com/pages/rack-middleware" 68: end 69: 70: if klass.abstract? 71: raise NotFound, "The '#{klass}' controller has no public actions" 72: end 73: 74: controller = dispatch_action(klass, params[:action]) 75: controller._benchmarks[:dispatch_time] = Time.now - start 76: Merb.logger.info { controller._benchmarks.inspect } 77: Merb.logger.flush 78: controller.rack_response 79: rescue Object => exception 80: dispatch_exception(exception).rack_response 81: end
If @route_params is an Array, then it will be the rack response. In this case, the request is considered handled.
Boolean: | true if @route_params is an Array, false otherwise. |
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 170 170: def handled? 171: @route_params.is_a?(Array) 172: end
Value of If-Modified-Since request header.
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 605 605: def if_modified_since 606: if time = @env[Merb::Const::HTTP_IF_MODIFIED_SINCE] 607: Time.rfc2822(time) 608: end 609: end
Value of If-None-Match request header.
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 597 597: def if_none_match 598: @env[Merb::Const::HTTP_IF_NONE_MATCH] 599: end
Sets the request as matched. This will abort evaluating any further deferred procs.
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 139 139: def matched! 140: @matched = true 141: end
Checks whether or not the request has been matched to a route.
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 146 146: def matched? 147: @matched 148: end
String: | Returns the redirect message Base64 unencoded. |
:api: public
# File merb-core/lib/merb-core/dispatch/request.rb, line 303 303: def message 304: return {} unless params[:_message] 305: begin 306: Marshal.load(Merb::Parse.unescape(params[:_message]).unpack("m").first) 307: rescue ArgumentError, TypeError 308: {} 309: end 310: end
Symbol: | The name of the request method, e.g. :get. |
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
# File merb-core/lib/merb-core/dispatch/request.rb, line 84 84: def method 85: @method ||= begin 86: request_method = @env[Merb::Const::REQUEST_METHOD].downcase.to_sym 87: case request_method 88: when :get, :head, :put, :delete, :options 89: request_method 90: when :post 91: m = nil 92: self.class.http_method_overrides.each do |o| 93: m ||= o.call(self); break if m 94: end 95: m.downcase! if m 96: METHODS.include?(m) ? m.to_sym : :post 97: else 98: raise "Unknown REQUEST_METHOD: #{@env[Merb::Const::REQUEST_METHOD]}" 99: end 100: end 101: end
Mash: | All request parameters. |
The order of precedence for the params is XML, JSON, multipart, body and request string.
:api: public
# File merb-core/lib/merb-core/dispatch/request.rb, line 289 289: def params 290: @params ||= begin 291: h = body_and_query_params.merge(route_params) 292: h.merge!(multipart_params) if self.class.parse_multipart_params && multipart_params 293: h.merge!(json_params) if self.class.parse_json_params && json_params 294: h.merge!(xml_params) if self.class.parse_xml_params && xml_params 295: h 296: end 297: end
String: | The URI without the query string. Strips trailing "/" and reduces duplicate "/" to a single "/". |
:api: public
# File merb-core/lib/merb-core/dispatch/request.rb, line 533 533: def path 534: # Merb::Const::SLASH is / 535: # Merb::Const::QUESTION_MARK is ? 536: path = (uri.empty? ? Merb::Const::SLASH : uri.split(Merb::Const::QUESTION_MARK).first).squeeze(Merb::Const::SLASH) 537: path = path[0..-2] if (path[-1] == ?/) && path.size > 1 538: path 539: end
(Array, Hash): | the route params for the matched route. |
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
# File merb-core/lib/merb-core/dispatch/request.rb, line 159 159: def rack_response 160: @route_params 161: end
String: | The remote IP address. |
:api: public
# File merb-core/lib/merb-core/dispatch/request.rb, line 343 343: def remote_ip 344: return @env[Merb::Const::HTTP_CLIENT_IP] if @env.include?(Merb::Const::HTTP_CLIENT_IP) 345: 346: if @env.include?(Merb::Const::HTTP_X_FORWARDED_FOR) then 347: remote_ips = @env[Merb::Const::HTTP_X_FORWARDED_FOR].split(',').reject do |ip| 348: ip =~ Merb::Const::LOCAL_IP_REGEXP 349: end 350: 351: return remote_ips.first.strip unless remote_ips.empty? 352: end 353: 354: return @env[Merb::Const::REMOTE_ADDR] 355: end
Boolean:: | True if the request is an SSL request. |
:api: public
# File merb-core/lib/merb-core/dispatch/request.rb, line 371 371: def ssl? 372: @env[Merb::Const::UPCASE_HTTPS] == 'on' || @env[Merb::Const::HTTP_X_FORWARDED_PROTO] == Merb::Const::HTTPS 373: end
tld_length<Fixnum>: | Number of domains levels to inlclude in the top level domain. Defaults to 1. |
Array: | All the subdomain parts of the host. |
:api: public
# File merb-core/lib/merb-core/dispatch/request.rb, line 575 575: def subdomains(tld_length = 1) 576: parts = host.split(Merb::Const::DOT) 577: parts[0..-(tld_length+2)] 578: end
Boolean: | If the request is an XML HTTP request. |
:api: public
# File merb-core/lib/merb-core/dispatch/request.rb, line 333 333: def xml_http_request? 334: not Merb::Const::XML_HTTP_REQUEST_REGEXP.match(@env[Merb::Const::HTTP_X_REQUESTED_WITH]).nil? 335: end
Mash: | The parameters gathered from the query string and the request body, with parameters in the body taking precedence. |
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 210 210: def body_and_query_params 211: # ^-- FIXME a better name for this method 212: @body_and_query_params ||= begin 213: h = query_params 214: h.merge!(body_params) if body_params 215: h.to_mash 216: end 217: end
Parameters passed in the body of the request. Ajax calls from prototype.js and other libraries pass content this way.
Hash: | The parameters passed in the body. |
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 196 196: def body_params 197: @body_params ||= begin 198: if content_type && content_type.match(Merb::Const::FORM_URL_ENCODED_REGEXP) # or content_type.nil? 199: Merb::Parse.query(raw_post) 200: end 201: end 202: end
Setup the controller and call the chosen action
klass<Merb::Controller>: | The controller class to dispatch to. |
action<Symbol>: | The action to dispatch. |
status<Integer>: | The status code to respond with. |
Merb::Controller: | The Merb::Controller that was dispatched to. |
:api: private
# File merb-core/lib/merb-core/dispatch/dispatcher.rb, line 96 96: def dispatch_action(klass, action, status=200) 97: # build controller 98: controller = klass.new(self, status) 99: if Dispatcher.use_mutex 100: @@mutex.synchronize { controller._dispatch(action) } 101: else 102: controller._dispatch(action) 103: end 104: controller 105: end
Re-route the current request to the Exception controller if it is available, and try to render the exception nicely.
You can handle exceptions by implementing actions for specific exceptions such as not_found or for entire classes of exceptions such as client_error. You can also implement handlers for exceptions outside the Merb exception hierarchy (e.g. StandardError is caught in standard_error).
exception<Object>: | The exception object that was created when trying to dispatch the original controller. |
Exceptions: | The Merb::Controller that was dispatched to. |
:api: private
# File merb-core/lib/merb-core/dispatch/dispatcher.rb, line 126 126: def dispatch_exception(exception) 127: if(exception.is_a?(Merb::ControllerExceptions::Base) && 128: !exception.is_a?(Merb::ControllerExceptions::ServerError)) 129: Merb.logger.info(Merb.exception(exception)) 130: else 131: Merb.logger.error(Merb.exception(exception)) 132: end 133: 134: self.exceptions = [exception] 135: 136: begin 137: e = exceptions.first 138: 139: if action_name = e.action_name 140: dispatch_action(Exceptions, action_name, e.class.status) 141: else 142: Merb::Dispatcher::DefaultException.new(self, e.class.status)._dispatch 143: end 144: rescue Object => dispatch_issue 145: if e.same?(dispatch_issue) || exceptions.size > 5 146: Merb::Dispatcher::DefaultException.new(self, e.class.status)._dispatch 147: else 148: Merb.logger.error("Dispatching #{e.class} raised another error.") 149: Merb.logger.error(Merb.exception(dispatch_issue)) 150: 151: exceptions.unshift dispatch_issue 152: retry 153: end 154: end 155: end
Hash: | Parameters from body if this is a JSON request. |
If the JSON object parses as a Hash, it will be merged with the parameters hash. If it parses to anything else (such as an Array, or if it inflates to an Object) it will be accessible via the inflated_object parameter.
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 253 253: def json_params 254: @json_params ||= begin 255: if Merb::Const::JSON_MIME_TYPE_REGEXP.match(content_type) 256: begin 257: jobj = JSON.parse(raw_post) 258: jobj = jobj.to_mash if jobj.is_a?(Hash) 259: rescue JSON::ParserError 260: jobj = Mash.new 261: end 262: jobj.is_a?(Hash) ? jobj : { :inflated_object => jobj } 263: end 264: end 265: end
ControllerExceptions::MultiPartParseError: | Unable to parse the multipart form data. |
Hash: | The parsed multipart parameters. |
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 227 227: def multipart_params 228: @multipart_params ||= 229: begin 230: # if the content-type is multipart 231: # parse the multipart. Otherwise return {} 232: if (Merb::Const::MULTIPART_REGEXP =~ content_type) 233: Merb::Parse.multipart(@body, $1, content_length) 234: else 235: {} 236: end 237: rescue ControllerExceptions::MultiPartParseError => e 238: @multipart_params = {} 239: raise e 240: end 241: end
Hash: | Parameters from body if this is an XML request. |
:api: private
# File merb-core/lib/merb-core/dispatch/request.rb, line 271 271: def xml_params 272: @xml_params ||= begin 273: if Merb::Const::XML_MIME_TYPE_REGEXP.match(content_type) 274: Hash.from_xml(raw_post) rescue Mash.new 275: end 276: end 277: end