@Test
  public void testExceptionWhenIOExceptionOn200()
      throws ExecutionException, InterruptedException, TimeoutException, IOException {
    Function<HttpResponse, URI> function =
        new ParseURIFromListOrLocationHeaderIf20x(uriBuilderProvider);
    HttpResponse response = createMock(HttpResponse.class);
    Payload payload = createMock(Payload.class);

    expect(response.getStatusCode()).andReturn(200).atLeastOnce();
    expect(response.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)).andReturn("text/uri-list");
    RuntimeException exception = new RuntimeException("bad");
    expect(response.getPayload()).andReturn(payload).atLeastOnce();
    expect(payload.getInput()).andThrow(exception);
    payload.release();

    replay(payload);
    replay(response);
    try {
      function.apply(response);
    } catch (Exception e) {
      assert e.equals(exception);
    }
    verify(payload);
    verify(response);
  }
  @Test
  void testMultipartDoesntAttemptToParseETagIntoMD5() throws Exception {
    HttpResponse http =
        HttpResponse.builder()
            .statusCode(400)
            .message("boa")
            .payload("")
            .addHeader(S3Headers.USER_METADATA_PREFIX + "foo", "bar")
            .addHeader(HttpHeaders.LAST_MODIFIED, lastModified)
            .addHeader(HttpHeaders.ETAG, "\"abcd-1\"")
            .addHeader(HttpHeaders.CACHE_CONTROL, "cacheControl")
            .build();
    http.getPayload().getContentMetadata().setContentLength(1025l);
    http.getPayload().getContentMetadata().setContentDisposition("contentDisposition");
    http.getPayload().getContentMetadata().setContentEncoding("encoding");
    http.getPayload().getContentMetadata().setContentType(MediaType.APPLICATION_OCTET_STREAM);

    MutableObjectMetadata response = parser.apply(http);

    MutableObjectMetadataImpl expects = new MutableObjectMetadataImpl();
    expects.setCacheControl("cacheControl");
    expects.getContentMetadata().setContentDisposition("contentDisposition");
    expects.getContentMetadata().setContentEncoding("encoding");
    expects.getContentMetadata().setContentType(MediaType.APPLICATION_OCTET_STREAM);
    expects.getContentMetadata().setContentLength(1025l);
    expects.setETag("\"abcd-1\"");
    expects.setKey("key");
    expects.setLastModified(now);
    expects.setOwner(null);
    expects.setStorageClass(StorageClass.STANDARD);
    expects.setUserMetadata(userMetadata);
    assertEquals(response, expects);
  }
 public String parseMessage(final HttpResponse response) {
   if (response.getPayload() == null) {
     return null;
   }
   try {
     return Strings2.toStringAndClose(response.getPayload().openStream());
   } catch (IOException e) {
     throw new RuntimeException(e);
   }
 }
Example #4
0
  @Test
  public void test408ShouldRetry() {
    HttpCommand command = createMock(HttpCommand.class);
    HttpResponse response = createMock(HttpResponse.class);
    @SuppressWarnings("unchecked")
    LoadingCache<Credentials, Access> cache = createMock(LoadingCache.class);
    BackoffLimitedRetryHandler backoffHandler = createMock(BackoffLimitedRetryHandler.class);

    expect(response.getPayload())
        .andReturn(
            Payloads.newStringPayload(
                "The server has waited too long for the request to be sent by the client."))
        .times(3);
    expect(backoffHandler.shouldRetryRequest(command, response)).andReturn(true).once();
    expect(response.getStatusCode()).andReturn(408).once();

    replay(command);
    replay(response);
    replay(cache);
    replay(backoffHandler);

    RetryOnRenew retry = new RetryOnRenew(cache, backoffHandler);

    assertTrue(retry.shouldRetryRequest(command, response));

    verify(command);
    verify(response);
    verify(cache);
    verify(backoffHandler);
  }
Example #5
0
  @Test
  public void test401ShouldRetry() {
    HttpCommand command = createMock(HttpCommand.class);
    HttpRequest request = createMock(HttpRequest.class);
    HttpResponse response = createMock(HttpResponse.class);
    @SuppressWarnings("unchecked")
    LoadingCache<Credentials, Access> cache = createMock(LoadingCache.class);
    BackoffLimitedRetryHandler backoffHandler = createMock(BackoffLimitedRetryHandler.class);

    expect(command.getCurrentRequest()).andReturn(request);

    cache.invalidateAll();
    expectLastCall();

    expect(response.getPayload()).andReturn(Payloads.newStringPayload("")).anyTimes();
    expect(response.getStatusCode()).andReturn(401).atLeastOnce();

    replay(command);
    replay(response);
    replay(cache);
    replay(backoffHandler);

    RetryOnRenew retry = new RetryOnRenew(cache, backoffHandler);

    assertTrue(retry.shouldRetryRequest(command, response));

    verify(command);
    verify(response);
    verify(cache);
  }
