ArtifactControllerHelper { public static void handlePartialDownload(InputStream is, HttpHeaders headers, HttpServletResponse response) throws IOException { String contentRange = headers.getFirst(HttpHeaders.RANGE); ByteRangeHeaderParser parser = new ByteRangeHeaderParser(contentRange); try { List<ByteRange> ranges = parser.getRanges(); if (!CollectionUtils.isEmpty(ranges)) { if (ranges.size() == 1) { logger.debug("Received request for a partial download with a single range."); handlePartialDownloadWithSingleRange(is, ranges.get(0), response); } else { logger.debug("Received request for a partial download with multiple ranges."); handlePartialDownloadWithMultipleRanges(is, ranges, response); } } } catch (ByteRangeValidationException e) { logger.error(e.getMessage(), e); ByteRangeInputStream bris = StreamUtils.findSource(ByteRangeInputStream.class, is); long length = bris != null ? StreamUtils.getLength(bris) : 0; setRangeNotSatisfiable(response, length); } } private  ArtifactControllerHelper(); static void handlePartialDownload(InputStream is,
                                             HttpHeaders headers,
                                             HttpServletResponse response); static boolean isRangedRequest(HttpHeaders headers); static void provideArtifactHeaders(HttpServletResponse response,
                                              RepositoryPath path); static final String MULTIPART_BOUNDARY; }
@ExtendWith({ RepositoryManagementTestExecutionListener.class, ArtifactManagementTestExecutionListener.class }) @Test void shouldNotHandlePartialDownloadWithSingleRangeWhenRequestedRangeNotSatisfiable( @MavenRepository(repositoryId = REPOSITORY_RELEASES_2) Repository repository, @MavenTestArtifact(repositoryId = REPOSITORY_RELEASES_2, id = "org.carlspring.strongbox:partial-single-not-satisfiable", versions = "1.0") Path artifactPath) throws IOException { RepositoryPath artifactRepositoryPath = (RepositoryPath) artifactPath.normalize(); try(InputStream is = artifactResolutionService.getInputStream(artifactRepositoryPath)) { long expectedLength = Files.size(artifactRepositoryPath); String byteRanges = String.format("%s-%s", expectedLength, expectedLength + 1); HttpHeaders httpHeaders = getHttpHeaders(byteRanges); HttpServletResponse response = new MockHttpServletResponse(); ArtifactControllerHelper.handlePartialDownload(is, httpHeaders, response); assertThat(response.getStatus()).isEqualTo(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value()); assertThat(response.getHeader(HttpHeaders.CONTENT_RANGE)).isEqualTo("bytes */" + expectedLength); } }
@ExtendWith({ RepositoryManagementTestExecutionListener.class, ArtifactManagementTestExecutionListener.class }) @Test void shouldNotHandlePartialDownloadWithSingleRangeWhenOffsetGreaterThanLimit( @MavenRepository(repositoryId = REPOSITORY_RELEASES_3) Repository repository, @MavenTestArtifact(repositoryId = REPOSITORY_RELEASES_3, id = "org.carlspring.strongbox:partial-multiple-not-satisfiable-validation", versions = "1.0") Path artifactPath) throws IOException { RepositoryPath artifactRepositoryPath = (RepositoryPath) artifactPath.normalize(); try(InputStream is = artifactResolutionService.getInputStream(artifactRepositoryPath)) { String byteRanges = "49-0"; HttpHeaders httpHeaders = getHttpHeaders(byteRanges); HttpServletResponse response = new MockHttpServletResponse(); ArtifactControllerHelper.handlePartialDownload(is, httpHeaders, response); assertThat(response.getStatus()).isEqualTo(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value()); assertThat(response.getHeader(HttpHeaders.CONTENT_RANGE)).startsWith("bytes */"); } }
@ExtendWith({ RepositoryManagementTestExecutionListener.class, ArtifactManagementTestExecutionListener.class }) @Test void shouldNotHandlePartialDownloadWithMultipleRangesWhenRequestedRangeNotSatisfiable( @MavenRepository(repositoryId = REPOSITORY_RELEASES_5) Repository repository, @MavenTestArtifact(repositoryId = REPOSITORY_RELEASES_5, id = "org.carlspring.strongbox:partial-multiple-not-satisfiable", versions = "1.0") Path artifactPath) throws IOException { RepositoryPath artifactRepositoryPath = (RepositoryPath) artifactPath.normalize(); try(InputStream is = artifactResolutionService.getInputStream(artifactRepositoryPath)) { long expectedLength = Files.size(artifactRepositoryPath); String byteRanges = String.format("0-49,%s-%s", expectedLength, expectedLength + 1); HttpHeaders httpHeaders = getHttpHeaders(byteRanges); HttpServletResponse response = new MockHttpServletResponse(); ArtifactControllerHelper.handlePartialDownload(is, httpHeaders, response); assertThat(response.getStatus()).isEqualTo(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value()); assertThat(response.getHeader(HttpHeaders.CONTENT_RANGE)).isEqualTo("bytes */" + expectedLength); } }
@ExtendWith({ RepositoryManagementTestExecutionListener.class, ArtifactManagementTestExecutionListener.class }) @Test void shouldNotHandlePartialDownloadWithMultipleRangesWhenOffsetGreaterThanLimit( @MavenRepository(repositoryId = REPOSITORY_RELEASES_6) Repository repository, @MavenTestArtifact(repositoryId = REPOSITORY_RELEASES_6, id = "org.carlspring.strongbox:partial-multiple-not-satisfiable-validation", versions = "1.0") Path artifactPath) throws IOException { RepositoryPath artifactRepositoryPath = (RepositoryPath) artifactPath.normalize(); try(InputStream is = artifactResolutionService.getInputStream(artifactRepositoryPath)) { String byteRanges = "49-0,60-55"; HttpHeaders httpHeaders = getHttpHeaders(byteRanges); HttpServletResponse response = new MockHttpServletResponse(); ArtifactControllerHelper.handlePartialDownload(is, httpHeaders, response); assertThat(response.getStatus()).isEqualTo(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value()); assertThat(response.getHeader(HttpHeaders.CONTENT_RANGE)).startsWith("bytes */"); } }