public static IOException translateException()

in hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AUtils.java [173:374]


  public static IOException translateException(@Nullable String operation,
      @Nullable String path,
      SdkException exception) {
    String message = String.format("%s%s: %s",
        operation,
        StringUtils.isNotEmpty(path)? (" on " + path) : "",
        exception);

    if (path == null || path.isEmpty()) {
      // handle null path by giving it a stub value.
      // not ideal/informative, but ensures that the path is never null in
      // exceptions constructed.
      path = "/";
    }

    exception = maybeProcessEncryptionClientException(exception);

    if (!(exception instanceof AwsServiceException)) {
      // exceptions raised client-side: connectivity, auth, network problems...
      Exception innerCause = containsInterruptedException(exception);
      if (innerCause != null) {
        // interrupted IO, or a socket exception underneath that class
        return translateInterruptedException(exception, innerCause, message);
      }
      if (isMessageTranslatableToEOF(exception)) {
        // call considered an sign of connectivity failure
        return (EOFException)new EOFException(message).initCause(exception);
      }
      // if the exception came from the auditor, hand off translation
      // to it.
      IOException ioe = maybeTranslateAuditException(path, exception);
      if (ioe != null) {
        return ioe;
      }
      ioe = maybeTranslateCredentialException(path, exception);
      if (ioe != null) {
        return ioe;
      }
      // network problems covered by an IOE inside the exception chain.
      ioe = maybeExtractIOException(path, exception, message);
      if (ioe != null) {
        return ioe;
      }
      // timeout issues
      // ApiCallAttemptTimeoutException: a single HTTP request attempt failed.
      // ApiCallTimeoutException: a request with any configured retries failed.
      // The ApiCallTimeoutException exception should be the only one seen in
      // the S3A code, but for due diligence both are handled and mapped to
      // our own AWSApiCallTimeoutException.
      if (exception instanceof ApiCallTimeoutException
          || exception instanceof ApiCallAttemptTimeoutException) {
        // An API call to an AWS service timed out.
        // This is a subclass of ConnectTimeoutException so
        // all retry logic for that exception is handled without
        // having to look down the stack for a
        return new AWSApiCallTimeoutException(message, exception);
      }
      // no custom handling.
      return new AWSClientIOException(message, exception);
    } else {
      // "error response returned by an S3 or other service."
      // These contain more details and should be translated based
      // on the HTTP status code and other details.
      IOException ioe;
      AwsServiceException ase = (AwsServiceException) exception;
      // this exception is non-null if the service exception is an s3 one
      S3Exception s3Exception = ase instanceof S3Exception
          ? (S3Exception) ase
          : null;
      int status = ase.statusCode();
      if (ase.awsErrorDetails() != null) {
        message = message + ":" + ase.awsErrorDetails().errorCode();
      }

      // big switch on the HTTP status code.
      switch (status) {

      case SC_301_MOVED_PERMANENTLY:
      case SC_307_TEMPORARY_REDIRECT:
        if (s3Exception != null) {
          message = String.format("Received permanent redirect response to "
                  + "region %s.  This likely indicates that the S3 region "
                  + "configured in %s does not match the AWS region containing " + "the bucket.",
              s3Exception.awsErrorDetails().sdkHttpResponse().headers().get(BUCKET_REGION_HEADER),
              AWS_REGION);
          ioe = new AWSRedirectException(message, s3Exception);
        } else {
          ioe = new AWSRedirectException(message, ase);
        }
        break;

      case SC_400_BAD_REQUEST:
        ioe = new AWSBadRequestException(message, ase);
        break;

      // permissions
      case SC_401_UNAUTHORIZED:
      case SC_403_FORBIDDEN:
        ioe = new AccessDeniedException(path, null, message);
        ioe.initCause(ase);
        break;

      // the object isn't there
      case SC_404_NOT_FOUND:
        if (isUnknownBucket(ase)) {
          // this is a missing bucket
          ioe = new UnknownStoreException(path, message, ase);
        } else {
          // a normal unknown object.
          // Can also be raised by third-party stores when aborting an unknown multipart upload
          ioe = new FileNotFoundException(message);
          ioe.initCause(ase);
        }
        break;

      // Caused by duplicate create bucket call.
      case SC_409_CONFLICT:
        ioe = new AWSBadRequestException(message, ase);
        break;

      // this also surfaces sometimes and is considered to
      // be ~ a not found exception.
      case SC_410_GONE:
        ioe = new FileNotFoundException(message);
        ioe.initCause(ase);
        break;

      // errors which stores can return from requests which
      // the store does not support.
      case SC_405_METHOD_NOT_ALLOWED:
      case SC_415_UNSUPPORTED_MEDIA_TYPE:
      case SC_501_NOT_IMPLEMENTED:
        ioe = new AWSUnsupportedFeatureException(message, ase);
        break;

      // precondition failure: the object is there, but the precondition
      // (e.g. etag) didn't match. Assume remote file change during
      // rename or status passed in to openfile had an etag which didn't match.
      case SC_412_PRECONDITION_FAILED:
        ioe = new RemoteFileChangedException(path, message, "", ase);
        break;

      // out of range. This may happen if an object is overwritten with
      // a shorter one while it is being read or openFile() was invoked
      // passing a FileStatus or file length less than that of the object.
      // although the HTTP specification says that the response should
      // include a range header specifying the actual range available,
      // this isn't picked up here.
      case SC_416_RANGE_NOT_SATISFIABLE:
        ioe = new RangeNotSatisfiableEOFException(message, ase);
        break;

      // this has surfaced as a "no response from server" message.
      // so rare we haven't replicated it.
      // Treating as an idempotent proxy error.
      case SC_443_NO_RESPONSE:
      case SC_444_NO_RESPONSE:
        ioe = new AWSNoResponseException(message, ase);
        break;

      // throttling
      case SC_429_TOO_MANY_REQUESTS_GCS:    // google cloud through this connector
      case SC_503_SERVICE_UNAVAILABLE:      // AWS
        ioe = new AWSServiceThrottledException(message, ase);
        break;

      // gateway timeout
      case SC_504_GATEWAY_TIMEOUT:
        ioe = new AWSApiCallTimeoutException(message, ase);
        break;

      // internal error
      case SC_500_INTERNAL_SERVER_ERROR:
        ioe = new AWSStatus500Exception(message, ase);
        break;

      case SC_200_OK:
        if (exception instanceof MultiObjectDeleteException) {
          // failure during a bulk delete
          return ((MultiObjectDeleteException) exception)
              .translateException(message);
        }
        // other 200: FALL THROUGH

      default:
        // no specifically handled exit code.

        // convert all unknown 500+ errors to a 500 exception
        if (status > SC_500_INTERNAL_SERVER_ERROR) {
          ioe = new AWSStatus500Exception(message, ase);
          break;
        }

        // Choose an IOE subclass based on the class of the caught exception
        ioe = s3Exception != null
            ? new AWSS3IOException(message, s3Exception)
            : new AWSServiceIOException(message, ase);
        break;
      }
      return ioe;
    }
  }