@Test(expectedExceptions = HttpDownloadContinuationException.class, expectedExceptionsMessageRegExp = ".*woops.*") public void buildContinuationRethrowsExceptionsDuringExecute() throws IOException { final HttpClient client = mock(HttpClient.class); when(client.execute(any(HttpUriRequest.class), any(HttpContext.class))).thenThrow(new IOException("woops")); new ApacheHttpGetResponseEntityContentContinuator(client, new HttpGet(), STUB_MARKER, INFINITE_CONTINUATIONS, null) .buildContinuation(new IOException(), 0); }
@Override public InputStream buildContinuation(final IOException ex, final long bytesRead) throws IOException { requireNonNull(ex); if (!isRecoverable(ex)) { throw ex; } this.continuation++; if (this.maxContinuations != INFINITE_CONTINUATIONS && this.maxContinuations <= this.continuation) { throw new HttpDownloadContinuationException( String.format("Maximum number of continuations reached [%s], aborting auto-retry: %s", this.maxContinuations, ex.getMessage()), ex); } LOG.debug("Attempting to build a continuation for " + "[{}] request " + "to path [{}] " + "to recover at byte offset {} " + "from exception {}", this.request.getMethod(), this.request.getRequestLine().getUri(), bytesRead, ex.getMessage()); if (bytesRead == this.marker.getTotalRangeSize()) { if (this.metricRegistry != null) { this.metricRegistry.counter(METRIC_NAME_RECOVERED_EXCEPTION_PREFIX + ex.getClass().getSimpleName()) .inc(); this.metricRegistry.counter(METRIC_NAME_RECOVERED_EOF).inc(); } return ClosedInputStream.CLOSED_INPUT_STREAM; } try { this.marker.updateRangeStart(bytesRead); } catch (final IllegalArgumentException iae) { throw new HttpDownloadContinuationException("Failed to update download continuation offset", iae); } this.request.setHeader(RANGE, this.marker.getCurrentRange().render()); final HttpResponse response; try { final HttpContext httpContext = new BasicHttpContext(); httpContext.setAttribute(CONTEXT_ATTRIBUTE_MANTA_RETRY_DISABLE, true); response = this.client.execute(this.request, httpContext); } catch (final IOException ioe) { throw new HttpDownloadContinuationException( "Exception occurred while attempting to build continuation: " + ioe.getMessage(), ioe); } final int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != SC_PARTIAL_CONTENT) { throw new HttpDownloadContinuationUnexpectedResponseException( String.format( "Invalid response code: expecting [%d], got [%d]", SC_PARTIAL_CONTENT, statusCode)); } try { validateResponseWithMarker(extractDownloadResponseFingerprint(response, false)); } catch (final HttpException he) { throw new HttpDownloadContinuationUnexpectedResponseException( "Continuation request failed validation: " + he.getMessage(), he); } final InputStream content; try { final HttpEntity entity = response.getEntity(); if (entity == null) { throw new HttpDownloadContinuationUnexpectedResponseException( "Entity missing from continuation response"); } content = entity.getContent(); if (content == null) { throw new HttpDownloadContinuationUnexpectedResponseException( "Entity content missing from continuation response"); } } catch (final UnsupportedOperationException | IOException uoe) { throw new HttpDownloadContinuationUnexpectedResponseException(uoe); } if (this.metricRegistry != null) { this.metricRegistry.counter(METRIC_NAME_RECOVERED_EXCEPTION_PREFIX + ex.getClass().getSimpleName()).inc(); } LOG.debug("Successfully constructed continuation at byte offset {} to recover from {}", bytesRead, ex); return content; }
ApacheHttpGetResponseEntityContentContinuator implements InputStreamContinuator { @Override public InputStream buildContinuation(final IOException ex, final long bytesRead) throws IOException { requireNonNull(ex); if (!isRecoverable(ex)) { throw ex; } this.continuation++; if (this.maxContinuations != INFINITE_CONTINUATIONS && this.maxContinuations <= this.continuation) { throw new HttpDownloadContinuationException( String.format("Maximum number of continuations reached [%s], aborting auto-retry: %s", this.maxContinuations, ex.getMessage()), ex); } LOG.debug("Attempting to build a continuation for " + "[{}] request " + "to path [{}] " + "to recover at byte offset {} " + "from exception {}", this.request.getMethod(), this.request.getRequestLine().getUri(), bytesRead, ex.getMessage()); if (bytesRead == this.marker.getTotalRangeSize()) { if (this.metricRegistry != null) { this.metricRegistry.counter(METRIC_NAME_RECOVERED_EXCEPTION_PREFIX + ex.getClass().getSimpleName()) .inc(); this.metricRegistry.counter(METRIC_NAME_RECOVERED_EOF).inc(); } return ClosedInputStream.CLOSED_INPUT_STREAM; } try { this.marker.updateRangeStart(bytesRead); } catch (final IllegalArgumentException iae) { throw new HttpDownloadContinuationException("Failed to update download continuation offset", iae); } this.request.setHeader(RANGE, this.marker.getCurrentRange().render()); final HttpResponse response; try { final HttpContext httpContext = new BasicHttpContext(); httpContext.setAttribute(CONTEXT_ATTRIBUTE_MANTA_RETRY_DISABLE, true); response = this.client.execute(this.request, httpContext); } catch (final IOException ioe) { throw new HttpDownloadContinuationException( "Exception occurred while attempting to build continuation: " + ioe.getMessage(), ioe); } final int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != SC_PARTIAL_CONTENT) { throw new HttpDownloadContinuationUnexpectedResponseException( String.format( "Invalid response code: expecting [%d], got [%d]", SC_PARTIAL_CONTENT, statusCode)); } try { validateResponseWithMarker(extractDownloadResponseFingerprint(response, false)); } catch (final HttpException he) { throw new HttpDownloadContinuationUnexpectedResponseException( "Continuation request failed validation: " + he.getMessage(), he); } final InputStream content; try { final HttpEntity entity = response.getEntity(); if (entity == null) { throw new HttpDownloadContinuationUnexpectedResponseException( "Entity missing from continuation response"); } content = entity.getContent(); if (content == null) { throw new HttpDownloadContinuationUnexpectedResponseException( "Entity content missing from continuation response"); } } catch (final UnsupportedOperationException | IOException uoe) { throw new HttpDownloadContinuationUnexpectedResponseException(uoe); } if (this.metricRegistry != null) { this.metricRegistry.counter(METRIC_NAME_RECOVERED_EXCEPTION_PREFIX + ex.getClass().getSimpleName()).inc(); } LOG.debug("Successfully constructed continuation at byte offset {} to recover from {}", bytesRead, ex); return content; } }
ApacheHttpGetResponseEntityContentContinuator implements InputStreamContinuator { @Override public InputStream buildContinuation(final IOException ex, final long bytesRead) throws IOException { requireNonNull(ex); if (!isRecoverable(ex)) { throw ex; } this.continuation++; if (this.maxContinuations != INFINITE_CONTINUATIONS && this.maxContinuations <= this.continuation) { throw new HttpDownloadContinuationException( String.format("Maximum number of continuations reached [%s], aborting auto-retry: %s", this.maxContinuations, ex.getMessage()), ex); } LOG.debug("Attempting to build a continuation for " + "[{}] request " + "to path [{}] " + "to recover at byte offset {} " + "from exception {}", this.request.getMethod(), this.request.getRequestLine().getUri(), bytesRead, ex.getMessage()); if (bytesRead == this.marker.getTotalRangeSize()) { if (this.metricRegistry != null) { this.metricRegistry.counter(METRIC_NAME_RECOVERED_EXCEPTION_PREFIX + ex.getClass().getSimpleName()) .inc(); this.metricRegistry.counter(METRIC_NAME_RECOVERED_EOF).inc(); } return ClosedInputStream.CLOSED_INPUT_STREAM; } try { this.marker.updateRangeStart(bytesRead); } catch (final IllegalArgumentException iae) { throw new HttpDownloadContinuationException("Failed to update download continuation offset", iae); } this.request.setHeader(RANGE, this.marker.getCurrentRange().render()); final HttpResponse response; try { final HttpContext httpContext = new BasicHttpContext(); httpContext.setAttribute(CONTEXT_ATTRIBUTE_MANTA_RETRY_DISABLE, true); response = this.client.execute(this.request, httpContext); } catch (final IOException ioe) { throw new HttpDownloadContinuationException( "Exception occurred while attempting to build continuation: " + ioe.getMessage(), ioe); } final int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != SC_PARTIAL_CONTENT) { throw new HttpDownloadContinuationUnexpectedResponseException( String.format( "Invalid response code: expecting [%d], got [%d]", SC_PARTIAL_CONTENT, statusCode)); } try { validateResponseWithMarker(extractDownloadResponseFingerprint(response, false)); } catch (final HttpException he) { throw new HttpDownloadContinuationUnexpectedResponseException( "Continuation request failed validation: " + he.getMessage(), he); } final InputStream content; try { final HttpEntity entity = response.getEntity(); if (entity == null) { throw new HttpDownloadContinuationUnexpectedResponseException( "Entity missing from continuation response"); } content = entity.getContent(); if (content == null) { throw new HttpDownloadContinuationUnexpectedResponseException( "Entity content missing from continuation response"); } } catch (final UnsupportedOperationException | IOException uoe) { throw new HttpDownloadContinuationUnexpectedResponseException(uoe); } if (this.metricRegistry != null) { this.metricRegistry.counter(METRIC_NAME_RECOVERED_EXCEPTION_PREFIX + ex.getClass().getSimpleName()).inc(); } LOG.debug("Successfully constructed continuation at byte offset {} to recover from {}", bytesRead, ex); return content; } ApacheHttpGetResponseEntityContentContinuator(final MantaApacheHttpClientContext connCtx,
                                                  final HttpGet request,
                                                  final HttpDownloadContinuationMarker marker,
                                                  final int maxContinuations);   ApacheHttpGetResponseEntityContentContinuator(final HttpClient client,
                                                  final HttpGet request,
                                                  final HttpDownloadContinuationMarker marker,
                                                  final int maxContinuations,
                                                  final MetricRegistry metricRegistry); }
