You are here

public function AcquiaPurgeExecutorBase::requestsExecute in Acquia Purge 7

Execute a series of HTTP requests efficiently through cURL's multi handler.

Parameters

AcquiaPurgeExecutorRequestInterface[] $requests: Unassociative list of request objects created by ::getRequest(). The properties 'scheme', 'method', 'uri' are used for executing the request. The properties 'result', 'error_curl', 'response_code' and 'error_debug' are updated during execution.

string $no_ssl_verify: Skip host and peer verification, don't use for requests that include sensitive data (e.g. API keys).

Overrides AcquiaPurgeExecutorInterface::requestsExecute

1 call to AcquiaPurgeExecutorBase::requestsExecute()
AcquiaPurgeExecutorAcquia::invalidate in lib/executor/AcquiaPurgeExecutorAcquia.php
Invalidate one or multiple paths from an external layer.

File

lib/executor/AcquiaPurgeExecutorBase.php, line 114
Contains AcquiaPurgeExecutorBase.

Class

AcquiaPurgeExecutorBase
Provides an executor, which is responsible for taking a set of invalidation objects and wiping these paths/URLs from an external cache.

Code

public function requestsExecute($requests, $no_ssl_verify = FALSE) {
  $single_mode = count($requests) === 1;
  $processed = array();

  // Initialize the cURL multi handler.
  if (!$single_mode) {
    $curl_multi = curl_multi_init();
  }

  // Enter our event loop and keep on requesting until $unprocessed is empty.
  $unprocessed = count($requests);
  while ($unprocessed > 0) {

    // Group requests per sets that we can run in parallel.
    for ($i = 0; $i < AcquiaPurgeCapacity::HTTP_PARALLEL_REQUESTS; $i++) {
      if ($r = array_shift($requests)) {
        $r->curl = curl_init();

        // Instantiate the cURL resource and configure its runtime parameters.
        curl_setopt($r->curl, CURLOPT_URL, $r->uri);
        curl_setopt($r->curl, CURLOPT_HTTPHEADER, $r->headers);
        curl_setopt($r->curl, CURLOPT_CUSTOMREQUEST, $r->method);
        curl_setopt($r->curl, CURLOPT_FAILONERROR, TRUE);
        curl_setopt($r->curl, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($r->curl, CURLOPT_TIMEOUT, AcquiaPurgeCapacity::HTTP_REQUEST_TIMEOUT);

        // For SSL purging, we disable SSL host and peer verification. This
        // should trigger red flags to the security concerned user, but it
        // also avoids purges to fail on sites with self-signed certs. This
        // therefore is a risk worth taking in return for a better user
        // experience as compromised cache invalidation requests couldn't
        // cause much harm anyway.
        if ($no_ssl_verify && $r->scheme === 'https') {
          curl_setopt($r->curl, CURLOPT_SSL_VERIFYHOST, FALSE);
          curl_setopt($r->curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        }

        // Add our handle to the multiple cURL handle.
        if (!$single_mode) {
          curl_multi_add_handle($curl_multi, $r->curl);
        }
        $processed[] = $r;
        $unprocessed--;
      }
    }

    // Execute the created handles in parallel.
    if (!$single_mode) {
      $active = NULL;
      do {
        $mrc = curl_multi_exec($curl_multi, $active);
      } while ($mrc == CURLM_CALL_MULTI_PERFORM);
      while ($active && $mrc == CURLM_OK) {
        if (curl_multi_select($curl_multi) != -1) {
          do {
            $mrc = curl_multi_exec($curl_multi, $active);
          } while ($mrc == CURLM_CALL_MULTI_PERFORM);
        }
      }
    }
    else {
      curl_exec($processed[0]->curl);
      $single_info = array(
        'result' => curl_errno($processed[0]->curl),
      );
    }

    // Iterate the set of results and fetch cURL result and resultcodes. Only
    // process those with the 'curl' property as the property will be removed.
    foreach ($processed as $i => $r) {
      if (!isset($r->curl)) {
        continue;
      }
      $info = $single_mode ? $single_info : curl_multi_info_read($curl_multi);
      $processed[$i]->result = $info['result'] == CURLE_OK ? TRUE : FALSE;
      $processed[$i]->error_curl = $info['result'];
      $processed[$i]->response_code = curl_getinfo($r->curl, CURLINFO_HTTP_CODE);

      // Collect debugging information if necessary.
      $processed[$i]->error_debug = '';
      if (!$processed[$i]->result) {
        $debug = array(
          'method' => $r->method,
          'headers' => $r->headers,
        );
        $debug = array_merge($debug, curl_getinfo($r->curl));
        unset($debug['certinfo']);
        $processed[$i]->error_debug = $this
          ->exportDebugSymbols($debug);
      }

      // Remove the handle if parallel processing occurred.
      if (!$single_mode) {
        curl_multi_remove_handle($curl_multi, $r->curl);
      }
      curl_close($r->curl);
      $r->curl = NULL;
    }
  }
  if (!$single_mode) {
    curl_multi_close($curl_multi);
  }
}