@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); } }
@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); }
@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); }
@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()); }
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); } }