Example #6
0
  @Test
  public void test401ShouldRetry4Times() {
    HttpCommand command = createMock(HttpCommand.class);
    HttpRequest request = createMock(HttpRequest.class);
    HttpResponse response = createMock(HttpResponse.class);

    @SuppressWarnings("unchecked")
    LoadingCache<Credentials, Access> cache = createMock(LoadingCache.class);
    BackoffLimitedRetryHandler backoffHandler = createMock(BackoffLimitedRetryHandler.class);

    expect(command.getCurrentRequest()).andReturn(request).anyTimes();
    expect(request.getHeaders()).andStubReturn(null);

    cache.invalidateAll();
    expectLastCall().anyTimes();

    expect(response.getPayload()).andReturn(Payloads.newStringPayload("")).anyTimes();
    expect(response.getStatusCode()).andReturn(401).anyTimes();

    replay(command, request, response, cache);

    RetryOnRenew retry = new RetryOnRenew(cache, backoffHandler);

    for (int i = 0; i < RetryOnRenew.NUM_RETRIES - 1; ++i) {
      assertTrue(retry.shouldRetryRequest(command, response), "Expected retry to succeed");
    }

    assertFalse(
        retry.shouldRetryRequest(command, response),
        "Expected retry to fail on attempt " + RetryOnRenew.NUM_RETRIES);

    verify(command, response, cache);
  }
  private void assertCodeMakes(
      String method,
      URI uri,
      int statusCode,
      String message,
      String contentType,
      String content,
      Class<? extends Exception> expected) {

    ElasticStackErrorHandler function =
        Guice.createInjector().getInstance(ElasticStackErrorHandler.class);

    HttpCommand command = createMock(HttpCommand.class);
    HttpRequest request = new HttpRequest(method, uri);
    HttpResponse response =
        new HttpResponse(
            statusCode, message, Payloads.newInputStreamPayload(Strings2.toInputStream(content)));
    response.getPayload().getContentMetadata().setContentType(contentType);

    expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
    command.setException(classEq(expected));

    replay(command);

    function.handleError(command, response);

    verify(command);
  }
  private void assertCodeMakes(
      String method,
      URI uri,
      int statusCode,
      String message,
      String contentType,
      String content,
      Class<? extends Exception> expected) {

    SoftLayerErrorHandler function =
        Guice.createInjector().getInstance(SoftLayerErrorHandler.class);

    HttpCommand command = createMock(HttpCommand.class);
    HttpRequest request = HttpRequest.builder().method(method).endpoint(uri).build();
    HttpResponse response =
        HttpResponse.builder().statusCode(statusCode).message(message).payload(content).build();
    response.getPayload().getContentMetadata().setContentType(contentType);

    expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
    command.setException(classEq(expected));

    replay(command);

    function.handleError(command, response);

    verify(command);
  }
    public HttpResponse call() throws Exception {

      HttpResponse response = null;
      for (; ; ) {
        HttpRequest request = command.getCurrentRequest();
        Q nativeRequest = null;
        try {
          for (HttpRequestFilter filter : request.getFilters()) {
            request = filter.filter(request);
          }
          checkRequestHasContentLengthOrChunkedEncoding(
              request,
              "After filtering, the request has neither chunked encoding nor content length: "
                  + request);
          logger.debug("Sending request %s: %s", request.hashCode(), request.getRequestLine());
          wirePayloadIfEnabled(wire, request);
          utils.logRequest(headerLog, request, ">>");
          nativeRequest = convert(request);
          response = invoke(nativeRequest);

          logger.debug("Receiving response %s: %s", request.hashCode(), response.getStatusLine());
          utils.logResponse(headerLog, response, "<<");
          if (response.getPayload() != null && wire.enabled()) wire.input(response);
          int statusCode = response.getStatusCode();
          if (statusCode >= 300) {
            if (shouldContinue(response)) continue;
            else break;
          } else {
            break;
          }
        } catch (Exception e) {
          IOException ioe = Throwables2.getFirstThrowableOfType(e, IOException.class);
          if (ioe != null) {
            if (ioe instanceof SSLException) {
              command.setException(
                  new AuthorizationException(
                      e.getMessage()
                          + " connecting to "
                          + command.getCurrentRequest().getRequestLine(),
                      e));
              break;
            } else if (ioRetryHandler.shouldRetryRequest(command, ioe)) {
              continue;
            }
          }
          command.setException(
              new HttpResponseException(
                  e.getMessage() + " connecting to " + command.getCurrentRequest().getRequestLine(),
                  command,
                  null,
                  e));
          break;
        } finally {
          cleanup(nativeRequest);
        }
      }
      if (command.getException() != null) throw command.getException();
      return response;
    }
 static {
   EXPECTED =
       Guice.createInjector()
           .getInstance(AtmosObject.Factory.class)
           .create(
               ParseSystemMetadataFromHeadersTest.EXPECTED,
               ParseUserMetadataFromHeadersTest.EXPECTED);
   EXPECTED.getContentMetadata().setName("e913e09366364e9ba384b8fead643d43");
   EXPECTED.setPayload(RESPONSE.getPayload());
 }
Example #11
0
 public AWSError parseAWSErrorFromContent(HttpRequest request, HttpResponse response) {
   if (response.getPayload() == null) return null;
   if ("text/plain".equals(response.getPayload().getContentMetadata().getContentType()))
     return null;
   try {
     AWSError error =
         factory.create(errorHandlerProvider.get()).setContext(request).apply(response);
     if (error.getRequestId() == null)
       error.setRequestId(response.getFirstHeaderOrNull(requestId));
     error.setRequestToken(response.getFirstHeaderOrNull(requestToken));
     if ("SignatureDoesNotMatch".equals(error.getCode())) {
       error.setStringSigned(signer.createStringToSign(request));
       error.setSignature(signer.sign(error.getStringSigned()));
     }
     return error;
   } catch (RuntimeException e) {
     logger.warn(e, "error parsing error");
     return null;
   }
 }
  @Test
  void testClosesInputStream()
      throws InterruptedException, IOException, SecurityException, NoSuchMethodException {
    HttpCommand command = createCommand();

    HttpResponse response = new HttpResponse(400, null, null);

    InputStream inputStream =
        new InputStream() {
          boolean isOpen = true;

          @Override
          public void close() {
            this.isOpen = false;
          }

          int count = 1;

          @Override
          public int read() throws IOException {
            if (this.isOpen) return (count > -1) ? count-- : -1;
            else return -1;
          }

          @Override
          public int available() throws IOException {
            if (this.isOpen) return count;
            else return 0;
          }
        };
    response.setPayload(Payloads.newInputStreamPayload(inputStream));
    response.getPayload().getContentMetadata().setContentLength(1l);
    assertEquals(response.getPayload().getInput().available(), 1);
    assertEquals(response.getPayload().getInput().read(), 1);

    handler.shouldRetryRequest(command, response);

    assertEquals(response.getPayload().getInput().available(), 0);
    assertEquals(response.getPayload().getInput().read(), -1);
  }
 @Override
 public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
   if (response.getStatusCode() == 503) {
     // Content can be null in the case of HEAD requests
     if (response.getPayload() != null) {
       closeClientButKeepContentStream(response);
       AWSError error = utils.parseAWSErrorFromContent(command.getCurrentRequest(), response);
       if (error != null) {
         return shouldRetryRequestOnError(command, response, error);
       }
     }
   }
   return false;
 }
  @Override
  public B2Object apply(HttpResponse from) {
    Payload payload = from.getPayload();
    MutableContentMetadata contentMeta = payload.getContentMetadata();

    String fileId = from.getFirstHeaderOrNull(B2Headers.FILE_ID);
    String fileName;
    try {
      fileName = URLDecoder.decode(from.getFirstHeaderOrNull(B2Headers.FILE_NAME), "UTF-8");
    } catch (UnsupportedEncodingException uee) {
      throw Throwables.propagate(uee);
    }
    String contentSha1 = from.getFirstHeaderOrNull(B2Headers.CONTENT_SHA1);
    ImmutableMap.Builder<String, String> fileInfo = ImmutableMap.builder();
    for (Map.Entry<String, String> entry : from.getHeaders().entries()) {
      if (entry
          .getKey()
          .regionMatches(
              true, 0, B2Headers.FILE_INFO_PREFIX, 0, B2Headers.FILE_INFO_PREFIX.length())) {
        String value;
        try {
          value = URLDecoder.decode(entry.getValue(), "UTF-8");
        } catch (UnsupportedEncodingException uee) {
          throw Throwables.propagate(uee);
        }
        fileInfo.put(entry.getKey().substring(B2Headers.FILE_INFO_PREFIX.length()), value);
      }
    }
    Date uploadTimestamp =
        new Date(Long.parseLong(from.getFirstHeaderOrNull(B2Headers.UPLOAD_TIMESTAMP)));
    String contentRange = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_RANGE);

    return B2Object.create(
        fileId,
        fileName,
        null,
        null,
        contentMeta.getContentLength(),
        contentSha1,
        contentMeta.getContentType(),
        fileInfo.build(),
        null,
        uploadTimestamp.getTime(),
        contentRange,
        payload);
  }
  @Override
  public void handleError(final HttpCommand command, final HttpResponse response) {
    // it is important to always read fully and close streams
    String message = parseMessage(response);
    Exception exception =
        message == null
            ? new HttpResponseException(command, response)
            : new HttpResponseException(command, response, message);
    try {
      message =
          message == null
              ? String.format(
                  "%s -> %s",
                  command.getCurrentRequest().getRequestLine(), response.getStatusLine())
              : message;
      switch (response.getStatusCode()) {
        case 400:
          if (message.contains("unauthorized_client")) {
            exception = new AuthorizationException(message, exception);
          } else {
            exception = new IllegalArgumentException(message, exception);
          }
          break;
        case 401:
        case 403:
          exception = new AuthorizationException(message, exception);
          break;

        case 404:
          if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
            exception = new ResourceNotFoundException(message, exception);
          }
          break;
        case 409:
          exception = new IllegalStateException(message, exception);
          break;
        case 429:
          exception = new AzureComputeRateLimitExceededException(response, exception);
          break;
        default:
      }
    } finally {
      Closeables2.closeQuietly(response.getPayload());
      command.setException(exception);
    }
  }
  @Test
  public void testResponseLocationOk() throws Exception {
    Function<HttpResponse, URI> function =
        new ParseURIFromListOrLocationHeaderIf20x(uriBuilderProvider);
    HttpResponse response = createMock(HttpResponse.class);
    Payload payload = createMock(Payload.class);

    expect(response.getStatusCode()).andReturn(200).atLeastOnce();
    expect(response.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)).andReturn("text/plain");
    expect(response.getFirstHeaderOrNull(HttpHeaders.LOCATION)).andReturn("http://locahost");
    expect(response.getPayload()).andReturn(payload).atLeastOnce();
    payload.release();

    replay(payload);
    replay(response);
    assertEquals(function.apply(response), URI.create("http://locahost"));
    verify(response);
    verify(payload);
  }
  @Override
  public void handleError(final HttpCommand command, final HttpResponse response) {
    Exception exception = null;
    String defaultMessage =
        String.format(
            "%s -> %s", command.getCurrentRequest().getRequestLine(), response.getStatusLine());

    try {
      switch (response.getStatusCode()) {
        case 401:
        case 403:
          // Authorization exceptions do not return an errors DTO, so we
          // encapsulate a generic exception
          exception =
              new AuthorizationException(
                  defaultMessage, new HttpResponseException(command, response, defaultMessage));
          break;
        case 404:
          // TODO: get the exception to encapsulate from the returned error
          // object
          exception = new ResourceNotFoundException(defaultMessage);
          break;
        case 301:
          // Moved resources in Abiquo should be handled with the
          // ReturnMovedResource exception parser to return the moved
          // entity.
          exception = new HttpResponseException(command, response, defaultMessage);
          break;
        default:
          // TODO: get the exception to encapsulate from the returned error
          // object
          exception = new HttpResponseException(response.getMessage(), command, response);
          break;
      }
    } finally {
      closeQuietly(response.getPayload());
      command.setException(exception);
    }
  }
  private void assertCodeMakes(
      String method,
      URI uri,
      int statusCode,
      String message,
      String contentType,
      String content,
      Class<? extends Exception> expected) {

    ParseAzureBlobErrorFromXmlContent function =
        Guice.createInjector(
                new SaxParserModule(),
                new AbstractModule() {

                  @Override
                  protected void configure() {
                    bind(SharedKeyLiteAuthentication.class)
                        .toInstance(createMock(SharedKeyLiteAuthentication.class));
                  }
                })
            .getInstance(ParseAzureBlobErrorFromXmlContent.class);

    HttpCommand command = createMock(HttpCommand.class);
    HttpRequest request = new HttpRequest(method, uri);
    HttpResponse response =
        new HttpResponse(
            statusCode, message, Payloads.newInputStreamPayload(Strings2.toInputStream(content)));
    response.getPayload().getContentMetadata().setContentType(contentType);

    expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
    command.setException(classEq(expected));

    replay(command);

    function.handleError(command, response);

    verify(command);
  }
  private void assertCodeMakes(
      String method,
      URI uri,
      int statusCode,
      String message,
      String contentType,
      String content,
      Class<? extends Exception> expected) {

    ParseAWSErrorFromXmlContent function =
        Guice.createInjector(
                new SaxParserModule(),
                new AbstractModule() {

                  @Override
                  protected void configure() {
                    bind(RequestSigner.class).toInstance(createMock(RequestSigner.class));
                    bindConstant().annotatedWith(Names.named(PROPERTY_HEADER_TAG)).to("amz");
                  }
                })
            .getInstance(ParseAWSErrorFromXmlContent.class);

    HttpCommand command = createMock(HttpCommand.class);
    HttpRequest request = HttpRequest.builder().method(method).endpoint(uri).build();
    HttpResponse response =
        HttpResponse.builder().statusCode(statusCode).message(message).payload(content).build();
    response.getPayload().getContentMetadata().setContentType(contentType);

    expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
    command.setException(classEq(expected));

    replay(command);

    function.handleError(command, response);

    verify(command);
  }
  @Test
  public void testResponsePathSchemeLocationOk() throws Exception {
    ParseURIFromListOrLocationHeaderIf20x function =
        new ParseURIFromListOrLocationHeaderIf20x(uriBuilderProvider);
    HttpResponse response = createMock(HttpResponse.class);
    GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class);
    Payload payload = createMock(Payload.class);

    function.setContext(request);
    expect(request.getEndpoint()).andReturn(URI.create("https://new/fd")).atLeastOnce();
    expect(response.getStatusCode()).andReturn(200).atLeastOnce();
    expect(response.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE)).andReturn("text/plain");
    expect(response.getFirstHeaderOrNull(HttpHeaders.LOCATION)).andReturn("path");
    expect(response.getPayload()).andReturn(payload).atLeastOnce();
    payload.release();

    replay(request);
    replay(payload);
    replay(response);
    assertEquals(function.apply(response), URI.create("https://new/path"));
    verify(request);
    verify(response);
    verify(payload);
  }
  public void handleError(HttpCommand command, HttpResponse response) {
    HttpRequest request = command.getCurrentRequest();
    Exception exception = new HttpResponseException(command, response);
    try {
      VCloudError error = null;
      String message = null;
      if (response.getPayload() != null) {
        try {
          error = utils.parseErrorFromContent(request, response);
          if (error != null) {
            message = error.getMessage();
            exception = new VCloudResponseException(command, response, error);
          } else {
            message = Strings2.toStringAndClose(response.getPayload().getInput());
            exception =
                message != null ? new HttpResponseException(command, response, message) : exception;
          }
        } catch (IOException e) {
        } finally {
          response.getPayload().release();
        }
      }
      message =
          message != null
              ? message
              : String.format("%s -> %s", request.getRequestLine(), response.getStatusLine());

      switch (response.getStatusCode()) {
        case 400:
          if (error != null
              && ((error.getMinorErrorCode() != null
                      && error.getMinorErrorCode() == MinorCode.BUSY_ENTITY)
                  || (error.getMessage() != null
                      && error.getMessage().indexOf("is not running") != -1)))
            exception = new IllegalStateException(message, exception);
          else exception = new IllegalArgumentException(message, exception);
          break;
        case 401:
        case 403:
          if (error != null
              && ((error.getMinorErrorCode() != null
                      && error.getMinorErrorCode() == MinorCode.ACCESS_TO_RESOURCE_IS_FORBIDDEN)
                  || (error.getMessage() != null
                      && error.getMessage().indexOf("No access to entity") != -1)))
            exception = new ResourceNotFoundException(message, exception);
          else exception = new AuthorizationException(exception.getMessage(), exception);
          break;
        case 404:
          if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
            String path = command.getCurrentRequest().getEndpoint().getPath();
            Matcher matcher = RESOURCE_PATTERN.matcher(path);
            if (matcher.find()) {
              message = String.format("%s %s not found", matcher.group(1), matcher.group(2));
            } else {
              message = path;
            }
            exception = new ResourceNotFoundException(message);
          }
          break;
      }
    } finally {
      releasePayload(response);
      command.setException(exception);
    }
  }