diff --git a/modules/pantheon/pantheon_apachesolr/Pantheon_Search_Api_Solr_Service.php b/modules/pantheon/pantheon_apachesolr/Pantheon_Search_Api_Solr_Service.php index be4533bc954..5f2adce1daa 100644 --- a/modules/pantheon/pantheon_apachesolr/Pantheon_Search_Api_Solr_Service.php +++ b/modules/pantheon/pantheon_apachesolr/Pantheon_Search_Api_Solr_Service.php @@ -1,4 +1,112 @@ setStreamContext( + stream_context_create( + array( + 'ssl' => array( + 'local_cert' => '../certs/binding.pem', + ) + ) + ) + ); + + // Adding in general settings for Search API + $options += array( + 'scheme' => 'http', + 'host' => 'localhost', + 'port' => 8983, + 'path' => 'solr', + 'http_user' => NULL, + 'http_pass' => NULL, + 'http_method' => 'POST', + 'local_cert'=> NULL, + ); + $this->options = $options; + + $path = '/' . trim($options['path'], '/') . '/'; + $this->base_url = $options['scheme'] . '://' . $options['host'] . ':' . $options['port'] . $path; + + // Make sure we always have a valid method set, default to POST. + $this->method = $options['http_method'] == 'GET' ? 'GET' : 'POST'; + + // Set HTTP Basic Authentication parameter, if login data was set. + if (strlen($options['http_user']) && strlen($options['http_pass'])) { + $this->http_auth = 'Basic ' . base64_encode($options['http_user'] . ':' . $options['http_pass']); + } + } + + /** + * Sends an HTTP request to Solr. + * + * This is just a wrapper around drupal_http_request(). + * + * Overridden by Pantheon to set a timeout and possibly other improvements. + */ + protected function makeHttpRequest($url, array $options = array()) { + if (empty($options['method']) || $options['method'] == 'GET' || $options['method'] == 'HEAD') { + // Make sure we are not sending a request body. + $options['data'] = NULL; + } + if ($this->http_auth) { + $options['headers']['Authorization'] = $this->http_auth; + } + if ($this->stream_context) { + $options['context'] = $this->stream_context; + } + // Customize timout. + $options['timeout'] = 5; + + $result = drupal_http_request($url, $options); + + if (!isset($result->code) || $result->code < 0) { + $result->code = 0; + $result->status_message = 'Request failed'; + $result->protocol = 'HTTP/1.0'; + } + // Additional information may be in the error property. + if (isset($result->error)) { + $result->status_message .= ': ' . check_plain($result->error); + } + + if (!isset($result->data)) { + $result->data = ''; + $result->response = NULL; + } + else { + $response = json_decode($result->data); + if (is_object($response)) { + foreach ($response as $key => $value) { + $result->$key = $value; + } + } + } + + return $result; + } + +} + +class PantheonApachesolrSearchApiSolrService extends SearchApiSolrService { + + protected $connection_class = 'PantheonApachesolrSearchApiSolrConnection'; + +} + +/** + * Legacy Supported Class for RC2 + */ class PantheonSearchApiSolrService extends SearchApiSolrConnection { /** @@ -36,147 +144,151 @@ public function __construct(array $options) { * * Uses curl() for sending the request with certificate auth */ -class PanteheonSearchApiSolrHttpTransport extends Apache_Solr_HttpTransport_Abstract { - public function __construct() { - // Nothing to see here. - } +if (class_exists('Apache_Solr_HttpTransport_Abstract')) { - /** - * Perform a GET HTTP operation with an optional timeout and return the response - * contents, use getLastResponseHeaders to retrieve HTTP headers - * - * @param string $url - * @param float $timeout - * @return Apache_Solr_HttpTransport_Response HTTP response - */ - public function performGetRequest($url, $timeout = FALSE) { - return $this->performHttpRequest('GET', $url, $timeout); - } - - /** - * Perform a HEAD HTTP operation with an optional timeout and return the response - * headers - NOTE: head requests have no response body - * - * @param string $url - * @param float $timeout - * @return Apache_Solr_HttpTransport_Response HTTP response - */ - public function performHeadRequest($url, $timeout = FALSE) { - return $this->performHttpRequest('HEAD', $url, $timeout); - } + class PanteheonSearchApiSolrHttpTransport extends Apache_Solr_HttpTransport_Abstract { - /** - * Perform a POST HTTP operation with an optional timeout and return the response - * contents, use getLastResponseHeaders to retrieve HTTP headers - * - * @param string $url - * @param string $rawPost - * @param string $contentType - * @param float $timeout - * @return Apache_Solr_HttpTransport_Response HTTP response - */ - public function performPostRequest($url, $rawPost, $contentType, $timeout = FALSE) { - return $this->performHttpRequest('POST', $url, $timeout, $rawPost, $contentType); - } - - /** - * Helper method for making an HTTP request. - */ - protected function performHttpRequest($method, $url, $timeout, $rawPost = NULL, $contentType = NULL) { - // The _constructUrl() in Apache_Solr_Service hard codes http like a boss. - $url = str_replace('http://', 'https://', $url); - // Kludgy workaround of double-get-arging. - // https://index.live.getpantheon.com:449/sites/self/environments/dev/index/admin/ping?q=id:1?q=id:1 - // WHY ARG WHY!?!?! - $parts = explode('?', $url); - $url = $parts[0] .'?'. $parts[1]; - $client_cert = '../certs/binding.pem'; - $port = 449; - $ch = curl_init(); - curl_setopt($ch, CURLOPT_SSLCERT, $client_cert); - - $opts = pantheon_apachesolr_curlopts(); - $opts[CURLOPT_URL] = $url; - $opts[CURLOPT_PORT] = $port; - - if ($timeout) { - $opts[CURLOPT_CONNECTTIMEOUT] = $timeout; + public function __construct() { + // Nothing to see here. } - curl_setopt_array($ch, $opts); - // If we are doing a delete request... - if ($method == 'DELETE') { - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE"); + /** + * Perform a GET HTTP operation with an optional timeout and return the response + * contents, use getLastResponseHeaders to retrieve HTTP headers + * + * @param string $url + * @param float $timeout + * @return Apache_Solr_HttpTransport_Response HTTP response + */ + public function performGetRequest($url, $timeout = FALSE) { + return $this->performHttpRequest('GET', $url, $timeout); } - // If we are doing a put request... - if ($method == 'PUT') { - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); - } - // If we are doing a put request... - if ($method == 'POST') { - curl_setopt($ch, CURLOPT_POST, 1); + + /** + * Perform a HEAD HTTP operation with an optional timeout and return the response + * headers - NOTE: head requests have no response body + * + * @param string $url + * @param float $timeout + * @return Apache_Solr_HttpTransport_Response HTTP response + */ + public function performHeadRequest($url, $timeout = FALSE) { + return $this->performHttpRequest('HEAD', $url, $timeout); } - if ($rawPost) { - curl_setopt($ch, CURLOPT_POSTFIELDS, $rawPost); + + /** + * Perform a POST HTTP operation with an optional timeout and return the response + * contents, use getLastResponseHeaders to retrieve HTTP headers + * + * @param string $url + * @param string $rawPost + * @param string $contentType + * @param float $timeout + * @return Apache_Solr_HttpTransport_Response HTTP response + */ + public function performPostRequest($url, $rawPost, $contentType, $timeout = FALSE) { + return $this->performHttpRequest('POST', $url, $timeout, $rawPost, $contentType); } - $response = curl_exec($ch); + /** + * Helper method for making an HTTP request. + */ + protected function performHttpRequest($method, $url, $timeout, $rawPost = NULL, $contentType = NULL) { + // The _constructUrl() in Apache_Solr_Service hard codes http like a boss. + $url = str_replace('http://', 'https://', $url); + // Kludgy workaround of double-get-arging. + // https://index.live.getpantheon.com:449/sites/self/environments/dev/index/admin/ping?q=id:1?q=id:1 + // WHY ARG WHY!?!?! + $parts = explode('?', $url); + $url = $parts[0] .'?'. $parts[1]; + $client_cert = '../certs/binding.pem'; + $port = 449; + $ch = curl_init(); + curl_setopt($ch, CURLOPT_SSLCERT, $client_cert); - if ($response == NULL) { - // TODO; better error handling - watchdog('pantheon_apachesolr', "Error !error connecting to !url on port !port", array('!error' => curl_error($ch), '!url' => $url, '!port' => $port), WATCHDOG_ERROR); - } - else { - // mimick the $result object from drupal_http_request() - // TODO; better error handling - $result = new stdClass(); - list($split, $result->data) = explode("\r\n\r\n", $response, 2); - $split = preg_split("/\r\n|\n|\r/", $split); - list($result->protocol, $result->code, $result->status_message) = explode(' ', trim(array_shift($split)), 3); - // Parse headers. - $result->headers = array(); - while ($line = trim(array_shift($split))) { - list($header, $value) = explode(':', $line, 2); - if (isset($result->headers[$header]) && $result->header == 'Set-Cookie') { - // RFC 2109: the Set-Cookie response header comprises the token Set- - // Cookie:, followed by a comma-separated list of one or more cookies. - $result->headers[$header] .= ',' . trim($value); - } - else { - $result->headers[$header] = trim($value); + $opts = pantheon_apachesolr_curlopts(); + $opts[CURLOPT_URL] = $url; + $opts[CURLOPT_PORT] = $port; + + if ($timeout) { + $opts[CURLOPT_CONNECTTIMEOUT] = $timeout; + } + curl_setopt_array($ch, $opts); + + // If we are doing a delete request... + if ($method == 'DELETE') { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE"); + } + // If we are doing a put request... + if ($method == 'PUT') { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); + } + // If we are doing a put request... + if ($method == 'POST') { + curl_setopt($ch, CURLOPT_POST, 1); + } + if ($rawPost) { + curl_setopt($ch, CURLOPT_POSTFIELDS, $rawPost); + } + + $response = curl_exec($ch); + + if ($response == NULL) { + // TODO; better error handling + watchdog('pantheon_apachesolr', "Error !error connecting to !url on port !port", array('!error' => curl_error($ch), '!url' => $url, '!port' => $port), WATCHDOG_ERROR); + } + else { + // mimick the $result object from drupal_http_request() + // TODO; better error handling + $result = new stdClass(); + list($split, $result->data) = explode("\r\n\r\n", $response, 2); + $split = preg_split("/\r\n|\n|\r/", $split); + list($result->protocol, $result->code, $result->status_message) = explode(' ', trim(array_shift($split)), 3); + // Parse headers. + $result->headers = array(); + while ($line = trim(array_shift($split))) { + list($header, $value) = explode(':', $line, 2); + if (isset($result->headers[$header]) && $result->header == 'Set-Cookie') { + // RFC 2109: the Set-Cookie response header comprises the token Set- + // Cookie:, followed by a comma-separated list of one or more cookies. + $result->headers[$header] .= ',' . trim($value); + } + else { + $result->headers[$header] = trim($value); + } } } - } - if (!isset($result->code) || $result->code < 0) { - $result->code = 0; - $result->status_message = 'Request failed'; - $result->protocol = 'HTTP/1.0'; - } - // Additional information may be in the error property. - if (isset($result->error)) { - $result->status_message .= ': ' . check_plain($result->error); - } + if (!isset($result->code) || $result->code < 0) { + $result->code = 0; + $result->status_message = 'Request failed'; + $result->protocol = 'HTTP/1.0'; + } + // Additional information may be in the error property. + if (isset($result->error)) { + $result->status_message .= ': ' . check_plain($result->error); + } - if (!isset($result->data)) { - $result->data = ''; - $result->response = NULL; - } - else { - $response = json_decode($result->data); - if (is_object($response)) { - foreach ($response as $key => $value) { - $result->$key = $value; + if (!isset($result->data)) { + $result->data = ''; + $result->response = NULL; + } + else { + $response = json_decode($result->data); + if (is_object($response)) { + foreach ($response as $key => $value) { + $result->$key = $value; + } } } - } - // drupal_set_message("$url: $result->code"); + // drupal_set_message("$url: $result->code"); - $type = isset($result->headers['content-type']) ? $result->headers['content-type'] : 'text/xml'; - $body = isset($result->data) ? $result->data : NULL; - return new Apache_Solr_HttpTransport_Response($result->code, $type, $body); - } + $type = isset($result->headers['content-type']) ? $result->headers['content-type'] : 'text/xml'; + $body = isset($result->data) ? $result->data : NULL; + return new Apache_Solr_HttpTransport_Response($result->code, $type, $body); + } + } } diff --git a/modules/pantheon/pantheon_apachesolr/pantheon_apachesolr.module b/modules/pantheon/pantheon_apachesolr/pantheon_apachesolr.module index 654e50ffd29..c4174d381a7 100644 --- a/modules/pantheon/pantheon_apachesolr/pantheon_apachesolr.module +++ b/modules/pantheon/pantheon_apachesolr/pantheon_apachesolr.module @@ -19,6 +19,14 @@ function pantheon_apachesolr_menu() { return $items; } +function pantheon_apachesolr_search_api_service_info_alter(array &$service_info) { + // Change the Search API Solr Service class to our custom class. This approach is used for + // Search API RC4 and greater which no longer uses the SolrPHP Client library. + if (!function_exists('_search_api_solr_solrphpclient_path')) { + $service_info['search_api_solr_service']['class'] = 'PantheonApachesolrSearchApiSolrService'; + } +} + function pantheon_apachesolr_curlopts() { return array( CURLOPT_HEADER => 1,