ApacheHttpGetResponseEntityContentContinuator implements InputStreamContinuator { @Override public InputStream buildContinuation(final IOException ex, final long bytesRead) throws IOException { requireNonNull(ex); if (!isRecoverable(ex)) { throw ex; } this.continuation++; if (this.maxContinuations != INFINITE_CONTINUATIONS && this.maxContinuations <= this.continuation) { throw new HttpDownloadContinuationException( String.format("Maximum number of continuations reached [%s], aborting auto-retry: %s", this.maxContinuations, ex.getMessage()), ex); } LOG.debug("Attempting to build a continuation for " + "[{}] request " + "to path [{}] " + "to recover at byte offset {} " + "from exception {}", this.request.getMethod(), this.request.getRequestLine().getUri(), bytesRead, ex.getMessage()); if (bytesRead == this.marker.getTotalRangeSize()) { if (this.metricRegistry != null) { this.metricRegistry.counter(METRIC_NAME_RECOVERED_EXCEPTION_PREFIX + ex.getClass().getSimpleName()) .inc(); this.metricRegistry.counter(METRIC_NAME_RECOVERED_EOF).inc(); } return ClosedInputStream.CLOSED_INPUT_STREAM; } try { this.marker.updateRangeStart(bytesRead); } catch (final IllegalArgumentException iae) { throw new HttpDownloadContinuationException("Failed to update download continuation offset", iae); } this.request.setHeader(RANGE, this.marker.getCurrentRange().render()); final HttpResponse response; try { final HttpContext httpContext = new BasicHttpContext(); httpContext.setAttribute(CONTEXT_ATTRIBUTE_MANTA_RETRY_DISABLE, true); response = this.client.execute(this.request, httpContext); } catch (final IOException ioe) { throw new HttpDownloadContinuationException( "Exception occurred while attempting to build continuation: " + ioe.getMessage(), ioe); } final int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != SC_PARTIAL_CONTENT) { throw new HttpDownloadContinuationUnexpectedResponseException( String.format( "Invalid response code: expecting [%d], got [%d]", SC_PARTIAL_CONTENT, statusCode)); } try { validateResponseWithMarker(extractDownloadResponseFingerprint(response, false)); } catch (final HttpException he) { throw new HttpDownloadContinuationUnexpectedResponseException( "Continuation request failed validation: " + he.getMessage(), he); } final InputStream content; try { final HttpEntity entity = response.getEntity(); if (entity == null) { throw new HttpDownloadContinuationUnexpectedResponseException( "Entity missing from continuation response"); } content = entity.getContent(); if (content == null) { throw new HttpDownloadContinuationUnexpectedResponseException( "Entity content missing from continuation response"); } } catch (final UnsupportedOperationException | IOException uoe) { throw new HttpDownloadContinuationUnexpectedResponseException(uoe); } if (this.metricRegistry != null) { this.metricRegistry.counter(METRIC_NAME_RECOVERED_EXCEPTION_PREFIX + ex.getClass().getSimpleName()).inc(); } LOG.debug("Successfully constructed continuation at byte offset {} to recover from {}", bytesRead, ex); return content; } ApacheHttpGetResponseEntityContentContinuator(final MantaApacheHttpClientContext connCtx,
                                                  final HttpGet request,
                                                  final HttpDownloadContinuationMarker marker,
                                                  final int maxContinuations);   ApacheHttpGetResponseEntityContentContinuator(final HttpClient client,
                                                  final HttpGet request,
                                                  final HttpDownloadContinuationMarker marker,
                                                  final int maxContinuations,
                                                  final MetricRegistry metricRegistry); @Override InputStream buildContinuation(final IOException ex, final long bytesRead); @Override void close(); }
