You are here

class SearchApiAcquiaSearchConnectionV3 in Acquia Search for Search API 7.2

Starting point for the Solr API. Represents a Solr server resource and has methods for pinging, adding, deleting, committing, optimizing and searching.

Hierarchy

Expanded class hierarchy of SearchApiAcquiaSearchConnectionV3

File

includes/v3/SearchApiAcquiaSearchConnectionV3.php, line 8

View source
class SearchApiAcquiaSearchConnectionV3 extends SearchApiSolrConnection {

  /**
   * {@inheritdoc}
   */
  public function makeServletRequest($servlet, $params = [], $options = []) {
    $params += [
      'wt' => 'json',
    ];
    $nonce = SearchApiAcquiaCrypt::randomBytes(24);
    $url = $this
      ->constructUrl($servlet, $params);
    $this
      ->prepareRequest($url, $options, $nonce);
    $response = $this
      ->makeHttpRequest($url, $options);
    $response = $this
      ->checkResponse($response);
    return $this
      ->authenticateResponse($response, $nonce, $url);
  }

  /**
   * {@inheritdoc}
   */
  protected function sendRawGet($url, $options = []) {

    // phpcs:ignore
    $nonce = SearchApiAcquiaCrypt::randomBytes(24);
    $this
      ->prepareRequest($url, $options, $nonce);
    $response = $this
      ->makeHttpRequest($url, $options);
    $response = $this
      ->checkResponse($response);
    return $this
      ->authenticateResponse($response, $nonce, $url);
  }

  /**
   * {@inheritdoc}
   */
  protected function sendRawPost($url, $options = []) {

    // phpcs:ignore
    $options['method'] = 'POST';
    if (!isset($options['headers']['Content-Type'])) {
      $options['headers']['Content-Type'] = 'text/xml; charset=UTF-8';
    }
    $nonce = SearchApiAcquiaCrypt::randomBytes(24);
    $this
      ->prepareRequest($url, $options, $nonce);
    $response = $this
      ->makeHttpRequest($url, $options);
    $response = $this
      ->checkResponse($response);
    return $this
      ->authenticateResponse($response, $nonce, $url);
  }

  /**
   * Prepares request before send.
   *
   * @param string $url
   *   Request URL.
   * @param array $options
   *   Request options.
   * @param string $nonce
   *   Nonce.
   *
   * @throws \Exception
   */
  protected function prepareRequest(&$url, array &$options, $nonce) {
    $url = $this
      ->adjustUrl($url);
    if (!isset($options['headers'])) {
      $options['headers'] = [];
    }
    $string = !empty($options['data']) ? $options['data'] : NULL;
    $options['headers']['Cookie'] = $this
      ->createAuthCookie($url, $nonce, $string);
    $options['headers'] += $this
      ->addUserAgentHeader();
  }

  /**
   * Prepares URL parameters before request.
   *
   * @param string $url
   *   URL.
   *
   * @return string
   *   Adjusted URL.
   */
  protected function adjustUrl($url) {
    $url_components = parse_url($url);
    if (isset($url_components['scheme'])) {
      $url_components['scheme'] = sprintf('%s://', $url_components['scheme']);
    }
    if (isset($url_components['port'])) {
      $url_components['port'] = sprintf(':%s', $url_components['port']);
    }
    if (!isset($url_components['query'])) {
      $url_components['query'] = '';
    }
    $query_pieces = drupal_get_query_array($url_components['query']);
    $query_pieces['request_id'] = uniqid();
    $query_string = drupal_http_build_query($query_pieces);
    $url_components['query'] = sprintf('?%s', $query_string);
    $url = implode('', $url_components);
    return $url;
  }

  /**
   * Builds user-agent header.
   *
   * @return array
   *   User-agent header.
   */
  protected function addUserAgentHeader() {
    $agent = 'search_api_acquia/' . variable_get('search_api_acquia_version', '7.x');
    return [
      'User-Agent' => $agent,
    ];
  }

  /**
   * Makes authentication checks.
   *
   * @param object $response
   *   Response object.
   * @param string $nonce
   *   Nonce.
   * @param string $url
   *   Request URL.
   *
   * @return mixed
   *   Throws exception in case of authentication check fail.
   *
   * @throws \Exception
   */
  protected function authenticateResponse($response, $nonce, $url) {
    $hmac = $this
      ->extractHmac($response->headers);
    if (!$this
      ->isValidResponse($hmac, $nonce, $response->data, NULL)) {
      throw new Exception('Authentication of search content failed url: ' . $url);
    }
    return $response;
  }

  /**
   * Creates auth cookie.
   *
   * @param string $url
   *   Request URL.
   * @param string $nonce
   *   Nonce.
   * @param string $string
   *   Payload.
   *
   * @return string
   *   Cookie.
   */
  private function createAuthCookie($url, $nonce, $string = '') {
    if (!empty($string)) {
      $auth_string = $this
        ->buildAuthString($string, $nonce);
      return $auth_string;
    }
    $uri = parse_url($url);
    $path = isset($uri['path']) ? $uri['path'] : '/';
    $query = isset($uri['query']) ? '?' . $uri['query'] : '';
    $auth_string = $this
      ->buildAuthString($path . $query, $nonce);
    return $auth_string;
  }

  /**
   * Builds auth string.
   *
   * @param string $string
   *   Payload.
   * @param string $nonce
   *   Nonce.
   *
   * @return string
   *   Auth string.
   */
  private function buildAuthString($string, $nonce) {
    $api = SearchApiAcquiaApi::getFromSettings();
    if (empty($api)) {
      return '';
    }
    $preferredCoreService = $api
      ->getPreferredCoreService();
    if (empty($preferredCoreService
      ->isPreferredCoreAvailable())) {
      return '';
    }
    $index = $preferredCoreService
      ->getPreferredCore();
    $derived_key = $this
      ->createDerivedKey($index['data']['product_policies']['salt'], $index['data']['key'], $index['data']['secret_key']);
    $hmac = hash_hmac('sha1', REQUEST_TIME . $nonce . $string, $derived_key);
    return sprintf('acquia_solr_time=%s; acquia_solr_nonce=%s; acquia_solr_hmac=%s;', REQUEST_TIME, $nonce, $hmac);
  }

  /**
   * Creates derived key.
   *
   * @param string $salt
   *   Key salt.
   * @param string $index_id
   *   Index ID.
   * @param string $key
   *   Secret key.
   *
   * @return string
   *   Derived key.
   */
  private function createDerivedKey($salt, $index_id, $key) {
    $pad_length = 80;
    $derivation_string = sprintf('%ssolr%s', $index_id, $salt);
    $data = str_pad($derivation_string, $pad_length, $derivation_string);
    $hmac = hash_hmac('sha1', $data, $key);
    return $hmac;
  }

  /**
   * Extracts HMAC value from headers.
   *
   * @param array $headers
   *   Headers list.
   *
   * @return string
   *   HMAC string.
   */
  private function extractHmac(array $headers) {
    $reg = [];
    if (is_array($headers)) {
      foreach ($headers as $name => $value) {
        if (strtolower($name) === 'pragma' && preg_match('/hmac_digest=([^;]+);/i', $value, $reg)) {
          return trim($reg[1]);
        }
      }
    }
    return '';
  }

