Skip to content

Instantly share code, notes, and snippets.

@jdmaturen
Created January 18, 2012 19:41
Show Gist options
  • Save jdmaturen/1635102 to your computer and use it in GitHub Desktop.
Save jdmaturen/1635102 to your computer and use it in GitHub Desktop.
<?php
// … 
/**
* Default, shared method for authenticating a connection to AWS.
*
* @param string $operation (Required) Indicates the operation to perform.
* @param array $payload (Required) An associative array of parameters for authenticating. See the individual methods for allowed keys.
* @return CFResponse Object containing a parsed HTTP response.
*/
public function authenticate($operation, $payload)
{
$original_payload = $payload;
$method_arguments = func_get_args();
$curlopts = array();
$return_curl_handle = false;
if (substr($operation, 0, strlen($this->operation_prefix)) !== $this->operation_prefix)
{
$operation = $this->operation_prefix . $operation;
}
// Extract the custom CURLOPT settings from the payload
if (is_array($payload) && isset($payload['curlopts']))
{
$curlopts = $payload['curlopts'];
unset($payload['curlopts']);
}
// Determine whether the response or curl handle should be returned
if (is_array($payload) && isset($payload['returnCurlHandle']))
{
$return_curl_handle = isset($payload['returnCurlHandle']) ? $payload['returnCurlHandle'] : false;
unset($payload['returnCurlHandle']);
}
// Use the caching flow to determine if we need to do a round-trip to the server.
if ($this->use_cache_flow)
{
// Generate an identifier specific to this particular set of arguments.
$cache_id = $this->key . '_' . get_class($this) . '_' . $operation . '_' . sha1(serialize($method_arguments));
// Instantiate the appropriate caching object.
$this->cache_object = new $this->cache_class($cache_id, $this->cache_location, $this->cache_expires, $this->cache_compress);
if ($this->delete_cache)
{
$this->use_cache_flow = false;
$this->delete_cache = false;
return $this->cache_object->delete();
}
// Invoke the cache callback function to determine whether to pull data from the cache or make a fresh request.
$data = $this->cache_object->response_manager(array($this, 'cache_callback'), $method_arguments);
// Parse the XML body
$data = $this->parse_callback($data);
// End!
return $data;
}
/*%******************************************************************************************%*/
// Signer
$signer = new $this->auth_class($this->hostname, $operation, $payload, $this->credentials);
$signer->key = $this->key;
$signer->secret_key = $this->secret_key;
$signer->auth_token = $this->auth_token;
$signer->api_version = $this->api_version;
$signer->utilities_class = $this->utilities_class;
$signer->request_class = $this->request_class;
$signer->response_class = $this->response_class;
$signer->use_ssl = $this->use_ssl;
$signer->proxy = $this->proxy;
$signer->util = $this->util;
$signer->registered_streaming_read_callback = $this->registered_streaming_read_callback;
$signer->registered_streaming_write_callback = $this->registered_streaming_write_callback;
$request = $signer->authenticate();
// Update RequestCore settings
$request->request_class = $this->request_class;
$request->response_class = $this->response_class;
$request->ssl_verification = $this->ssl_verification;
/*%******************************************************************************************%*/
// Debug mode
if ($this->debug_mode)
{
$request->debug_mode = $this->debug_mode;
}
// Set custom CURLOPT settings
if (count($curlopts))
{
$request->set_curlopts($curlopts);
}
// Manage the (newer) batch request API or the (older) returnCurlHandle setting.
if ($this->use_batch_flow)
{
$handle = $request->prep_request();
$this->batch_object->add($handle);
$this->use_batch_flow = false;
return $handle;
}
elseif ($return_curl_handle)
{
return $request->prep_request();
}
// Send!
$request->send_request();
// Prepare the response.
$headers = $request->get_response_header();
$headers['x-aws-stringtosign'] = $signer->string_to_sign;
if (isset($signer->canonical_request))
{
$headers['x-aws-canonicalrequest'] = $signer->canonical_request;
}
$headers['x-aws-request-headers'] = $request->request_headers;
$headers['x-aws-body'] = $signer->querystring;
$data = new $this->response_class($headers, ($this->parse_the_response === true) ? $this->parse_callback($request->get_response_body()) : $request->get_response_body(), $request->get_response_code());
// Was it Amazon's fault the request failed? Retry the request until we reach $max_retries.
if (
(integer) $request->get_response_code() === 500 || // Internal Error (presumably transient)
(integer) $request->get_response_code() === 503) // Service Unavailable (presumably transient)
{
if ($this->redirects <= $this->max_retries)
{
// Exponential backoff
$delay = (integer) (pow(4, $this->redirects) * 100000);
usleep($delay);
$this->redirects++;
$data = $this->authenticate($operation, $original_payload);
}
}
// DynamoDB has custom logic
elseif (
(integer) $request->get_response_code() === 400 &&
stripos((string) $request->get_response_body(), 'com.amazonaws.dynamodb.') !== false && (
stripos((string) $request->get_response_body(), 'ProvisionedThroughputExceededException') !== false
)
)
{
if ($this->redirects === 0)
{
$this->redirects++;
$data = $this->authenticate($operation, $original_payload);
}
elseif ($this->redirects <= max($this->max_retries, 10))
{
// Exponential backoff
$delay = (integer) (pow(2, ($this->redirects - 1)) * 50000);
usleep($delay);
$this->redirects++;
$data = $this->authenticate($operation, $original_payload);
}
}
$this->redirects = 0;
return $data;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment