@Override
  public AbstractStorageItem retrieveItem(
      ProxyRepository repository, ResourceStoreRequest request, String baseUrl)
      throws ItemNotFoundException, RemoteStorageException {
    final URL remoteURL = getAbsoluteUrlFromBase(baseUrl, request.getRequestPath());

    final String itemUrl = remoteURL.toString();

    final AsyncHttpClient client = getClient(repository);

    try {

      BodyDeferringInputStream ris = AHCUtils.fetchContent(client, itemUrl);

      // this blocks until response headers arrived
      Response response = ris.getAsapResponse();

      // expected: 200 OK
      validateResponse(repository, request, "GET", itemUrl, response, 200);

      long length = AHCUtils.getContentLength(response, -1);

      long lastModified = AHCUtils.getLastModified(response, System.currentTimeMillis());

      // non-reusable simplest content locator, the ris InputStream is ready to be consumed
      PreparedContentLocator contentLocator =
          new PreparedContentLocator(ris, response.getContentType());

      DefaultStorageFileItem result =
          new DefaultStorageFileItem(
              repository, request, true /* canRead */, true /* canWrite */, contentLocator);

      result.setLength(length);

      result.setModified(lastModified);

      result.setCreated(result.getModified());

      result.setRemoteUrl(itemUrl);

      result.getItemContext().setParentContext(request.getRequestContext());

      return result;
    } catch (ItemNotFoundException e) {
      throw e;
    } catch (RemoteStorageException e) {
      throw e;
    } catch (Exception e) {
      throw new RemoteStorageException(e);
    }
  }
  protected void validateResponse(
      final ProxyRepository repository,
      final ResourceStoreRequest request,
      final String method,
      final String remoteUrl,
      final Response response,
      int... expectedCodes)
      throws ItemNotFoundException, RemoteStorageException {
    // maintain the S3 flag
    checkForRemotePeerAmazonS3Storage(repository, response.getHeader("server"));

    if (response.isRedirected()) {
      getLogger()
          .info(
              String.format(
                  "Proxy repository %s (id=%s) got redirected from %s, please verify your remoteUrl is up-to-date!",
                  repository.getName(), repository.getId(), remoteUrl));
    }

    if (AHCUtils.isAnyOfTheseStatusCodes(response, expectedCodes)) {
      // good, an expected one
      return;
    }

    // 404 NotFound
    if (404 == response.getStatusCode()) {
      throw new ItemNotFoundException(request, repository);
    }

    // 401 Unauthorized
    if (401 == response.getStatusCode()) {
      throw new RemoteAuthenticationNeededException(
          repository, remoteUrl, response.getStatusText());
    }

    // 403 Forbidden
    if (403 == response.getStatusCode()) {
      throw new RemoteAccessDeniedException(repository, remoteUrl, response.getStatusText());
    }

    // anything else "unexpected"?
    throw new RemoteStorageException(
        String.format(
            "Coult not perform %s against Url %s, unexpected response is %s",
            method, remoteUrl, response.getStatusText()));
  }
  @Override
  protected boolean checkRemoteAvailability(
      long newerThen, ProxyRepository repository, ResourceStoreRequest request, boolean isStrict)
      throws RemoteStorageException {
    final URL remoteURL = getAbsoluteUrlFromBase(repository, request);

    final String itemUrl = remoteURL.toString();

    final AsyncHttpClient client = getClient(repository);

    if (getLogger().isDebugEnabled()) {
      getLogger()
          .debug(
              String.format(
                  "Checking remote availability of proxy repository \"%s\" (id=%s) on URL %s",
                  repository.getName(), repository.getId(), itemUrl));
    }

    // artifactory hack, it pukes on HEAD so we will try with GET if HEAD fails
    boolean doGet = false;

    Response responseObject = null;

    int response = 400;

    try {
      responseObject = client.prepareHead(itemUrl).execute().get();

      response = responseObject.getStatusCode();

      validateResponse(repository, request, "HEAD", itemUrl, responseObject, 200);
    } catch (ItemNotFoundException e) {
      return false;
    } catch (RemoteStorageException e) {
      // If HEAD failed, attempt a GET. Some repos may not support HEAD method
      doGet = true;

      getLogger().debug("HEAD method failed, will attempt GET.  Exception: " + e.getMessage(), e);
    } catch (Exception e) {
      throw new RemoteStorageException(e);
    } finally {
      // HEAD returned error, but not exception, try GET before failing
      if (!doGet && response != 200) {
        // try with GET unless some known to fail responses are in
        doGet = (response != 401) && (response != 403);

        getLogger().debug("HEAD method failed, will attempt GET.  Status: " + response);
      }
    }

    if (doGet) {
      try {
        responseObject = client.prepareGet(itemUrl).execute().get();

        response = responseObject.getStatusCode();

        validateResponse(repository, request, "GET", itemUrl, responseObject, 200);
      } catch (ItemNotFoundException e) {
        return false;
      } catch (Exception e) {
        throw new RemoteStorageException(e);
      }
    }

    // if we are not strict and remote is S3
    if (!isStrict && isRemotePeerAmazonS3Storage(repository)) {
      // if we are relaxed, we will accept any HTTP response code below 500. This means anyway the
      // HTTP
      // transaction succeeded. This method was never really detecting that the remoteUrl really
      // denotes a root of
      // repository (how could we do that?)
      // this "relaxed" check will help us to "pass" S3 remote storage.
      return response >= 200 && response < 500;
    } else {
      // non relaxed check is strict, and will select only the OK response
      if (response == 200) {
        // we have it
        // we have newer if this below is true
        return AHCUtils.getLastModified(responseObject, System.currentTimeMillis()) > newerThen;
      } else if ((response >= 300 && response < 400) || response == 404) {
        return false;
      } else {
        throw new RemoteStorageException(
            "Unexpected response code while executing GET"
                + " method [repositoryId=\""
                + repository.getId()
                + "\", requestPath=\""
                + request.getRequestPath()
                + "\", remoteUrl=\""
                + itemUrl
                + "\"]. Expected: \"SUCCESS (200)\". Received: "
                + response
                + " : "
                + responseObject.getStatusText());
      }
    }
  }