authenticate ( $operation, $payload )

Default, shared method for authenticating a connection to AWS.

Access

public

Parameters

Parameter

Type

Required

Description

$operation

string

Required

Indicates the operation to perform.

$payload

array

Required

An associative array of parameters for authenticating. See the individual methods for allowed keys.

Returns

Type

Description

CFResponse

Object containing a parsed HTTP response.

Source

Method defined in sdk.class.php | Toggle source view (178 lines) | View on GitHub

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());

    $response_body = (string) $request->get_response_body();

    // 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 additional, custom logic for retrying requests
    else
    {
        // If the request to DynamoDB was throttled, we need to retry
        $need_to_retry_dynamodb_request = (
            (integer) $request->get_response_code() === 400 &&
            stripos($response_body, 'com.amazonaws.dynamodb.') !== false &&
            stripos($response_body, 'ProvisionedThroughputExceededException') !== false
        );

        // If the CRC32 of the response does not match the expected value, we need to retry
        $response_headers = $request->get_response_header();
        if (!$need_to_retry_dynamodb_request && isset($response_headers['x-amz-crc32']))
        {
            $crc32_expected = $response_headers['x-amz-crc32'];
            $crc32_actual = hexdec(hash('crc32b', $response_body));
            $need_to_retry_dynamodb_request = ($crc32_expected != $crc32_actual);
        }

        // Perform retry if necessary using a more aggressive exponential backoff
        if ($need_to_retry_dynamodb_request)
        {
            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;
}

Copyright © 2010–2013 Amazon Web Services, LLC


Feedback