Skip to content

Commit

Permalink
Handle HTTP exceptions in HttpTransport
Browse files Browse the repository at this point in the history
Signed-off-by: Kim Pepper <[email protected]>
  • Loading branch information
kimpepper committed Jan 15, 2025
1 parent fbb73a3 commit ff70623
Show file tree
Hide file tree
Showing 41 changed files with 566 additions and 168 deletions.
8 changes: 6 additions & 2 deletions src/OpenSearch/Common/Exceptions/Forbidden403Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@

namespace OpenSearch\Common\Exceptions;

@trigger_error(Forbidden403Exception::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0.', E_USER_DEPRECATED);
use OpenSearch\Exception\ForbiddenHttpException;

@trigger_error(Forbidden403Exception::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\ForbiddenHttpException instead', E_USER_DEPRECATED);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
*
* @see \OpenSearch\Exception\ForbiddenHttpException
*/
class Forbidden403Exception extends \Exception implements OpenSearchException
class Forbidden403Exception extends ForbiddenHttpException
{
}
11 changes: 9 additions & 2 deletions src/OpenSearch/Common/Exceptions/Missing404Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,18 @@

namespace OpenSearch\Common\Exceptions;

@trigger_error(Missing404Exception::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0.', E_USER_DEPRECATED);
use OpenSearch\Exception\NotFoundHttpException;

@trigger_error(
Missing404Exception::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\NotFoundHttpException instead.',
E_USER_DEPRECATED
);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
*
* @see \OpenSearch\Exception\NotFoundHttpException
*/
class Missing404Exception extends \Exception implements OpenSearchException
class Missing404Exception extends NotFoundHttpException
{
}
11 changes: 8 additions & 3 deletions src/OpenSearch/Common/Exceptions/NoDocumentsToGetException.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@

namespace OpenSearch\Common\Exceptions;

@trigger_error(NoDocumentsToGetException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0.', E_USER_DEPRECATED);
@trigger_error(
NoDocumentsToGetException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\NoDocumentsToGetException instead.',
E_USER_DEPRECATED
);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
* @deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\NoDocumentsToGetException instead.
*
* @see \OpenSearch\Exception\ScriptLangNotSupportedException
*/
class NoDocumentsToGetException extends ServerErrorResponseException implements OpenSearchException
class NoDocumentsToGetException extends \OpenSearch\Exception\NoDocumentsToGetException
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@

namespace OpenSearch\Common\Exceptions;

@trigger_error(
NoNodesAvailableException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0.',
E_USER_DEPRECATED
);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
*/
class NoNodesAvailableException extends ServerErrorResponseException implements OpenSearchException
{
}
12 changes: 11 additions & 1 deletion src/OpenSearch/Common/Exceptions/NoShardAvailableException.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@

namespace OpenSearch\Common\Exceptions;

class NoShardAvailableException extends ServerErrorResponseException implements OpenSearchException
@trigger_error(
NoShardAvailableException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\NoShardAvailableException instead.',
E_USER_DEPRECATED
);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\NoShardAvailableException instead.
*
* @see \OpenSearch\Exception\NoShardAvailableException
*/
class NoShardAvailableException extends \OpenSearch\Exception\NoShardAvailableException
{
}
12 changes: 10 additions & 2 deletions src/OpenSearch/Common/Exceptions/OpenSearchException.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,16 @@

namespace OpenSearch\Common\Exceptions;

use Throwable;
use OpenSearch\Exception\OpenSearchExceptionInterface;

interface OpenSearchException extends Throwable
@trigger_error(
NoNodesAvailableException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0.',
E_USER_DEPRECATED
);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
*/
interface OpenSearchException extends OpenSearchExceptionInterface
{
}
12 changes: 11 additions & 1 deletion src/OpenSearch/Common/Exceptions/RoutingMissingException.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@

namespace OpenSearch\Common\Exceptions;

class RoutingMissingException extends ServerErrorResponseException implements OpenSearchException
@trigger_error(
RoutingMissingException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\RoutingMissingException instead.',
E_USER_DEPRECATED
);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0. Use OpenSearch\Exception\UnauthorizedHttpException instead.
*
* @see \OpenSearch\Exception\ScriptLangNotSupportedException
*/
class RoutingMissingException extends \OpenSearch\Exception\RoutingMissingException
{
}
4 changes: 3 additions & 1 deletion src/OpenSearch/Common/Exceptions/RuntimeException.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

namespace OpenSearch\Common\Exceptions;

class RuntimeException extends \RuntimeException implements OpenSearchException
use OpenSearch\Exception\OpenSearchExceptionInterface;

class RuntimeException extends \RuntimeException implements OpenSearchExceptionInterface
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@

namespace OpenSearch\Common\Exceptions;

class ScriptLangNotSupportedException extends BadRequest400Exception implements OpenSearchException
@trigger_error(
ScriptLangNotSupportedException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use OpenSearch\Exception\ScriptLangNotSupportedException instead.',
E_USER_DEPRECATED
);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0. Use OpenSearch\Exception\UnauthorizedHttpException instead.
*
* @see \OpenSearch\Exception\ScriptLangNotSupportedException
*/
class ScriptLangNotSupportedException extends \OpenSearch\Exception\ScriptLangNotSupportedException
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@

namespace OpenSearch\Common\Exceptions;

@trigger_error(RequestTimeout408Exception::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0.', E_USER_DEPRECATED);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
*/
class ServerErrorResponseException extends TransportException implements OpenSearchException
{
}
14 changes: 13 additions & 1 deletion src/OpenSearch/Common/Exceptions/Unauthorized401Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@

namespace OpenSearch\Common\Exceptions;

class Unauthorized401Exception extends \Exception implements OpenSearchException
use OpenSearch\Exception\UnauthorizedHttpException;

@trigger_error(
Unauthorized401Exception::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use OpenSearch\Exception\UnauthorizedHttpException instead.',
E_USER_DEPRECATED
);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0. Use OpenSearch\Exception\UnauthorizedHttpException instead.
*
* @see \OpenSearch\Exception\UnauthorizedHttpException
*/
class Unauthorized401Exception extends UnauthorizedHttpException
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

namespace OpenSearch\Common\Exceptions;

class UnexpectedValueException extends \UnexpectedValueException implements OpenSearchException
use OpenSearch\Exception\OpenSearchExceptionInterface;

class UnexpectedValueException extends \UnexpectedValueException implements OpenSearchExceptionInterface
{
}
19 changes: 9 additions & 10 deletions src/OpenSearch/Connections/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -664,19 +664,19 @@ private function process4xxError(array $request, array $response, array $ignore)

$responseBody = $this->convertBodyToString($response['body'], $statusCode, $exception);
if ($statusCode === 401) {
$exception = new Unauthorized401Exception($responseBody, $statusCode);
$exception = new Unauthorized401Exception($responseBody);
} elseif ($statusCode === 403) {
$exception = new Forbidden403Exception($responseBody, $statusCode);
$exception = new Forbidden403Exception($responseBody);
} elseif ($statusCode === 404) {
$exception = new Missing404Exception($responseBody, $statusCode);
$exception = new Missing404Exception($responseBody);
} elseif ($statusCode === 409) {
$exception = new Conflict409Exception($responseBody, $statusCode);
} elseif ($statusCode === 400 && strpos($responseBody, 'script_lang not supported') !== false) {
$exception = new ScriptLangNotSupportedException($responseBody. $statusCode);
$exception = new ScriptLangNotSupportedException($responseBody);
} elseif ($statusCode === 408) {
$exception = new RequestTimeout408Exception($responseBody, $statusCode);
$exception = new RequestTimeout408Exception($responseBody);
} else {
$exception = new BadRequest400Exception($responseBody, $statusCode);
$exception = new BadRequest400Exception($responseBody);
}

$this->logRequestFail($request, $response, $exception);
Expand Down Expand Up @@ -706,15 +706,14 @@ private function process5xxError(array $request, array $response, array $ignore)
}

if ($statusCode === 500 && strpos($responseBody, "RoutingMissingException") !== false) {
$exception = new RoutingMissingException($exception->getMessage(), $statusCode, $exception);
$exception = new RoutingMissingException($exception->getMessage(), [], 0, $exception);
} elseif ($statusCode === 500 && preg_match('/ActionRequestValidationException.+ no documents to get/', $responseBody) === 1) {
$exception = new NoDocumentsToGetException($exception->getMessage(), $statusCode, $exception);
$exception = new NoDocumentsToGetException($exception->getMessage(), [], 0, $exception);
} elseif ($statusCode === 500 && strpos($responseBody, 'NoShardAvailableActionException') !== false) {
$exception = new NoShardAvailableException($exception->getMessage(), $statusCode, $exception);
$exception = new NoShardAvailableException($exception->getMessage(), [], 0, $exception);
} else {
$exception = new ServerErrorResponseException(
$this->convertBodyToString($responseBody, $statusCode, $exception),
$statusCode
);
}

Expand Down
17 changes: 17 additions & 0 deletions src/OpenSearch/Exception/BadRequestHttpException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace OpenSearch\Exception;

/**
* Exception thrown when a 400 Bad Request HTTP error occurs.
*/
class BadRequestHttpException extends HttpException
{
public function __construct(string $message = '', array $headers = [], int $code = 0, ?\Throwable $previous = null)
{
parent::__construct(400, $message, $headers, $code, $previous);
}

}
16 changes: 16 additions & 0 deletions src/OpenSearch/Exception/ConflictHttpException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace OpenSearch\Exception;

/**
* Exception thrown when a 409 Conflict HTTP error occurs.
*/
class ConflictHttpException extends HttpException
{
public function __construct(string $message = '', array $headers = [], int $code = 0, ?\Throwable $previous = null)
{
parent::__construct(409, $message, $headers, $code, $previous);
}
}
56 changes: 56 additions & 0 deletions src/OpenSearch/Exception/ErrorMessageExtractor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace OpenSearch\Exception;

use OpenSearch\Serializers\SerializerInterface;

/**
* Extracts an error message from the response body.
*/
class ErrorMessageExtractor
{
public function __construct(
private readonly SerializerInterface $serializer,
) {
}

public function extractErrorMessage(mixed $body, array $headers): ?string
{
if (!is_string($body)) {
// Convert non-string response body to string message.
return json_encode($body);
}

$error = $this->serializer->deserialize($body, $headers);

if (is_string($error)) {
return $error;
}

if (!isset($error['error'])) {
// <2.0 "i just blew up" non-structured exception.
// $error is an array, but we don't know the format, so we reuse the response body instead
// added json_encode to convert into a string
return json_encode($body);
}

// 2.0 structured exceptions
if (is_array($error['error']) && array_key_exists('reason', $error['error'])) {
// Try to use root cause first (only grabs the first root cause)
$info = $error['error']['root_cause'][0] ?? $error['error'];
$cause = $info['reason'];
$type = $info['type'];

return "$type: $cause";
}

// <2.0 semi-structured exceptions
$legacyError = $error['error'];
if (is_array($error['error'])) {
return json_encode($legacyError);
}
return $legacyError;
}
}
16 changes: 16 additions & 0 deletions src/OpenSearch/Exception/ForbiddenHttpException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace OpenSearch\Exception;

/**
* Exception thrown when a 403 Forbidden HTTP error occurs.
*/
class ForbiddenHttpException extends HttpException
{
public function __construct(string $message = '', array $headers = [], int $code = 0, ?\Throwable $previous = null)
{
parent::__construct(403, $message, $headers, $code, $previous);
}
}
34 changes: 34 additions & 0 deletions src/OpenSearch/Exception/HttpException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace OpenSearch\Exception;

/**
* Exception thrown when an HTTP error occurs.
*
* @phpstan-consistent-constructor
*/
class HttpException extends \RuntimeException implements HttpExceptionInterface
{
public function __construct(
protected readonly int $statusCode,
string $message = '',
protected readonly array $headers = [],
int $code = 0,
?\Throwable $previous = null,
) {
parent::__construct($message, $code, $previous);
}

public function getStatusCode(): int
{
return $this->statusCode;
}

public function getHeaders(): array
{
return $this->headers;
}

}
Loading

0 comments on commit ff70623

Please sign in to comment.