From 96a8ad0461b4721775ff10cf2a32712cac840686 Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Tue, 6 Feb 2018 08:32:36 +0100 Subject: [PATCH] Artefact last modified is returned my DMF auth call (#600) * Last modified is stored as part of artifact and returns accordingly by APIs. Signed-off-by: kaizimmerm * Fixed tests. Signed-off-by: kaizimmerm * Check value > 0 Signed-off-by: kaizimmerm * Use created at. Signed-off-by: kaizimmerm * Sonar issue fixed. Signed-off-by: kaizimmerm --- .../ddi/rest/resource/DdiRootController.java | 3 +-- .../rest/resource/DdiRootControllerTest.java | 2 +- .../AmqpAuthenticationMessageHandler.java | 1 + .../AmqpControllerAuthenticationTest.java | 4 ++-- ...ticationMessageHandlerIntegrationTest.java | 2 ++ .../hawkbit/dmf/json/model/DmfArtifact.java | 20 +++++++++++++------ .../MgmtDownloadArtifactResource.java | 5 +---- .../rest/resource/MgmtDownloadResource.java | 2 +- .../rest/resource/MgmtRestModelMapper.java | 4 ++-- .../resource/MgmtDownloadResourceTest.java | 12 +++++------ .../rest/resource/MgmtTargetResourceTest.java | 2 +- .../hawkbit/repository/model/BaseEntity.java | 4 ++-- .../jpa/model/AbstractJpaBaseEntity.java | 12 +++++------ .../jpa/DeploymentManagementTest.java | 2 +- .../hawkbit/rest/util/FileStreamingUtil.java | 6 +++--- 15 files changed, 44 insertions(+), 37 deletions(-) diff --git a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java index c858768c6..674c721e0 100644 --- a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java +++ b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java @@ -179,8 +179,7 @@ public class DdiRootController implements DdiRootControllerRestApi { final Long statusId = action.getId(); - result = FileStreamingUtil.writeFileResponse(file, artifact.getFilename(), - artifact.getLastModifiedAt() != null ? artifact.getLastModifiedAt() : artifact.getCreatedAt(), + result = FileStreamingUtil.writeFileResponse(file, artifact.getFilename(), artifact.getCreatedAt(), requestResponseContextHolder.getHttpServletResponse(), requestResponseContextHolder.getHttpServletRequest(), (length, shippedSinceLastEvent, total) -> eventPublisher diff --git a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java index bad2d28f0..bfbdbd7ed 100644 --- a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java +++ b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java @@ -299,7 +299,7 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { assertThat(target.getCreatedBy()).isEqualTo("CONTROLLER_PLUG_AND_PLAY"); assertThat(target.getCreatedAt()).isGreaterThanOrEqualTo(create); assertThat(target.getLastModifiedBy()).isNull(); - assertThat(target.getLastModifiedAt()).isNull(); + assertThat(target.getLastModifiedAt()).isZero(); } diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpAuthenticationMessageHandler.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpAuthenticationMessageHandler.java index 5394a4cd3..ee07e726a 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpAuthenticationMessageHandler.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpAuthenticationMessageHandler.java @@ -189,6 +189,7 @@ public class AmqpAuthenticationMessageHandler extends BaseAmqpService { private static DmfArtifact convertDbArtifact(final Artifact dbArtifact) { final DmfArtifact artifact = new DmfArtifact(); artifact.setSize(dbArtifact.getSize()); + artifact.setLastModified(dbArtifact.getCreatedAt()); artifact.setHashes(new DmfArtifactHash(dbArtifact.getSha1Hash(), dbArtifact.getMd5Hash())); return artifact; } diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java index b7bb911b9..037381213 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java @@ -40,10 +40,10 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.repository.model.TenantMetaData; import org.eclipse.hawkbit.security.DdiSecurityProperties; -import org.eclipse.hawkbit.security.DmfTenantSecurityToken; import org.eclipse.hawkbit.security.DdiSecurityProperties.Authentication.Anonymous; -import org.eclipse.hawkbit.security.DmfTenantSecurityToken.FileResource; import org.eclipse.hawkbit.security.DdiSecurityProperties.Rp; +import org.eclipse.hawkbit.security.DmfTenantSecurityToken; +import org.eclipse.hawkbit.security.DmfTenantSecurityToken.FileResource; import org.eclipse.hawkbit.security.SecurityContextTenantAware; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpAuthenticationMessageHandlerIntegrationTest.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpAuthenticationMessageHandlerIntegrationTest.java index 27dbfc75e..9c2d39b6d 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpAuthenticationMessageHandlerIntegrationTest.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpAuthenticationMessageHandlerIntegrationTest.java @@ -380,6 +380,8 @@ public class AmqpAuthenticationMessageHandlerIntegrationTest extends AbstractAmq final DmfDownloadResponse convertedMessage = verifyResult(returnMessage, HttpStatus.OK, null); assertThat(convertedMessage.getDownloadUrl()).isNotNull(); assertThat(convertedMessage.getArtifact()).isNotNull(); + assertThat(convertedMessage.getArtifact().getLastModified()) + .isEqualTo(artifactManagement.findFirstBySHA1(artifact.getSha1Hash()).get().getCreatedAt()); assertThat(convertedMessage.getArtifact().getHashes().getSha1()).isEqualTo(artifact.getSha1Hash()); } diff --git a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfArtifact.java b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfArtifact.java index 8c58f631b..09ecf6884 100644 --- a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfArtifact.java +++ b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfArtifact.java @@ -18,9 +18,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; /** * JSON representation of artifact. - * - * - * */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) @@ -32,7 +29,10 @@ public class DmfArtifact { private DmfArtifactHash hashes; @JsonProperty - private Long size; + private long size; + + @JsonProperty + private long lastModified; @JsonProperty private Map urls; @@ -45,6 +45,14 @@ public class DmfArtifact { return Collections.unmodifiableMap(urls); } + public long getLastModified() { + return lastModified; + } + + public void setLastModified(final long lastModified) { + this.lastModified = lastModified; + } + public void setUrls(final Map urls) { this.urls = urls; } @@ -65,11 +73,11 @@ public class DmfArtifact { this.hashes = hashes; } - public Long getSize() { + public long getSize() { return size; } - public void setSize(final Long size) { + public void setSize(final long size) { this.size = size; } diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadArtifactResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadArtifactResource.java index 654839018..9d7ef4f6c 100644 --- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadArtifactResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadArtifactResource.java @@ -23,8 +23,6 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.rest.util.FileStreamingUtil; import org.eclipse.hawkbit.rest.util.HttpUtil; import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.http.HttpHeaders; @@ -76,8 +74,7 @@ public class MgmtDownloadArtifactResource implements MgmtDownloadArtifactRestApi return new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED); } - return FileStreamingUtil.writeFileResponse(file, artifact.getFilename(), - artifact.getLastModifiedAt() != null ? artifact.getLastModifiedAt() : artifact.getCreatedAt(), + return FileStreamingUtil.writeFileResponse(file, artifact.getFilename(), artifact.getCreatedAt(), requestResponseContextHolder.getHttpServletResponse(), request, null); } diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResource.java index e3b9193ce..997d193df 100644 --- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResource.java @@ -72,7 +72,7 @@ public class MgmtDownloadResource implements MgmtDownloadRestApi { return ResponseEntity.notFound().build(); } - return FileStreamingUtil.writeFileResponse(artifact, downloadId, null, + return FileStreamingUtil.writeFileResponse(artifact, downloadId, 0L, requestResponseContextHolder.getHttpServletResponse(), requestResponseContextHolder.getHttpServletRequest(), null); diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRestModelMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRestModelMapper.java index 7a5c36f16..f26e734ac 100644 --- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRestModelMapper.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRestModelMapper.java @@ -30,10 +30,10 @@ final class MgmtRestModelMapper { static void mapBaseToBase(final MgmtBaseEntity response, final TenantAwareBaseEntity base) { response.setCreatedBy(base.getCreatedBy()); response.setLastModifiedBy(base.getLastModifiedBy()); - if (base.getCreatedAt() != null) { + if (base.getCreatedAt() > 0) { response.setCreatedAt(base.getCreatedAt()); } - if (base.getLastModifiedAt() != null) { + if (base.getLastModifiedAt() > 0) { response.setLastModifiedAt(base.getLastModifiedAt()); } } diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResourceTest.java index fcf24be27..0d706daf0 100644 --- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDownloadResourceTest.java @@ -34,9 +34,9 @@ public class MgmtDownloadResourceTest extends AbstractManagementApiIntegrationTe @Autowired private DownloadIdCache downloadIdCache; - private final String downloadIdSha1 = "downloadIdSha1"; + private static final String DOWNLOAD_ID_SHA1 = "downloadIdSha1"; - private final String downloadIdNotAvailable = "downloadIdNotAvailable"; + private static final String DOWNLOAD_ID_NOT_AVAILABLE = "downloadIdNotAvailable"; @Before public void setupCache() { @@ -45,7 +45,7 @@ public class MgmtDownloadResourceTest extends AbstractManagementApiIntegrationTe final SoftwareModule softwareModule = distributionSet.getModules().stream().findAny().get(); final Artifact artifact = testdataFactory.createArtifacts(softwareModule.getId()).stream().findAny().get(); - downloadIdCache.put(downloadIdSha1, new DownloadArtifactCache(DownloadType.BY_SHA1, artifact.getSha1Hash())); + downloadIdCache.put(DOWNLOAD_ID_SHA1, new DownloadArtifactCache(DownloadType.BY_SHA1, artifact.getSha1Hash())); } @Test @@ -54,7 +54,7 @@ public class MgmtDownloadResourceTest extends AbstractManagementApiIntegrationTe mvc.perform(get( MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, - tenantAware.getCurrentTenant(), downloadIdNotAvailable)).andDo(MockMvcResultPrinter.print()) + tenantAware.getCurrentTenant(), DOWNLOAD_ID_NOT_AVAILABLE)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); } @@ -65,14 +65,14 @@ public class MgmtDownloadResourceTest extends AbstractManagementApiIntegrationTe mvc.perform(get( MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, - tenantAware.getCurrentTenant(), downloadIdSha1)).andDo(MockMvcResultPrinter.print()) + tenantAware.getCurrentTenant(), DOWNLOAD_ID_SHA1)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isOk()); // because cache is empty mvc.perform(get( MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE + MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING, - tenantAware.getCurrentTenant(), downloadIdSha1)).andDo(MockMvcResultPrinter.print()) + tenantAware.getCurrentTenant(), DOWNLOAD_ID_SHA1)).andDo(MockMvcResultPrinter.print()) .andExpect(status().isNotFound()); } diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java index 1d20fe0c4..894cd1f7a 100644 --- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java @@ -129,7 +129,7 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest .andExpect(jsonPath("content.[0].id", equalTo(status.getId().intValue()))) .andExpect(jsonPath("content.[0].type", equalTo("finished"))) .andExpect(jsonPath("content.[0].messages", hasSize(1))) - .andExpect(jsonPath("content.[0].reportedAt", equalTo(status.getCreatedAt().longValue()))) + .andExpect(jsonPath("content.[0].reportedAt", equalTo(status.getCreatedAt()))) .andExpect(jsonPath("content.[1].type", equalTo("canceling"))); } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/BaseEntity.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/BaseEntity.java index 94cbc16cd..7c56647f6 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/BaseEntity.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/BaseEntity.java @@ -27,7 +27,7 @@ public interface BaseEntity extends Serializable, Identifiable { * @return time in {@link TimeUnit#MILLISECONDS} when the {@link BaseEntity} * was created. */ - Long getCreatedAt(); + long getCreatedAt(); /** * @return user that created the {@link BaseEntity}. @@ -38,7 +38,7 @@ public interface BaseEntity extends Serializable, Identifiable { * @return time in {@link TimeUnit#MILLISECONDS} when the {@link BaseEntity} * was last time changed. */ - Long getLastModifiedAt(); + long getLastModifiedAt(); /** * @return user that updated the {@link BaseEntity} last. diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java index 7431041b2..48189720b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java @@ -44,8 +44,8 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity { private String createdBy; private String lastModifiedBy; - private Long createdAt; - private Long lastModifiedAt; + private long createdAt; + private long lastModifiedAt; @Version @Column(name = "optlock_revision") @@ -61,7 +61,7 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity { @Override @Access(AccessType.PROPERTY) @Column(name = "created_at", insertable = true, updatable = false) - public Long getCreatedAt() { + public long getCreatedAt() { return createdAt; } @@ -75,7 +75,7 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity { @Override @Access(AccessType.PROPERTY) @Column(name = "last_modified_at", insertable = true, updatable = true) - public Long getLastModifiedAt() { + public long getLastModifiedAt() { return lastModifiedAt; } @@ -97,12 +97,12 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity { } @CreatedDate - public void setCreatedAt(final Long createdAt) { + public void setCreatedAt(final long createdAt) { this.createdAt = createdAt; } @LastModifiedDate - public void setLastModifiedAt(final Long lastModifiedAt) { + public void setLastModifiedAt(final long lastModifiedAt) { if (isController()) { return; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java index 21de98ad7..a46d2ca96 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java @@ -458,7 +458,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest { .as("TargetUpdateStatus IN_SYNC") .allMatch(target -> TargetUpdateStatus.IN_SYNC.equals(target.getUpdateStatus())) .as("InstallationDate equal to LastModifiedAt") - .allMatch(target -> target.getLastModifiedAt().equals(target.getInstallationDate())); + .allMatch(target -> target.getLastModifiedAt() == target.getInstallationDate()); } @Test diff --git a/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/FileStreamingUtil.java b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/FileStreamingUtil.java index fef8d7b9e..e56518edc 100644 --- a/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/FileStreamingUtil.java +++ b/hawkbit-rest-core/src/main/java/org/eclipse/hawkbit/rest/util/FileStreamingUtil.java @@ -119,7 +119,7 @@ public final class FileStreamingUtil { * if streaming fails */ public static ResponseEntity writeFileResponse(final AbstractDbArtifact artifact, - final String filename, final Long lastModified, final HttpServletResponse response, + final String filename, final long lastModified, final HttpServletResponse response, final HttpServletRequest request, final FileStreamingProgressListener progressListener) { ResponseEntity result; @@ -131,7 +131,7 @@ public final class FileStreamingUtil { response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + filename); response.setHeader(HttpHeaders.ETAG, etag); response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes"); - if (lastModified != null) { + if (lastModified > 0) { response.setDateHeader(HttpHeaders.LAST_MODIFIED, lastModified); } @@ -143,7 +143,7 @@ public final class FileStreamingUtil { // Validate and process Range and If-Range headers. final String range = request.getHeader("Range"); - if (lastModified != null && range != null) { + if (lastModified > 0 && range != null) { LOG.debug("range header for filename ({}) is: {}", filename, range); // Range header matches"bytes=n-n,n-n,n-n..."