  /**
   * Validates response.
   *
   * @param string $hmac
   *   HMAC string.
   * @param string $nonce
   *   Nonce.
   * @param string $string
   *   Payload.
   * @param string|null $derived_key
   *   Derived key.
   * @param string|null $env_id
   *   Search environment ID.
   *
   * @return bool
   *   TRUE if request is valid, otherwise - FALSE.
   */
  private function isValidResponse($hmac, $nonce, $string, $derived_key = NULL) {
    if (empty($derived_key)) {
      $api = SearchApiAcquiaApi::getFromSettings();
      if (empty($api)) {
        return FALSE;
      }
      $core = $api
        ->getPreferredCoreService()
        ->getPreferredCore();
      if (empty($core['data'])) {
        return FALSE;
      }
      $derived_key = $this
        ->createDerivedKey($core['data']['product_policies']['salt'], $core['data']['key'], $core['data']['secret_key']);
    }
    return $hmac === hash_hmac('sha1', $nonce . $string, $derived_key);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
SearchApiAcquiaSearchConnectionV3::addUserAgentHeader protected function Builds user-agent header.
SearchApiAcquiaSearchConnectionV3::adjustUrl protected function Prepares URL parameters before request.
SearchApiAcquiaSearchConnectionV3::authenticateResponse protected function Makes authentication checks.
SearchApiAcquiaSearchConnectionV3::buildAuthString private function Builds auth string.
SearchApiAcquiaSearchConnectionV3::createAuthCookie private function Creates auth cookie.
SearchApiAcquiaSearchConnectionV3::createDerivedKey private function Creates derived key.
SearchApiAcquiaSearchConnectionV3::extractHmac private function Extracts HMAC value from headers.
SearchApiAcquiaSearchConnectionV3::isValidResponse private function Validates response.
SearchApiAcquiaSearchConnectionV3::makeServletRequest public function Makes a request to a servlet (a path) that's not a standard path. Overrides SearchApiSolrConnection::makeServletRequest
SearchApiAcquiaSearchConnectionV3::prepareRequest protected function Prepares request before send.
SearchApiAcquiaSearchConnectionV3::sendRawGet protected function Sends a GET request to the Solr server. Overrides SearchApiSolrConnection::sendRawGet
SearchApiAcquiaSearchConnectionV3::sendRawPost protected function Sends a PUT request to the Solr server. Overrides SearchApiSolrConnection::sendRawPost
SearchApiSolrConnection::$base_url protected property The Solr server's URL.
SearchApiSolrConnection::$http_auth protected property HTTP Basic Authentication header to set for requests to the Solr server.
SearchApiSolrConnection::$luke protected property Cache for the metadata from admin/luke.
SearchApiSolrConnection::$options protected property The options passed when creating this connection.
SearchApiSolrConnection::$soft_commit protected property Flag that denotes whether to use soft commits for Solr 4.x.
SearchApiSolrConnection::$stats protected property Cache for information about the Solr core.
SearchApiSolrConnection::$stream_context protected property The stream context to use for requests to the Solr server.
SearchApiSolrConnection::$system_info protected property Cache for system information.
SearchApiSolrConnection::$update_url protected property Cached URL to the update servlet.
SearchApiSolrConnection::addDocuments public function Adds an array of Solr Documents to the index all at once Overrides SearchApiSolrConnectionInterface::addDocuments
SearchApiSolrConnection::checkResponse protected function Checks the reponse code and throws an exception if it's not 200.
SearchApiSolrConnection::clearCache public function Clears the cached Solr data. Overrides SearchApiSolrConnectionInterface::clearCache
SearchApiSolrConnection::commit public function Sends a commit command to the Solr server. Overrides SearchApiSolrConnectionInterface::commit
SearchApiSolrConnection::constructUrl protected function Returns the HTTP URL for a certain servlet on the Solr server.
SearchApiSolrConnection::deleteById public function Sends a delete request based on a document ID. Overrides SearchApiSolrConnectionInterface::deleteById
SearchApiSolrConnection::deleteByMultipleIds public function Sends a delete request for several documents, based on the document IDs. Overrides SearchApiSolrConnectionInterface::deleteByMultipleIds
SearchApiSolrConnection::deleteByQuery public function Sends a delete request for all documents that match the given Solr query. Overrides SearchApiSolrConnectionInterface::deleteByQuery
SearchApiSolrConnection::escape public static function Escapes special characters from a Solr query. Overrides SearchApiSolrConnectionInterface::escape
SearchApiSolrConnection::escapeFieldName public static function Escapes a Search API field name for passing to Solr. Overrides SearchApiSolrConnectionInterface::escapeFieldName
SearchApiSolrConnection::escapePhrase public static function Escapes a string that should be included in a Solr phrase. Overrides SearchApiSolrConnectionInterface::escapePhrase
SearchApiSolrConnection::FILE_SERVLET constant Path to the file servlet.
SearchApiSolrConnection::getBaseUrl public function Gets the base URL of the Solr server. Overrides SearchApiSolrConnectionInterface::getBaseUrl
SearchApiSolrConnection::getCacheId protected function Computes the cache ID to use for this connection.
SearchApiSolrConnection::getFields public function Get metadata about fields in the Solr/Lucene index. Overrides SearchApiSolrConnectionInterface::getFields
SearchApiSolrConnection::getLuke public function Gets meta-data about the index. Overrides SearchApiSolrConnectionInterface::getLuke
SearchApiSolrConnection::getSoftCommit public function Tells whether this connection will use soft commits when comitting. Overrides SearchApiSolrConnectionInterface::getSoftCommit
SearchApiSolrConnection::getSolrVersion public function Gets the current solr version. Overrides SearchApiSolrConnectionInterface::getSolrVersion
SearchApiSolrConnection::getStats public function Gets information about the Solr core. Overrides SearchApiSolrConnectionInterface::getStats
SearchApiSolrConnection::getStatsSummary public function Gets summary information about the Solr Core. Overrides SearchApiSolrConnectionInterface::getStatsSummary
SearchApiSolrConnection::getStreamContext public function Returns the stream context to use for requests to the Solr server. Overrides SearchApiSolrConnectionInterface::getStreamContext
SearchApiSolrConnection::getSystemInfo public function Implements SearchApiSolrConnectionInterface::getSystemInfo(). Overrides SearchApiSolrConnectionInterface::getSystemInfo
SearchApiSolrConnection::httpBuildQuery protected function Generates an URL-encoded query string.
SearchApiSolrConnection::logResponse protected function Logs a Solr response object.
SearchApiSolrConnection::LUKE_SERVLET constant Path to the luke servlet.
SearchApiSolrConnection::makeHttpRequest protected function Sends an HTTP request to Solr.
SearchApiSolrConnection::NAMED_LIST_FORMAT constant Defines how NamedLists should be formatted in the output.
SearchApiSolrConnection::optimize public function Sends an optimize command to the Solr server. Overrides SearchApiSolrConnectionInterface::optimize
SearchApiSolrConnection::optimizeOrCommit protected function Sends a commit or optimize command to the Solr server.
SearchApiSolrConnection::phrase public static function Converts a string to a Solr phrase. Overrides SearchApiSolrConnectionInterface::phrase
SearchApiSolrConnection::ping public function Calls the /admin/ping servlet, to test the connection to the server. Overrides SearchApiSolrConnectionInterface::ping
SearchApiSolrConnection::PING_SERVLET constant Path to the ping servlet.
SearchApiSolrConnection::search public function Executes a search on the Solr server. Overrides SearchApiSolrConnectionInterface::search
SearchApiSolrConnection::SEARCH_SERVLET constant Path to the search servlet.
SearchApiSolrConnection::setBaseUrl public function Sets the base URL of the Solr server. Overrides SearchApiSolrConnectionInterface::setBaseUrl
SearchApiSolrConnection::setLuke protected function Sets $this->luke with the metadata about the index from admin/luke.
SearchApiSolrConnection::setSoftCommit public function Sets whether this connection will use soft commits when comitting. Overrides SearchApiSolrConnectionInterface::setSoftCommit
SearchApiSolrConnection::setStats protected function Stores information about the Solr core in $this->stats.
SearchApiSolrConnection::setStreamContext public function Set the stream context to use for requests to the Solr server. Overrides SearchApiSolrConnectionInterface::setStreamContext
SearchApiSolrConnection::setSystemInfo protected function Call the /admin/system servlet to retrieve system information.
SearchApiSolrConnection::STATS_SERVLET constant Path to the stats servlet.
SearchApiSolrConnection::STATS_SERVLET_4 constant Path to the stats servlet for Solr 4.x servers.
SearchApiSolrConnection::SYSTEM_SERVLET constant Path to the system servlet.
SearchApiSolrConnection::update public function Sends a raw update request to the Solr server. Overrides SearchApiSolrConnectionInterface::update
SearchApiSolrConnection::UPDATE_SERVLET constant Path to the update servlet.
SearchApiSolrConnection::__construct public function Implements SearchApiSolrConnectionInterface::__construct(). Overrides SearchApiSolrConnectionInterface::__construct