vendor/ruflin/elastica/src/Transport/Http.php line 48

Open in your IDE?
  1. <?php
  2. namespace Elastica\Transport;
  3. use Elastica\Exception\Connection\HttpException;
  4. use Elastica\Exception\ConnectionException;
  5. use Elastica\Exception\PartialShardFailureException;
  6. use Elastica\Exception\ResponseException;
  7. use Elastica\JSON;
  8. use Elastica\Request;
  9. use Elastica\Response;
  10. use Elastica\Util;
  11. /**
  12. * Elastica Http Transport object.
  13. *
  14. * @author Nicolas Ruflin <spam@ruflin.com>
  15. */
  16. class Http extends AbstractTransport
  17. {
  18. /**
  19. * Http scheme.
  20. *
  21. * @var string Http scheme
  22. */
  23. protected $_scheme = 'http';
  24. /**
  25. * Curl resource to reuse.
  26. *
  27. * @var \CurlHandle|resource|null Curl resource to reuse
  28. */
  29. protected static $_curlConnection;
  30. /**
  31. * Makes calls to the elasticsearch server.
  32. *
  33. * All calls that are made to the server are done through this function
  34. *
  35. * @param array<string, mixed> $params Host, Port, ...
  36. *
  37. * @throws ConnectionException
  38. * @throws ResponseException
  39. * @throws HttpException
  40. *
  41. * @return Response Response object
  42. */
  43. public function exec(Request $request, array $params): Response
  44. {
  45. $connection = $this->getConnection();
  46. $conn = $this->_getConnection($connection->isPersistent());
  47. // If url is set, url is taken. Otherwise port, host and path
  48. $url = $connection->hasConfig('url') ? $connection->getConfig('url') : '';
  49. if (!empty($url)) {
  50. $baseUri = $url;
  51. } else {
  52. $baseUri = $this->_scheme.'://'.$connection->getHost().':'.$connection->getPort().'/'.$connection->getPath();
  53. }
  54. $requestPath = $request->getPath();
  55. if (!Util::isDateMathEscaped($requestPath)) {
  56. $requestPath = Util::escapeDateMath($requestPath);
  57. }
  58. $baseUri .= $requestPath;
  59. $query = $request->getQuery();
  60. if (!empty($query)) {
  61. $baseUri .= '?'.\http_build_query(
  62. $this->sanityzeQueryStringBool($query)
  63. );
  64. }
  65. \curl_setopt($conn, \CURLOPT_URL, $baseUri);
  66. \curl_setopt($conn, \CURLOPT_TIMEOUT_MS, $connection->getTimeout() * 1000);
  67. \curl_setopt($conn, \CURLOPT_FORBID_REUSE, 0);
  68. // Tell ES that we support the compressed responses
  69. // An "Accept-Encoding" header containing all supported encoding types is sent
  70. // curl will decode the response automatically if the response is encoded
  71. \curl_setopt($conn, \CURLOPT_ENCODING, '');
  72. /* @see Connection::setConnectTimeout() */
  73. $connectTimeoutMs = $connection->getConnectTimeout() * 1000;
  74. // Let's only apply this value if the number of ms is greater than or equal to "1".
  75. // In case "0" is passed as an argument, the value is reset to its default (300 s)
  76. if ($connectTimeoutMs >= 1) {
  77. \curl_setopt($conn, \CURLOPT_CONNECTTIMEOUT_MS, $connectTimeoutMs);
  78. }
  79. if (null !== $proxy = $connection->getProxy()) {
  80. \curl_setopt($conn, \CURLOPT_PROXY, $proxy);
  81. }
  82. $username = $connection->getUsername();
  83. $password = $connection->getPassword();
  84. if (null !== $username && null !== $password) {
  85. \curl_setopt($conn, \CURLOPT_HTTPAUTH, $this->_getAuthType());
  86. \curl_setopt($conn, \CURLOPT_USERPWD, "{$username}:{$password}");
  87. }
  88. $this->_setupCurl($conn);
  89. $headersConfig = $connection->hasConfig('headers') ? $connection->getConfig('headers') : [];
  90. $headers = [];
  91. if (!empty($headersConfig)) {
  92. foreach ($headersConfig as $header => $headerValue) {
  93. $headers[] = $header.': '.$headerValue;
  94. }
  95. }
  96. // TODO: REFACTOR
  97. $data = $request->getData();
  98. $httpMethod = $request->getMethod();
  99. $headers[] = 'Content-Type: '.$request->getContentType();
  100. if (!empty($data)) {
  101. if ($this->hasParam('postWithRequestBody') && true == $this->getParam('postWithRequestBody')) {
  102. $httpMethod = Request::POST;
  103. }
  104. if (\is_array($data)) {
  105. $content = JSON::stringify($data, \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES);
  106. } else {
  107. $content = $data;
  108. // Escaping of / not necessary. Causes problems in base64 encoding of files
  109. $content = \str_replace('\/', '/', $content);
  110. }
  111. if ($connection->hasCompression()) {
  112. // Compress the body of the request ...
  113. \curl_setopt($conn, \CURLOPT_POSTFIELDS, \gzencode($content));
  114. // ... and tell ES that it is compressed
  115. $headers[] = 'Content-Encoding: gzip';
  116. } else {
  117. \curl_setopt($conn, \CURLOPT_POSTFIELDS, $content);
  118. }
  119. } else {
  120. \curl_setopt($conn, \CURLOPT_POSTFIELDS, '');
  121. }
  122. \curl_setopt($conn, \CURLOPT_HTTPHEADER, $headers);
  123. \curl_setopt($conn, \CURLOPT_NOBODY, 'HEAD' === $httpMethod);
  124. \curl_setopt($conn, \CURLOPT_CUSTOMREQUEST, $httpMethod);
  125. $start = \microtime(true);
  126. // cURL opt returntransfer leaks memory, therefore OB instead.
  127. \ob_start();
  128. \curl_exec($conn);
  129. $responseString = \ob_get_clean();
  130. $end = \microtime(true);
  131. // Checks if error exists
  132. $errorNumber = \curl_errno($conn);
  133. $response = new Response($responseString, \curl_getinfo($conn, \CURLINFO_RESPONSE_CODE));
  134. $response->setQueryTime($end - $start);
  135. $response->setTransferInfo(\curl_getinfo($conn));
  136. if ($connection->hasConfig('bigintConversion')) {
  137. $response->setJsonBigintConversion($connection->getConfig('bigintConversion'));
  138. }
  139. if ($response->hasError()) {
  140. throw new ResponseException($request, $response);
  141. }
  142. if ($response->hasFailedShards()) {
  143. throw new PartialShardFailureException($request, $response);
  144. }
  145. if ($errorNumber > 0) {
  146. throw new HttpException($errorNumber, $request, $response);
  147. }
  148. return $response;
  149. }
  150. /**
  151. * Called to add additional curl params.
  152. *
  153. * @param \CurlHandle|resource $curlConnection Curl connection
  154. */
  155. protected function _setupCurl($curlConnection): void
  156. {
  157. if ($this->getConnection()->hasConfig('curl')) {
  158. foreach ($this->getConnection()->getConfig('curl') as $key => $param) {
  159. \curl_setopt($curlConnection, $key, $param);
  160. }
  161. }
  162. }
  163. /**
  164. * Return Curl resource.
  165. *
  166. * @param bool $persistent False if not persistent connection
  167. *
  168. * @return \CurlHandle|resource Connection resource
  169. */
  170. protected function _getConnection(bool $persistent = true)
  171. {
  172. if (!$persistent || !self::$_curlConnection) {
  173. self::$_curlConnection = \curl_init();
  174. }
  175. return self::$_curlConnection;
  176. }
  177. /**
  178. * @return int
  179. */
  180. protected function _getAuthType()
  181. {
  182. switch ($this->_connection->getAuthType()) {
  183. case 'digest':
  184. return \CURLAUTH_DIGEST;
  185. case 'gssnegotiate':
  186. return \CURLAUTH_GSSNEGOTIATE;
  187. case 'ntlm':
  188. return \CURLAUTH_NTLM;
  189. case 'basic':
  190. return \CURLAUTH_BASIC;
  191. default:
  192. return \CURLAUTH_ANY;
  193. }
  194. }
  195. }