ApacheHttpGetResponseEntityContentContinuator implements InputStreamContinuator { @Override public InputStream buildContinuation(final IOException ex, final long bytesRead) throws IOException { requireNonNull(ex); if (!isRecoverable(ex)) { throw ex; } this.continuation++; if (this.maxContinuations != INFINITE_CONTINUATIONS && this.maxContinuations <= this.continuation) { throw new HttpDownloadContinuationException( String.format("Maximum number of continuations reached [%s], aborting auto-retry: %s", this.maxContinuations, ex.getMessage()), ex); } LOG.debug("Attempting to build a continuation for " + "[{}] request " + "to path [{}] " + "to recover at byte offset {} " + "from exception {}", this.request.getMethod(), this.request.getRequestLine().getUri(), bytesRead, ex.getMessage()); if (bytesRead == this.marker.getTotalRangeSize()) { if (this.metricRegistry != null) { this.metricRegistry.counter(METRIC_NAME_RECOVERED_EXCEPTION_PREFIX + ex.getClass().getSimpleName()) .inc(); this.metricRegistry.counter(METRIC_NAME_RECOVERED_EOF).inc(); } return ClosedInputStream.CLOSED_INPUT_STREAM; } try { this.marker.updateRangeStart(bytesRead); } catch (final IllegalArgumentException iae) { throw new HttpDownloadContinuationException("Failed to update download continuation offset", iae); } this.request.setHeader(RANGE, this.marker.getCurrentRange().render()); final HttpResponse response; try { final HttpContext httpContext = new BasicHttpContext(); httpContext.setAttribute(CONTEXT_ATTRIBUTE_MANTA_RETRY_DISABLE, true); response = this.client.execute(this.request, httpContext); } catch (final IOException ioe) { throw new HttpDownloadContinuationException( "Exception occurred while attempting to build continuation: " + ioe.getMessage(), ioe); } final int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != SC_PARTIAL_CONTENT) { throw new HttpDownloadContinuationUnexpectedResponseException( String.format( "Invalid response code: expecting [%d], got [%d]", SC_PARTIAL_CONTENT, statusCode)); } try { validateResponseWithMarker(extractDownloadResponseFingerprint(response, false)); } catch (final HttpException he) { throw new HttpDownloadContinuationUnexpectedResponseException( "Continuation request failed validation: " + he.getMessage(), he); } final InputStream content; try { final HttpEntity entity = response.getEntity(); if (entity == null) { throw new HttpDownloadContinuationUnexpectedResponseException( "Entity missing from continuation response"); } content = entity.getContent(); if (content == null) { throw new HttpDownloadContinuationUnexpectedResponseException( "Entity content missing from continuation response"); } } catch (final UnsupportedOperationException | IOException uoe) { throw new HttpDownloadContinuationUnexpectedResponseException(uoe); } if (this.metricRegistry != null) { this.metricRegistry.counter(METRIC_NAME_RECOVERED_EXCEPTION_PREFIX + ex.getClass().getSimpleName()).inc(); } LOG.debug("Successfully constructed continuation at byte offset {} to recover from {}", bytesRead, ex); return content; } ApacheHttpGetResponseEntityContentContinuator(final MantaApacheHttpClientContext connCtx,
                                                  final HttpGet request,
                                                  final HttpDownloadContinuationMarker marker,
                                                  final int maxContinuations);   ApacheHttpGetResponseEntityContentContinuator(final HttpClient client,
                                                  final HttpGet request,
                                                  final HttpDownloadContinuationMarker marker,
                                                  final int maxContinuations,
                                                  final MetricRegistry metricRegistry); @Override InputStream buildContinuation(final IOException ex, final long bytesRead); @Override void close();  }