From 5af2e661f4e32d79e928e278df68a84a5ffbdb64 Mon Sep 17 00:00:00 2001
From: Ian Thomas <ian.thomas@tuidev.com>
Date: Tue, 15 Oct 2013 17:27:11 +0100
Subject: [PATCH] Issue #1997702 by ianthomas_uk: Add AUTO HTTP method to pick
 the best HTTP method for each query

---
 README.txt                             |  4 ++++
 includes/service.inc                   |  9 +++++----
 includes/solr_connection.inc           | 26 ++++++++++++++------------
 includes/solr_connection.interface.inc |  4 ++--
 4 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/README.txt b/README.txt
index 7ea11f5..8c1443a 100644
--- a/README.txt
+++ b/README.txt
@@ -126,6 +126,10 @@ Hidden variables
   prefix is added, so the global prefix will come first in the final name:
   (GLOBAL_PREFIX)(INDEX_PREFIX)(INDEX_ID)
   The same rules as above apply for setting the prefix.
+- search_api_solr_http_get_max_length (default: 4000)
+  The maximum number of bytes that can be handled as an HTTP GET query when
+  HTTP method is AUTO. Typically Solr can handle up to 65355 bytes, but Tomcat
+  and Jetty will error at slightly less than 4096 bytes.
 
 Customizing your Solr server
 ----------------------------
diff --git a/includes/service.inc b/includes/service.inc
index ee43501..5bb8cd7 100644
--- a/includes/service.inc
+++ b/includes/service.inc
@@ -219,9 +219,10 @@ class SearchApiSolrService extends SearchApiAbstractService {
     $form['advanced']['http_method'] = array(
       '#type' => 'select',
       '#title' => t('HTTP method'),
-      '#description' => t('The HTTP method to use for sending queries. Usually, POST will work fine in all cases.'),
+      '#description' => t('The HTTP method to use for sending queries. GET will often fail with larger queries, while POST should not be cached. AUTO will use GET when possible, and POST for queries that are too large.'),
       '#default_value' => $options['http_method'],
       '#options' => array(
+        'AUTO' => 'AUTO',
         'POST' => 'POST',
         'GET' => 'GET',
       ),
@@ -898,7 +899,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
       $params['fl'] = '*,score';
     }
     // Retrieve http method from server options.
-    $http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'POST';
+    $http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'AUTO';
 
     $call_args = array(
       'query'       => &$keys,
@@ -1603,7 +1604,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
       'spellcheck.count' => 1,
     );
     // Retrieve http method from server options.
-    $http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'POST';
+    $http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'AUTO';
 
     $call_args = array(
       'query'       => &$keys,
@@ -1830,7 +1831,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
     }
 
     // Retrieve http method from server options.
-    $http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'POST';
+    $http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'AUTO';
 
     // Send search request
     $time_processing_done = microtime(TRUE);
diff --git a/includes/solr_connection.inc b/includes/solr_connection.inc
index 8a26212..d164b30 100644
--- a/includes/solr_connection.inc
+++ b/includes/solr_connection.inc
@@ -208,8 +208,8 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
    *     information to add basic HTTP authentication to all requests to the
    *     Solr server. Not set by default.
    *   - http_pass: See "http_user".
-   *   - http_method: The HTTP method to use for searches. Can be either "GET"
-   *     or "POST". Defaults to "POST".
+   *   - http_method: The HTTP method to use for searches. Can be either "GET",
+   *     "POST" or "AUTO". Defaults to "POST".
    */
   public function __construct(array $options) {
     $options += array(
@@ -226,8 +226,8 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
     $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';
+    // Make sure we always have a valid method set, default to AUTO.
+    $this->method = in_array($options['http_method'], array('GET', 'POST', 'AUTO')) ? $options['http_method'] : 'POST';
 
     // Set HTTP Basic Authentication parameter, if login data was set.
     if (strlen($options['http_user']) && strlen($options['http_pass'])) {
@@ -887,15 +887,17 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
     // PHP's built-in http_build_query() doesn't give us the format Solr wants.
     $queryString = $this->httpBuildQuery($params);
 
-    if ($this->method == 'GET') {
+    if ($this->method == 'GET' || $this->method == 'AUTO') {
       $searchUrl = $this->constructUrl(self::SEARCH_SERVLET, array(), $queryString);
-      return $this->sendRawGet($searchUrl);
-    }
-    else if ($this->method == 'POST') {
-      $searchUrl = $this->constructUrl(self::SEARCH_SERVLET);
-      $options['data'] = $queryString;
-      $options['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
-      return $this->sendRawPost($searchUrl, $options);
+      if ($this->method == 'GET' || strlen($searchUrl) <= variable_get('search_api_solr_http_get_max_length', 4000)) {
+        return $this->sendRawGet($searchUrl);
+      }
     }
+
+    // Method is POST, or AUTO with a long query
+    $searchUrl = $this->constructUrl(self::SEARCH_SERVLET);
+    $options['data'] = $queryString;
+    $options['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
+    return $this->sendRawPost($searchUrl, $options);
   }
 }
diff --git a/includes/solr_connection.interface.inc b/includes/solr_connection.interface.inc
index df30ade..be8f5cd 100644
--- a/includes/solr_connection.interface.inc
+++ b/includes/solr_connection.interface.inc
@@ -288,8 +288,8 @@ interface SearchApiSolrConnectionInterface {
    *   documentation). Use arrays for parameter keys used more than once (e.g.,
    *   facet.field).
    * @param string $method
-   *   The HTTP method to use. Must be either "GET" or "POST". Defaults to
-   *   "GET".
+   *   The HTTP method to use. Must be either "GET", "POST" or "AUTO". Defaults
+   *   to "GET".
    *
    * @return object
    *   A response object.
-- 
1.7.11.msysgit.0

