Request Client for internal execution
Class declared in SYSPATH/classes/Request/Client/Internal.php on line 3.
Cache
$_cachelink to thisCaching library for request caching
NULL
int
$_callback_depthlink to thisTracks the callback depth of the currently executing request
integer 1
array
$_callback_paramslink to thisArbitrary parameters that are shared with header callbacks through their Request_Client object
array(0)
bool
$_followlink to thisShould redirects be followed?
bool FALSE
array
$_follow_headerslink to thisHeaders to preserve when following a redirect
array(1) ( 0 => string(13) "authorization" )
array
$_header_callbackslink to thisCallbacks to use when response contains given headers
array(1) ( "Location" => string(34) "Request_Client::on_header_location" )
int
$_max_callback_depthlink to thisMaximum number of requests that header callbacks can trigger before the request is aborted
integer 5
array
$_previous_environmentlink to thisNULL
bool
$_strict_redirectlink to thisFollow 302 redirect with original request method?
bool TRUE
Processes the request, executing the controller action that handles this request, determined by the Route.
$request
->execute();
Request
$request
required - $request unknown
$response
required Response
public
function
execute_request(Request
$request
, Response
$response
)
{
// Create the class prefix
$prefix
=
'Controller_'
;
// Directory
$directory
=
$request
->directory();
// Controller
$controller
=
$request
->controller();
if
(
$directory
) {
// Add the directory name to the class prefix
$prefix
.=
str_replace
([
'\\'
,
'/'
],
'_'
, trim(
$directory
,
'/'
)) .
'_'
;
}
if
(Kohana::
$profiling
) {
// Set the benchmark name
$benchmark
=
'"'
.
$request
->uri() .
'"'
;
if
(
$request
!== Request::
$initial
AND Request::
$current
) {
// Add the parent request uri
$benchmark
.=
' « "'
. Request::
$current
->uri() .
'"'
;
}
// Start benchmarking
$benchmark
= Profiler::start(
'Requests'
,
$benchmark
);
}
// Store the currently active request
$previous
= Request::
$current
;
// Change the current request to this request
Request::
$current
=
$request
;
// Is this the initial request
$initial_request
= (
$request
=== Request::
$initial
);
try
{
if
(!
class_exists
(
$prefix
.
$controller
)) {
throw
HTTP_Exception::factory(404,
'The requested URL :uri was not found on this server.'
, [
':uri'
=>
$request
->uri()])->request(
$request
);
}
// Load the controller using reflection
$class
=
new
ReflectionClass(
$prefix
.
$controller
);
if
(
$class
->isAbstract()) {
throw
new
Kohana_Exception(
'Cannot create instances of abstract :controller'
, [
':controller'
=>
$prefix
.
$controller
]);
}
// Create a new instance of the controller
$controller
=
$class
->newInstance(
$request
,
$response
);
// Run the controller's execute() method
$response
=
$class
->getMethod(
'execute'
)->invoke(
$controller
);
if
(!
$response
instanceof
Response) {
// Controller failed to return a Response.
throw
new
Kohana_Exception(
'Controller failed to return a Response'
);
}
}
catch
(HTTP_Exception
$e
) {
// Store the request context in the Exception
if
(
$e
->request() === null) {
$e
->request(
$request
);
}
// Get the response via the Exception
$response
=
$e
->get_response();
}
catch
(Exception
$e
) {
// Generate an appropriate Response object
$response
= Kohana_Exception::_handler(
$e
);
}
// Restore the previous request
Request::
$current
=
$previous
;
if
(isset(
$benchmark
)) {
// Stop the benchmark
Profiler::stop(
$benchmark
);
}
// Return the response
return
$response
;
}
Creates a new Request_Client
object,
allows for dependency injection.
array
$params
= array(0) - Params
public
function
__construct(
array
$params
= [])
{
foreach
(
$params
as
$key
=>
$value
) {
if
(method_exists(
$this
,
$key
)) {
$this
->
$key
(
$value
);
}
}
}
Assigns the properties of the current Request_Client to another Request_Client instance - used when setting up a subsequent request.
Request_Client
$client
required - $client
public
function
assign_client_properties(Request_Client
$client
)
{
$client
->cache(
$this
->cache());
$client
->follow(
$this
->follow());
$client
->follow_headers(
$this
->follow_headers());
$client
->header_callbacks(
$this
->header_callbacks());
$client
->max_callback_depth(
$this
->max_callback_depth());
$client
->callback_params(
$this
->callback_params());
}
Getter and setter for the internal caching engine, used to cache responses if available and valid.
HTTP_Cache
$cache
= NULL - Engine to use for caching HTTP_Cache
Request_Client
public
function
cache(HTTP_Cache
$cache
= null)
{
if
(
$cache
=== null)
return
$this
->_cache;
$this
->_cache =
$cache
;
return
$this
;
}
Getter/Setter for the callback depth property, which is used to track how many recursions have been executed within the current request execution.
int
$depth
= NULL - Current recursion depth Request_Client|int
public
function
callback_depth(
$depth
= null)
{
if
(
$depth
=== null)
return
$this
->_callback_depth;
$this
->_callback_depth =
$depth
;
return
$this
;
}
Getter/Setter for the callback_params array, which allows additional application-specific parameters to be shared with callbacks.
As with other Kohana setter/getters, usage is:
// Set full array
$client
->callback_params([
'foo'
=>
'bar'
]);
// Set single key
$client
->callback_params(
'foo'
,
'bar'
);
// Get full array
$params
=
$client
->callback_params();
// Get single key
$foo
=
$client
->callback_params(
'foo'
);
string|array
$param
= NULL - $param mixed
$value
= NULL - $value Request_Client|mixed
public
function
callback_params(
$param
= null,
$value
= null)
{
// Getter for full array
if
(
$param
=== null)
return
$this
->_callback_params;
// Setter for full array
if
(
is_array
(
$param
)) {
$this
->_callback_params =
$param
;
return
$this
;
}
// Getter for single value
elseif
(
$value
=== null) {
return
Arr::get(
$this
->_callback_params,
$param
);
}
// Setter for single value
else
{
$this
->_callback_params[
$param
] =
$value
;
return
$this
;
}
}
Processes the request, executing the controller action that handles this request, determined by the Route.
By default, the output from the controller is captured and returned, and no headers are sent.
$request
->execute();
Request
$request
required - $request Response
public
function
execute(Request
$request
)
{
// Prevent too much recursion of header callback requests
if
(
$this
->callback_depth() >
$this
->max_callback_depth())
throw
new
Request_Client_Recursion_Exception(
"Could not execute request to :uri - too many recursions after :depth requests"
, [
':uri'
=>
$request
->uri(),
':depth'
=>
$this
->callback_depth() - 1,
]);
// Execute the request and pass the currently used protocol
$orig_response
=
$response
= Response::factory([
'_protocol'
=>
$request
->protocol()]);
if
((
$cache
=
$this
->cache())
instanceof
HTTP_Cache)
return
$cache
->execute(
$this
,
$request
,
$response
);
$response
=
$this
->execute_request(
$request
,
$response
);
// Execute response callbacks
foreach
(
$this
->header_callbacks()
as
$header
=>
$callback
) {
if
(
$response
->headers(
$header
)) {
$cb_result
= call_user_func(
$callback
,
$request
,
$response
,
$this
);
if
(
$cb_result
instanceof
Request) {
// If the callback returns a request, automatically assign client params
$this
->assign_client_properties(
$cb_result
->client());
$cb_result
->client()->callback_depth(
$this
->callback_depth() + 1);
// Execute the request
$response
=
$cb_result
->execute();
}
elseif
(
$cb_result
instanceof
Response) {
// Assign the returned response
$response
=
$cb_result
;
}
// If the callback has created a new response, do not process any further
if
(
$response
!==
$orig_response
)
break
;
}
}
return
$response
;
}
Getter and setter for the follow redirects setting.
bool
$follow
= NULL - Boolean indicating if redirects should be followed bool
Request_Client
public
function
follow(
$follow
= null)
{
if
(
$follow
=== null)
return
$this
->_follow;
$this
->_follow =
$follow
;
return
$this
;
}
Getter and setter for the follow redirects headers array.
array
$follow_headers
= NULL - Array of headers to be re-used when following a Location header array
Request_Client
public
function
follow_headers(
$follow_headers
= null)
{
if
(
$follow_headers
=== null)
return
$this
->_follow_headers;
$this
->_follow_headers =
array_map
(
'strtolower'
,
$follow_headers
);
return
$this
;
}
Getter and setter for the header callbacks array.
Accepts an array with HTTP response headers as keys and a PHP callback function as values. These callbacks will be triggered if a response contains the given header and can either issue a subsequent request or manipulate the response as required.
By default, the Request_Client::on_header_location callback is assigned to the Location header to support automatic redirect following.
$client
->header_callbacks([
'Location'
=>
'Request_Client::on_header_location'
,
'WWW-Authenticate'
=>
function
(
$request
,
$response
,
$client
) {
return
$new_response
;
}
];
array
$header_callbacks
= NULL - Array of callbacks to trigger on presence of given headers Request_Client
public
function
header_callbacks(
$header_callbacks
= null)
{
if
(
$header_callbacks
=== null)
return
$this
->_header_callbacks;
$this
->_header_callbacks =
$header_callbacks
;
return
$this
;
}
Getter and setter for the maximum callback depth property.
This protects the main execution from recursive callback execution (eg following infinite redirects, conflicts between callbacks causing loops etc). Requests will only be allowed to nest to the level set by this param before execution is aborted with a Request_Client_Recursion_Exception.
int
$depth
= NULL - Maximum number of callback requests to execute before aborting Request_Client|int
public
function
max_callback_depth(
$depth
= null)
{
if
(
$depth
=== null)
return
$this
->_max_callback_depth;
$this
->_max_callback_depth =
$depth
;
return
$this
;
}
The default handler for following redirects, triggered by the presence of a Location header in the response.
The client's follow property must be set true and the HTTP response status one of 201, 301, 302, 303 or 307 for the redirect to be followed.
Request
$request
required - $request Response
$response
required - $response Request_Client
$client
required - $client
public
static
function
on_header_location(Request
$request
, Response
$response
, Request_Client
$client
)
{
// Do we need to follow a Location header ?
if
(
$client
->follow() AND in_array(
$response
->status(), [201, 301, 302, 303, 307])) {
// Figure out which method to use for the follow request
switch
(
$response
->status()) {
default
:
case
301:
case
307:
$follow_method
=
$request
->method();
break
;
case
201:
case
303:
$follow_method
= Request::GET;
break
;
case
302:
// Cater for sites with broken HTTP redirect implementations
if
(
$client
->strict_redirect()) {
$follow_method
=
$request
->method();
}
else
{
$follow_method
= Request::GET;
}
break
;
}
// Prepare the additional request, copying any follow_headers that were present on the original request
$orig_headers
=
$request
->headers()->getArrayCopy();
$follow_header_keys
=
array_intersect
(
array_keys
(
$orig_headers
),
$client
->follow_headers());
$follow_headers
= \Arr::extract(
$orig_headers
,
$follow_header_keys
);
$follow_request
= Request::factory(
$response
->headers(
'Location'
))
->method(
$follow_method
)
->headers(
$follow_headers
);
if
(
$follow_method
!== Request::GET) {
$follow_request
->body(
$request
->body());
}
return
$follow_request
;
}
return
null;
}
Getter and setter for the strict redirects setting
HTTP/1.1 specifies that a 302 redirect should be followed using the original request method. However, the vast majority of clients and servers get this wrong, with 302 widely used for 'POST - 302 redirect - GET' patterns. By default, Kohana's client is fully compliant with the HTTP spec. Some non-compliant third party sites may require that strict_redirect is set false to force the client to switch to GET following a 302 response.
bool
$strict_redirect
= NULL - Boolean indicating if 302 redirects should be followed with the original method Request_Client
public
function
strict_redirect(
$strict_redirect
= null)
{
if
(
$strict_redirect
=== null)
return
$this
->_strict_redirect;
$this
->_strict_redirect =
$strict_redirect
;
return
$this
;
}