Class: Arrow::Transaction
Overview
The Arrow::Transaction class, a derivative of Arrow::Object. Instances of this class encapsulate a transaction within a web application implemented using the Arrow application framework.
Authors
-
Michael Granger <[email protected]>
Please see the file LICENSE in the top-level directory for licensing details.
Constant Summary collapse
- FORM_CONTENT_TYPES =
Regex to match the mimetypes that browsers use for sending form data
%r{application/x-www-form-urlencoded|multipart/form-data}i
- HTML_DOC =
A minimal HTML document for #status_doc
<<-"EOF".gsub(/^\t/, '') <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html> <head><title>%d %s</title></head> <body><h1>%s</h1><p>%s</p></body> </html> EOF
- STATUS_NAME =
Names for redirect statuses for #status_doc
{ 300 => "Multiple Choices", 301 => "Moved Permanently", 302 => "Found", 303 => "See Other", 304 => "Not Modified", 305 => "Use Proxy", 307 => "Temporary Redirect", }
- DelegatedMethods =
Apache::Request.instance_methods(false) - [ "inspect", "to_s" ]
Constants included from Constants
Constants::HTML_MIMETYPE, Constants::RUBY_MARSHALLED_MIMETYPE, Constants::RUBY_OBJECT_MIMETYPE, Constants::XHTML_MIMETYPE, Constants::YAML_DOMAIN
Instance Attribute Summary collapse
-
#applet_path ⇒ Object
The applet portion of the path_info.
-
#broker ⇒ Object
readonly
The Arrow::Broker that is responsible for delegating the Transaction to one or more Arrow::Applet objects.
-
#config ⇒ Object
readonly
The Arrow::Config object for the Arrow application that created this transaction.
-
#cookies ⇒ Object
readonly
The Arrow::CookieSet that contains cookies to be added to the response.
-
#data ⇒ Object
readonly
User-data hash.
-
#handler_status ⇒ Object
The handler status code to return to Apache.
-
#request ⇒ Object
readonly
The Apache::Request that initiated this transaction.
-
#request_cookies ⇒ Object
readonly
The Hash of Arrow::Cookies parsed from the request.
-
#serial ⇒ Object
readonly
The transaction’s unique id in the context of the system.
-
#vargs ⇒ Object
The argument validator (a FormValidator object).
Instance Method Summary collapse
-
#accepted_types ⇒ Object
Return the contents of the ‘Accept’ header as an Array of Arrow::AcceptParam objects.
-
#accepts?(content_type) ⇒ Boolean
(also: #accept?)
Returns boolean true/false if the requestor can handle the given
content_type
. -
#accepts_html? ⇒ Boolean
Returns true if the request’s content-negotiation headers indicate that it can accept either ‘text/html’ or ‘application/xhtml+xml’.
-
#add_cookie_headers ⇒ Object
Add a ‘Set-Cookie’ header to the response for each cookie that currently exists the transaction’s cookieset.
-
#app_root ⇒ Object
(also: #approot)
Return the portion of the request’s URI that serves as the base URI for the application.
-
#app_root_url ⇒ Object
(also: #approot_url)
Returns a fully-qualified URI String to the current applet using the request object’s server name and port.
-
#applet ⇒ Object
(also: #applet_uri)
Return an absolute uri that refers back to the applet the transaction is being run in.
-
#applet_url ⇒ Object
Returns a fully-qualified URI String to the current applet using the request object’s server name and port.
-
#arrow_version ⇒ Object
Get the verson of Arrow currently running.
-
#attachment=(filename) ⇒ Object
Set the result’s ‘Content-Disposition’ header to ‘attachment’ and set the attachment’s
filename
. -
#browser_is_ie? ⇒ Boolean
Returns true if the User-Agent header indicates that the remote browser is Internet Explorer.
-
#construct_url(uri) ⇒ Object
Overridden from Apache::Request to take Apache mod_proxy headers into account.
-
#explicitly_accepts?(content_type) ⇒ Boolean
(also: #explicitly_accept?)
Returns boolean true/false if the requestor can handle the given
content_type
, not including mime wildcards. -
#for_ie_users ⇒ Object
Execute a block if the User-Agent header indicates that the remote browser is Internet Explorer.
-
#form_request? ⇒ Boolean
Return
true
if there are HTML form parameters in the request, either in the query string with a GET request, or in the body of a POST with a mimetype of either ‘application/x-www-form-urlencoded’ or ‘multipart/form-data’. -
#initialize(request, config, broker) ⇒ Transaction
constructor
Create a new Arrow::Transaction object with the specified
request
(an Apache::Request object),config
(an Arrow::Config object),broker
object (an Arrow::Broker), andsession
(Arrow::Session) objects. -
#inspect ⇒ Object
Returns a human-readable String representation of the transaction, suitable for debugging.
-
#is_ajax_request? ⇒ Boolean
Return
true
if the request is from XMLHttpRequest (as indicated by the ‘X-Requested-With’ header from Scriptaculous or jQuery). -
#is_declined? ⇒ Boolean
Returns true if the transaction’s server status will cause the request to be declined (i.e., not handled by Arrow).
-
#is_success? ⇒ Boolean
Returns true if the transactions response status is 2xx.
-
#normalized_accept_string ⇒ Object
Return a normalized list of acceptable types, sorted by q-value and specificity.
-
#not_modified ⇒ Object
Set the necessary header fields in the response to cause a NOT_MODIFIED response to be sent.
-
#parsed_uri ⇒ Object
Return a URI object that is parsed from the request’s URI.
-
#path ⇒ Object
Returns the path operated on by the Arrow::Broker when delegating the transaction.
-
#proxied_host ⇒ Object
If the request came from a reverse proxy (i.e., the X-Forwarded-Host or X-Forwarded-Server headers are present), return the hostname that the proxy is forwarding for.
-
#redirect(uri, status_code = Apache::HTTP_MOVED_TEMPORARILY) ⇒ Object
Set the necessary fields in the request to cause the response to be a redirect to the given
url
with the specifiedstatus_code
(302 by default). -
#referer ⇒ Object
Get the request’s referer, if any.
-
#referring_action ⇒ Object
If the referer was another applet under the same Arrow instance, return the name of the action that preceded the current one.
-
#referring_applet ⇒ Object
If the referer was another applet under the same Arrow instance, return the uri to it.
-
#refresh(seconds, url = nil) ⇒ Object
Set the necessary header to make the displayed page refresh to the specified
url
in the given number ofseconds
. -
#remote_ip ⇒ Object
Fetch the client’s IP, either from proxy headers or the connection’s IP.
-
#request_content_type ⇒ Object
Return the Content-type header given in the request’s headers, if any.
-
#root_dispatcher? ⇒ Boolean
Returns
true
if the dispatcher is mounted on the root URI (“/”). -
#session(config = {}) ⇒ Object
The session associated with the receiver (an Arrow::Session object).
-
#session? ⇒ Boolean
Returns
true
if a session has been created for the receiver. -
#status_doc(status_code, uri = nil) ⇒ Object
Return a minimal HTML doc for representing a given status_code.
Methods inherited from Object
deprecate_class_method, deprecate_method, inherited
Constructor Details
#initialize(request, config, broker) ⇒ Transaction
Create a new Arrow::Transaction object with the specified request
(an Apache::Request object), config
(an Arrow::Config object), broker
object (an Arrow::Broker), and session
(Arrow::Session) objects.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/arrow/transaction.rb', line 76 def initialize( request, config, broker ) @request = request @config = config @broker = broker @handler_status = Apache::OK @serial = make_transaction_serial( request ) # Stuff that may be filled in later @session = nil # Lazily-instantiated @applet_path = nil # Added by the broker @vargs = nil # Filled in by the applet @data = {} @request_cookies = ( request ) @cookies = Arrow::CookieSet.new() @accepted_types = nil # Check for a "RubyOption root_dispatcher true" if @request..key?('root_dispatcher') && @request.['root_dispatcher'].match( /^(true|yes|1)$/i ) self.log.debug "Dispatching from root path" @root_dispatcher = true else self.log.debug "Dispatching from sub-path" @root_dispatcher = false end @request.sync_header = true super() end |
Instance Attribute Details
#applet_path ⇒ Object
The applet portion of the path_info
131 132 133 |
# File 'lib/arrow/transaction.rb', line 131 def applet_path @applet_path end |
#broker ⇒ Object (readonly)
The Arrow::Broker that is responsible for delegating the Transaction to one or more Arrow::Applet objects.
125 126 127 |
# File 'lib/arrow/transaction.rb', line 125 def broker @broker end |
#config ⇒ Object (readonly)
The Arrow::Config object for the Arrow application that created this transaction.
121 122 123 |
# File 'lib/arrow/transaction.rb', line 121 def config @config end |
#cookies ⇒ Object (readonly)
The Arrow::CookieSet that contains cookies to be added to the response
143 144 145 |
# File 'lib/arrow/transaction.rb', line 143 def @cookies end |
#data ⇒ Object (readonly)
User-data hash. Can be used to pass data between applets in a chain.
137 138 139 |
# File 'lib/arrow/transaction.rb', line 137 def data @data end |
#handler_status ⇒ Object
The handler status code to return to Apache
146 147 148 |
# File 'lib/arrow/transaction.rb', line 146 def handler_status @handler_status end |
#request ⇒ Object (readonly)
The Apache::Request that initiated this transaction
117 118 119 |
# File 'lib/arrow/transaction.rb', line 117 def request @request end |
#request_cookies ⇒ Object (readonly)
The Hash of Arrow::Cookies parsed from the request
140 141 142 |
# File 'lib/arrow/transaction.rb', line 140 def @request_cookies end |
#serial ⇒ Object (readonly)
The transaction’s unique id in the context of the system.
134 135 136 |
# File 'lib/arrow/transaction.rb', line 134 def serial @serial end |
#vargs ⇒ Object
The argument validator (a FormValidator object)
128 129 130 |
# File 'lib/arrow/transaction.rb', line 128 def vargs @vargs end |
Instance Method Details
#accepted_types ⇒ Object
Return the contents of the ‘Accept’ header as an Array of Arrow::AcceptParam objects.
399 400 401 402 |
# File 'lib/arrow/transaction.rb', line 399 def accepted_types @accepted_types ||= parse_accept_header( self.headers_in['Accept'] ) return @accepted_types end |
#accepts?(content_type) ⇒ Boolean Also known as: accept?
Returns boolean true/false if the requestor can handle the given content_type
.
407 408 409 |
# File 'lib/arrow/transaction.rb', line 407 def accepts?( content_type ) return self.accepted_types.find {|type| type =~ content_type } ? true : false end |
#accepts_html? ⇒ Boolean
Returns true if the request’s content-negotiation headers indicate that it can accept either ‘text/html’ or ‘application/xhtml+xml’
424 425 426 |
# File 'lib/arrow/transaction.rb', line 424 def accepts_html? return self.accepts?( XHTML_MIMETYPE ) || self.accepts?( HTML_MIMETYPE ) end |
#add_cookie_headers ⇒ Object
Add a ‘Set-Cookie’ header to the response for each cookie that currently exists the transaction’s cookieset.
311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/arrow/transaction.rb', line 311 def self..each do || if self.is_success? self.log.debug "Adding 'Set-Cookie' header: %p (%p)" % [, .to_s] self.headers_out['Set-Cookie'] = .to_s else self.log.debug "Adding 'Set-Cookie' to the error headers: %p (%p)" % [, .to_s] self.err_headers_out['Set-Cookie'] = .to_s end end end |
#app_root ⇒ Object Also known as: approot
Return the portion of the request’s URI that serves as the base URI for the application. All self-referential URLs created by the application should include this.
234 235 236 237 |
# File 'lib/arrow/transaction.rb', line 234 def app_root return "" if self.root_dispatcher? return @request.script_name end |
#app_root_url ⇒ Object Also known as: approot_url
Returns a fully-qualified URI String to the current applet using the request object’s server name and port.
243 244 245 |
# File 'lib/arrow/transaction.rb', line 243 def app_root_url return construct_url( self.app_root ) end |
#applet ⇒ Object Also known as: applet_uri
Return an absolute uri that refers back to the applet the transaction is being run in
251 252 253 |
# File 'lib/arrow/transaction.rb', line 251 def applet return [ self.app_root, self.applet_path ].join("/").gsub( %r{//+}, '/' ) end |
#applet_url ⇒ Object
Returns a fully-qualified URI String to the current applet using the request object’s server name and port.
260 261 262 |
# File 'lib/arrow/transaction.rb', line 260 def applet_url return construct_url( self.applet ) end |
#arrow_version ⇒ Object
Get the verson of Arrow currently running.
540 541 542 |
# File 'lib/arrow/transaction.rb', line 540 def arrow_version return Arrow::VERSION end |
#attachment=(filename) ⇒ Object
Set the result’s ‘Content-Disposition’ header to ‘attachment’ and set the attachment’s filename
.
370 371 372 373 374 375 376 377 378 379 |
# File 'lib/arrow/transaction.rb', line 370 def ( filename ) # IE flubs attachments of any mimetype it handles directly. if self.browser_is_ie? self.content_type = 'application/octet-stream' end val = %q{attachment; filename="%s"} % [ filename ] self.headers_out['Content-Disposition'] = val end |
#browser_is_ie? ⇒ Boolean
Returns true if the User-Agent header indicates that the remote browser is Internet Explorer. Useful for making the inevitable IE workarounds.
442 443 444 445 |
# File 'lib/arrow/transaction.rb', line 442 def browser_is_ie? agent = self.headers_in['user-agent'] || '' return agent =~ /MSIE/ ? true : false end |
#construct_url(uri) ⇒ Object
Overridden from Apache::Request to take Apache mod_proxy headers into account. If the ‘X-Forwarded-Host’ or ‘X-Forwarded-Server’ headers exist in the request, the hostname specified is used instead of the canonical host.
330 331 332 333 334 335 336 337 338 339 340 341 342 |
# File 'lib/arrow/transaction.rb', line 330 def construct_url( uri ) url = @request.construct_url( uri ) # If the request came through a proxy, rewrite the url's host to match # the hostname the proxy is forwarding for. if (( host = self.proxied_host )) uriobj = URI.parse( url ) uriobj.host = host url = uriobj.to_s end return url end |
#explicitly_accepts?(content_type) ⇒ Boolean Also known as: explicitly_accept?
Returns boolean true/false if the requestor can handle the given content_type
, not including mime wildcards.
415 416 417 418 |
# File 'lib/arrow/transaction.rb', line 415 def explicitly_accepts?( content_type ) self.accepted_types.reject { |param| param.subtype.nil? }. find {|type| type =~ content_type } ? true : false end |
#for_ie_users ⇒ Object
Execute a block if the User-Agent header indicates that the remote browser is Internet Explorer. Useful for making the inevitable IE workarounds.
451 452 453 |
# File 'lib/arrow/transaction.rb', line 451 def for_ie_users yield if self.browser_is_ie? end |
#form_request? ⇒ Boolean
Return true
if there are HTML form parameters in the request, either in the query string with a GET request, or in the body of a POST with a mimetype of either ‘application/x-www-form-urlencoded’ or ‘multipart/form-data’.
468 469 470 471 472 473 474 475 476 477 478 479 480 |
# File 'lib/arrow/transaction.rb', line 468 def form_request? case self.request_method when 'GET', 'HEAD', 'DELETE', 'PUT' return (!self.parsed_uri.query.nil? || self.request_content_type =~ FORM_CONTENT_TYPES) ? true : false when 'POST' return self.request_content_type =~ FORM_CONTENT_TYPES ? true : false else return false end end |
#inspect ⇒ Object
Returns a human-readable String representation of the transaction, suitable for debugging.
151 152 153 154 155 156 157 158 |
# File 'lib/arrow/transaction.rb', line 151 def inspect "#<%s:0x%0x serial: %s; HTTP status: %d>" % [ self.class.name, self.object_id * 2, self.serial, self.status ] end |
#is_ajax_request? ⇒ Boolean
Return true
if the request is from XMLHttpRequest (as indicated by the ‘X-Requested-With’ header from Scriptaculous or jQuery)
458 459 460 461 462 |
# File 'lib/arrow/transaction.rb', line 458 def is_ajax_request? xrw_header = self.headers_in['x-requested-with'] return true if !xrw_header.nil? && xrw_header =~ /xmlhttprequest/i return false end |
#is_declined? ⇒ Boolean
Returns true if the transaction’s server status will cause the request to be declined (i.e., not handled by Arrow)
182 183 184 185 186 |
# File 'lib/arrow/transaction.rb', line 182 def is_declined? self.log.debug "Checking to see if the transaction is declined (%p)" % [self.handler_status] return self.handler_status == Apache::DECLINED ? true : false end |
#is_success? ⇒ Boolean
Returns true if the transactions response status is 2xx.
174 175 176 177 |
# File 'lib/arrow/transaction.rb', line 174 def is_success? return nil unless self.status return (self.status / 100) == 2 end |
#normalized_accept_string ⇒ Object
Return a normalized list of acceptable types, sorted by q-value and specificity.
430 431 432 |
# File 'lib/arrow/transaction.rb', line 430 def normalized_accept_string return self.accepted_types.sort.collect {|ap| ap.to_s }.join( ', ' ) end |
#not_modified ⇒ Object
Set the necessary header fields in the response to cause a NOT_MODIFIED response to be sent.
521 522 523 |
# File 'lib/arrow/transaction.rb', line 521 def not_modified return self.redirect( uri, Apache::HTTP_NOT_MODIFIED ) end |
#parsed_uri ⇒ Object
Return a URI object that is parsed from the request’s URI.
383 384 385 |
# File 'lib/arrow/transaction.rb', line 383 def parsed_uri return URI.parse( self.request.unparsed_uri ) end |
#path ⇒ Object
Returns the path operated on by the Arrow::Broker when delegating the transaction. Equal to the #uri minus the #app_root.
224 225 226 227 228 |
# File 'lib/arrow/transaction.rb', line 224 def path path = @request.uri uripat = Regexp.new( "^" + self.app_root ) return path.sub( uripat, '' ) end |
#proxied_host ⇒ Object
If the request came from a reverse proxy (i.e., the X-Forwarded-Host or X-Forwarded-Server headers are present), return the hostname that the proxy is forwarding for. If no proxy headers are present, return nil.
349 350 351 352 |
# File 'lib/arrow/transaction.rb', line 349 def proxied_host headers = @request.headers_in return headers['x-forwarded-host'] || headers['x-forwarded-server'] end |
#redirect(uri, status_code = Apache::HTTP_MOVED_TEMPORARILY) ⇒ Object
Set the necessary fields in the request to cause the response to be a redirect to the given url
with the specified status_code
(302 by default).
509 510 511 512 513 514 515 516 |
# File 'lib/arrow/transaction.rb', line 509 def redirect( uri, status_code=Apache::HTTP_MOVED_TEMPORARILY ) self.log.debug "Redirecting to %s" % uri self.headers_out[ 'Location' ] = uri.to_s self.status = status_code self.handler_status = Apache::REDIRECT return '' end |
#referer ⇒ Object
Get the request’s referer, if any
363 364 365 |
# File 'lib/arrow/transaction.rb', line 363 def referer return self.headers_in['Referer'] end |
#referring_action ⇒ Object
If the referer was another applet under the same Arrow instance, return the name of the action that preceded the current one. If there was no ‘Referer’ header, or the referer wasn’t an applet under the same Arrow instance, return nil
.
288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/arrow/transaction.rb', line 288 def referring_action return nil unless self.referer uri = URI.parse( self.referer ) path = uri.path or return nil appletRe = Regexp.new( self.app_root + "/\\w+/" ) return nil unless appletRe.match( path ) subpath = path. sub( appletRe, '' ). split( %r{/} ). first return subpath end |
#referring_applet ⇒ Object
If the referer was another applet under the same Arrow instance, return the uri to it. If there was no ‘Referer’ header, or the referer wasn’t an applet under the same Arrow instance, returns nil
.
268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/arrow/transaction.rb', line 268 def referring_applet return nil unless self.referer uri = URI.parse( self.referer ) path = uri.path or return nil rootRe = Regexp.new( self.app_root + "/" ) return nil unless rootRe.match( path ) subpath = path. sub( rootRe, '' ). split( %r{/} ). first return subpath end |
#refresh(seconds, url = nil) ⇒ Object
Set the necessary header to make the displayed page refresh to the specified url
in the given number of seconds
.
528 529 530 531 532 533 534 535 536 |
# File 'lib/arrow/transaction.rb', line 528 def refresh( seconds, url=nil ) seconds = Integer( seconds ) url ||= self.construct_url( '' ) if !URI.parse( url ).absolute? url = self.construct_url( url ) end self.headers_out['Refresh'] = "%d;%s" % [seconds, url] end |
#remote_ip ⇒ Object
Fetch the client’s IP, either from proxy headers or the connection’s IP.
356 357 358 |
# File 'lib/arrow/transaction.rb', line 356 def remote_ip return self.headers_in['X-Forwarded-For'] || self.connection.remote_ip end |
#request_content_type ⇒ Object
Return the Content-type header given in the request’s headers, if any
389 390 391 |
# File 'lib/arrow/transaction.rb', line 389 def request_content_type return self.headers_in['Content-type'] end |
#root_dispatcher? ⇒ Boolean
Returns true
if the dispatcher is mounted on the root URI (“/”)
217 218 219 |
# File 'lib/arrow/transaction.rb', line 217 def root_dispatcher? return @root_dispatcher end |
#session(config = {}) ⇒ Object
The session associated with the receiver (an Arrow::Session object).
168 169 170 |
# File 'lib/arrow/transaction.rb', line 168 def session( config={} ) @session ||= Arrow::Session.create( self, config ) end |
#session? ⇒ Boolean
Returns true
if a session has been created for the receiver.
162 163 164 |
# File 'lib/arrow/transaction.rb', line 162 def session? @session ? true : false end |
#status_doc(status_code, uri = nil) ⇒ Object
Return a minimal HTML doc for representing a given status_code
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/arrow/transaction.rb', line 488 def status_doc( status_code, uri=nil ) body = '' if uri body = %q{<a href="%s">%s</a>} % [ uri, uri ] end #<head><title>%d %s</title></head> #<body><h1>%s</h1><p>%s</p></body> return HTML_DOC % [ status_code, STATUS_NAME[status_code], STATUS_NAME[status_code], body ] end |