Remove module for legacy download API (never used by hawkBit). (#500)
* Remove module for legacy download API (never used by hawkBit). Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Add stream aware error controller. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Fixed bean definition. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
@@ -289,9 +289,10 @@ public class SecurityManagedConfiguration {
|
||||
// in the ShallowEtagHeaderFilter, just using the SH1 hash of the
|
||||
// artifact itself as 'ETag', because otherwise the file will be copied
|
||||
// in memory!
|
||||
filterRegBean.setFilter(new ExcludePathAwareShallowETagFilter(
|
||||
"/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download", "/{tenant}/controller/artifacts/**",
|
||||
"/{targetid}/softwaremodules/{softwareModuleId}/artifacts/**", "/api/v1/downloadserver/**"));
|
||||
filterRegBean.setFilter(
|
||||
new ExcludePathAwareShallowETagFilter("/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download",
|
||||
"/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/**",
|
||||
"/api/v1/downloadserver/**"));
|
||||
|
||||
return filterRegBean;
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# Eclipse.IoT hawkBit - DDI Artifact Download API - Resources
|
||||
|
||||
This module is part of the Direct Device Integration (DDI) API and is used by devices/targets for downloading artifacts through HTTP.
|
||||
|
||||
# Version 1
|
||||
|
||||
The model follows [semantic versioning](http://semver.org) with MAJOR version, i.e. breaking changes will result in a new MAJOR version.
|
||||
|
||||
# Compile
|
||||
|
||||
#### Build hawkbit-ddi-dl-api
|
||||
|
||||
```
|
||||
$ cd hawkbit/hawkbit-ddi-dl-api
|
||||
$ mvn clean install
|
||||
```
|
||||
@@ -1,28 +0,0 @@
|
||||
<!--
|
||||
|
||||
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
which accompanies this distribution, and is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
|
||||
-->
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.eclipse.hawkbit</groupId>
|
||||
<artifactId>hawkbit-parent</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>hawkbit-ddi-dl-api</artifactId>
|
||||
<name>hawkBit :: DDI Download Server (DL) API</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ddi.dl.rest.api;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* REST resource handling for artifact download operations.
|
||||
*/
|
||||
@RequestMapping(DdiDlRestConstants.ARTIFACTS_V1_REQUEST_MAPPING)
|
||||
public interface DdiDlArtifactStoreControllerRestApi {
|
||||
|
||||
/**
|
||||
* Handles GET download request. This could be full or partial download
|
||||
* request.
|
||||
*
|
||||
* @param tenant
|
||||
* name of the client
|
||||
* @param fileName
|
||||
* to search for
|
||||
* @param principal
|
||||
* the authentication principal stored in the security context
|
||||
*
|
||||
* @return response of the servlet which in case of success is status code
|
||||
* {@link HttpStatus#OK} or in case of partial download
|
||||
* {@link HttpStatus#PARTIAL_CONTENT}.
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.GET, value = DdiDlRestConstants.ARTIFACT_DOWNLOAD_BY_FILENAME
|
||||
+ "/{fileName}")
|
||||
@ResponseBody
|
||||
ResponseEntity<InputStream> downloadArtifactByFilename(@PathVariable("tenant") final String tenant,
|
||||
@PathVariable("fileName") final String fileName);
|
||||
|
||||
/**
|
||||
* Handles GET MD5 checksum file download request.
|
||||
*
|
||||
* @param tenant
|
||||
* name of the client
|
||||
* @param fileName
|
||||
* to search for
|
||||
*
|
||||
* @return response of the servlet
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.GET, value = DdiDlRestConstants.ARTIFACT_DOWNLOAD_BY_FILENAME + "/{fileName}"
|
||||
+ DdiDlRestConstants.ARTIFACT_MD5_DWNL_SUFFIX)
|
||||
@ResponseBody
|
||||
ResponseEntity<Void> downloadArtifactMD5ByFilename(@PathVariable("tenant") final String tenant,
|
||||
@PathVariable("fileName") final String fileName);
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ddi.dl.rest.api;
|
||||
|
||||
/**
|
||||
* Constants for the direct device integration rest resources.
|
||||
*/
|
||||
public final class DdiDlRestConstants {
|
||||
|
||||
/**
|
||||
* The base URL mapping of the artifact repository rest resources.
|
||||
*/
|
||||
public static final String ARTIFACTS_V1_REQUEST_MAPPING = "/{tenant}/controller/artifacts/v1";
|
||||
|
||||
/**
|
||||
* The artifact URL mapping rest resource.
|
||||
*/
|
||||
public static final String ARTIFACT_DOWNLOAD = "artifact";
|
||||
|
||||
/**
|
||||
* The artifact by filename URL mapping rest resource.
|
||||
*/
|
||||
public static final String ARTIFACT_DOWNLOAD_BY_FILENAME = "/filename";
|
||||
|
||||
/**
|
||||
* File suffix for MDH hash download (see Linux md5sum).
|
||||
*/
|
||||
public static final String ARTIFACT_MD5_DWNL_SUFFIX = ".MD5SUM";
|
||||
|
||||
// constant class, private constructor.
|
||||
private DdiDlRestConstants() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -26,11 +26,6 @@
|
||||
<artifactId>hawkbit-ddi-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.hawkbit</groupId>
|
||||
<artifactId>hawkbit-ddi-dl-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.hawkbit</groupId>
|
||||
<artifactId>hawkbit-rest-core</artifactId>
|
||||
|
||||
@@ -18,7 +18,6 @@ import org.eclipse.hawkbit.api.ApiType;
|
||||
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
|
||||
import org.eclipse.hawkbit.api.URLPlaceholder;
|
||||
import org.eclipse.hawkbit.api.URLPlaceholder.SoftwareData;
|
||||
import org.eclipse.hawkbit.ddi.dl.rest.api.DdiDlRestConstants;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiArtifact;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiArtifactHash;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiChunk;
|
||||
@@ -160,7 +159,7 @@ public final class DataConversionHelper {
|
||||
final StringBuilder header = new StringBuilder();
|
||||
header.append("attachment;filename=");
|
||||
header.append(fileName);
|
||||
header.append(DdiDlRestConstants.ARTIFACT_MD5_DWNL_SUFFIX);
|
||||
header.append(DdiRestConstants.ARTIFACT_MD5_DWNL_SUFFIX);
|
||||
|
||||
response.setContentLength(content.length);
|
||||
response.setHeader("Content-Disposition", header.toString());
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ddi.rest.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||
import org.eclipse.hawkbit.ddi.dl.rest.api.DdiDlArtifactStoreControllerRestApi;
|
||||
import org.eclipse.hawkbit.im.authentication.UserPrincipal;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactBinaryNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.SoftwareModuleNotAssignedToTargetException;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder;
|
||||
import org.eclipse.hawkbit.rest.util.RestResourceConversionHelper;
|
||||
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.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* The {@link DdiArtifactStoreController} of the HawkBit server controller API
|
||||
* that is queried by the HawkBit target in order to download artifacts
|
||||
* independent of their own individual resource. This is offered in addition to
|
||||
* the {@link DdiRootController#downloadArtifact(String, Long, String)} for
|
||||
* legacy controllers that can not be fed with a download URI at runtime.
|
||||
*/
|
||||
@RestController
|
||||
@Scope(WebApplicationContext.SCOPE_REQUEST)
|
||||
public class DdiArtifactStoreController implements DdiDlArtifactStoreControllerRestApi {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DdiArtifactStoreController.class);
|
||||
|
||||
@Autowired
|
||||
private ArtifactManagement artifactManagement;
|
||||
|
||||
@Autowired
|
||||
private ControllerManagement controllerManagement;
|
||||
|
||||
@Autowired
|
||||
private RequestResponseContextHolder requestResponseContextHolder;
|
||||
|
||||
@Autowired
|
||||
private EntityFactory entityFactory;
|
||||
|
||||
@Override
|
||||
public ResponseEntity<InputStream> downloadArtifactByFilename(@PathVariable("tenant") final String tenant,
|
||||
@PathVariable("fileName") final String fileName) {
|
||||
final Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
final Optional<Artifact> foundArtifacts = artifactManagement.findArtifactByFilename(fileName);
|
||||
|
||||
if (!foundArtifacts.isPresent()) {
|
||||
LOG.warn("Software artifact with name {} could not be found.", fileName);
|
||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
ResponseEntity<InputStream> result;
|
||||
final Artifact artifact = foundArtifacts.get();
|
||||
|
||||
final String ifMatch = requestResponseContextHolder.getHttpServletRequest().getHeader("If-Match");
|
||||
if (ifMatch != null && !RestResourceConversionHelper.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) {
|
||||
result = new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED);
|
||||
} else {
|
||||
final DbArtifact file = artifactManagement.loadArtifactBinary(artifact.getSha1Hash())
|
||||
.orElseThrow(() -> new ArtifactBinaryNotFoundException(artifact.getSha1Hash()));
|
||||
|
||||
// we set a download status only if we are aware of the
|
||||
// targetid, i.e. authenticated and not anonymous
|
||||
if (principal instanceof UserPrincipal && ((UserPrincipal) principal).getUsername() != null
|
||||
&& !"anonymous".equals(((UserPrincipal) principal).getUsername())) {
|
||||
final ActionStatus actionStatus = checkAndReportDownloadByTarget(
|
||||
requestResponseContextHolder.getHttpServletRequest(), ((UserPrincipal) principal).getUsername(),
|
||||
artifact);
|
||||
result = RestResourceConversionHelper.writeFileResponse(artifact,
|
||||
requestResponseContextHolder.getHttpServletResponse(),
|
||||
requestResponseContextHolder.getHttpServletRequest(), file, controllerManagement,
|
||||
actionStatus.getId());
|
||||
} else {
|
||||
result = RestResourceConversionHelper.writeFileResponse(artifact,
|
||||
requestResponseContextHolder.getHttpServletResponse(),
|
||||
requestResponseContextHolder.getHttpServletRequest(), file);
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> downloadArtifactMD5ByFilename(@PathVariable("tenant") final String tenant,
|
||||
@PathVariable("fileName") final String fileName) {
|
||||
final Optional<Artifact> foundArtifacts = artifactManagement.findArtifactByFilename(fileName);
|
||||
|
||||
if (!foundArtifacts.isPresent()) {
|
||||
LOG.warn("Software artifact with name {} could not be found.", fileName);
|
||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
DataConversionHelper.writeMD5FileResponse(fileName, requestResponseContextHolder.getHttpServletResponse(),
|
||||
foundArtifacts.get());
|
||||
} catch (final IOException e) {
|
||||
LOG.error("Failed to stream MD5 File", e);
|
||||
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
private ActionStatus checkAndReportDownloadByTarget(final HttpServletRequest request, final String controllerId,
|
||||
final Artifact artifact) {
|
||||
final Target target = controllerManagement.findByControllerId(controllerId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||
|
||||
final Action action = controllerManagement
|
||||
.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(),
|
||||
artifact.getSoftwareModule().getId())
|
||||
.orElseThrow(() -> new SoftwareModuleNotAssignedToTargetException(artifact.getSoftwareModule().getId(),
|
||||
target.getControllerId()));
|
||||
final String range = request.getHeader("Range");
|
||||
|
||||
String message;
|
||||
if (range != null) {
|
||||
message = RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads range " + range + " of: "
|
||||
+ request.getRequestURI();
|
||||
} else {
|
||||
message = RepositoryConstants.SERVER_MESSAGE_PREFIX + "Target downloads: " + request.getRequestURI();
|
||||
}
|
||||
|
||||
return controllerManagement.addInformationalActionStatus(
|
||||
entityFactory.actionStatus().create(action.getId()).status(Status.DOWNLOAD).message(message));
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,6 @@ import java.util.TimeZone;
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
import org.eclipse.hawkbit.ddi.rest.resource.DdiArtifactDownloadTest.DownloadTestConfiguration;
|
||||
import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
@@ -42,9 +40,8 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
@@ -66,8 +63,8 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
|
||||
|
||||
private static final int ARTIFACT_SIZE = 5 * 1024 * 1024;
|
||||
|
||||
private volatile static int downLoadProgress = 0;
|
||||
private volatile static long shippedBytes = 0;
|
||||
private static volatile int downLoadProgress = 0;
|
||||
private static volatile long shippedBytes = 0;
|
||||
|
||||
private final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH);
|
||||
|
||||
@@ -93,149 +90,71 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
|
||||
ds.findFirstModuleByType(osType).get().getId(), "file1", false);
|
||||
|
||||
// no artifact available
|
||||
mvc.perform(get("/controller/v1/{targetid}/softwaremodules/{softwareModuleId}/artifacts/123455",
|
||||
mvc.perform(get("/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/123455",
|
||||
target.getControllerId(), getOsModule(ds))).andExpect(status().isNotFound());
|
||||
mvc.perform(get("/controller/v1/{targetid}/softwaremodules/{softwareModuleId}/artifacts/123455.MD5SUM",
|
||||
mvc.perform(get("/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/123455.MD5SUM",
|
||||
target.getControllerId(), getOsModule(ds))).andExpect(status().isNotFound());
|
||||
|
||||
// SM does not exist
|
||||
mvc.perform(get("/controller/v1/{targetid}/softwaremodules/1234567890/artifacts/{filename}",
|
||||
mvc.perform(get("/controller/v1/{controllerId}/softwaremodules/1234567890/artifacts/{filename}",
|
||||
target.getControllerId(), artifact.getFilename())).andExpect(status().isNotFound());
|
||||
mvc.perform(get("/controller/v1/{targetid}/softwaremodules/1234567890/artifacts/{filename}.MD5SUM",
|
||||
mvc.perform(get("/controller/v1/{controllerId}/softwaremodules/1234567890/artifacts/{filename}.MD5SUM",
|
||||
target.getControllerId(), artifact.getFilename())).andExpect(status().isNotFound());
|
||||
|
||||
// test now consistent data to test allowed methods
|
||||
mvc.perform(get("/{tenant}/controller/v1/{targetid}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
mvc.perform(get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())
|
||||
.header(HttpHeaders.IF_MATCH, artifact.getSha1Hash()))
|
||||
.andExpect(status().isOk());
|
||||
mvc.perform(get("/{tenant}/controller/v1/{targetid}/softwaremodules/{smId}/artifacts/{filename}.MD5SUM",
|
||||
mvc.perform(get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}.MD5SUM",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
// test failed If-match
|
||||
mvc.perform(get("/{tenant}/controller/v1/{targetid}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
mvc.perform(get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())
|
||||
.header("If-Match", "fsjkhgjfdhg"))
|
||||
.andExpect(status().isPreconditionFailed());
|
||||
|
||||
// test invalid range
|
||||
mvc.perform(get("/{tenant}/controller/v1/{targetid}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
mvc.perform(get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())
|
||||
.header("Range", "bytes=1-10,hdsfjksdh"))
|
||||
.andExpect(header().string("Content-Range", "bytes */" + 5 * 1024))
|
||||
.andExpect(status().isRequestedRangeNotSatisfiable());
|
||||
|
||||
mvc.perform(get("/{tenant}/controller/v1/{targetid}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
mvc.perform(get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename())
|
||||
.header("Range", "bytes=100-10"))
|
||||
.andExpect(header().string("Content-Range", "bytes */" + 5 * 1024))
|
||||
.andExpect(status().isRequestedRangeNotSatisfiable());
|
||||
|
||||
// not allowed methods
|
||||
mvc.perform(put("/{tenant}/controller/v1/{targetid}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
mvc.perform(put("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()))
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(delete("/{tenant}/controller/v1/{targetid}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
mvc.perform(delete("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()))
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(post("/{tenant}/controller/v1/{targetid}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
mvc.perform(post("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()))
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(put("/{tenant}/controller/v1/{targetid}/softwaremodules/{smId}/artifacts/{filename}.MD5SUM",
|
||||
mvc.perform(put("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}.MD5SUM",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()))
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(delete("/{tenant}/controller/v1/{targetid}/softwaremodules/{smId}/artifacts/{filename}.MD5SUM",
|
||||
mvc.perform(delete("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}.MD5SUM",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()))
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(post("/{tenant}/controller/v1/{targetid}/softwaremodules/{smId}/artifacts/{filename}.MD5SUM",
|
||||
mvc.perform(post("/{tenant}/controller/v1/{controllerId}/softwaremodules/{smId}/artifacts/{filename}.MD5SUM",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), artifact.getFilename()))
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TestdataFactory.DEFAULT_CONTROLLER_ID, authorities = "ROLE_CONTROLLER", allSpPermissions = true)
|
||||
@Description("Tests non allowed requests on the artifact ressource, e.g. invalid URI, wrong if-match, wrong command.")
|
||||
public void invalidRequestsOnArtifactResourceByName() throws Exception {
|
||||
// create target
|
||||
final Target target = testdataFactory.createTarget();
|
||||
final List<Target> targets = Lists.newArrayList(target);
|
||||
|
||||
// create ds
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
||||
assignDistributionSet(ds, targets);
|
||||
|
||||
// create artifact
|
||||
final byte random[] = RandomUtils.nextBytes(5 * 1024);
|
||||
|
||||
// Binary
|
||||
// no artifact available
|
||||
mvc.perform(get("/controller/artifacts/v1/filename/{filename}", "file1")).andExpect(status().isNotFound());
|
||||
|
||||
// no artifact available
|
||||
mvc.perform(get("/controller/artifacts/v1/filename/{filename}.MD5SUM", "file1"))
|
||||
.andExpect(status().isNotFound());
|
||||
|
||||
// test now consistent data to test allowed methods
|
||||
final Artifact artifact = artifactManagement.createArtifact(new ByteArrayInputStream(random), getOsModule(ds),
|
||||
"file1", false);
|
||||
|
||||
mvc.perform(
|
||||
get("/{tenant}/controller/artifacts/v1/filename/{filename}", tenantAware.getCurrentTenant(), "file1")
|
||||
.header(HttpHeaders.IF_MATCH, artifact.getSha1Hash()))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
mvc.perform(get("/{tenant}/controller/artifacts/v1/filename/{filename}.MD5SUM", tenantAware.getCurrentTenant(),
|
||||
"file1")).andExpect(status().isOk());
|
||||
|
||||
// test failed If-match
|
||||
mvc.perform(
|
||||
get("/{tenant}/controller/artifacts/v1/filename/{filename}", tenantAware.getCurrentTenant(), "file1")
|
||||
.header("If-Match", "fsjkhgjfdhg"))
|
||||
.andExpect(status().isPreconditionFailed());
|
||||
|
||||
// test invalid range
|
||||
mvc.perform(
|
||||
get("/{tenant}/controller/artifacts/v1/filename/{filename}", tenantAware.getCurrentTenant(), "file1")
|
||||
.header("Range", "bytes=1-10,hdsfjksdh"))
|
||||
.andExpect(header().string("Content-Range", "bytes */" + 5 * 1024))
|
||||
.andExpect(status().isRequestedRangeNotSatisfiable());
|
||||
|
||||
mvc.perform(
|
||||
get("/{tenant}/controller/artifacts/v1/filename/{filename}", tenantAware.getCurrentTenant(), "file1")
|
||||
.header("Range", "bytes=100-10"))
|
||||
.andExpect(header().string("Content-Range", "bytes */" + 5 * 1024))
|
||||
.andExpect(status().isRequestedRangeNotSatisfiable());
|
||||
|
||||
// not allowed methods
|
||||
mvc.perform(
|
||||
put("/{tenant}/controller/artifacts/v1/filename/{filename}", tenantAware.getCurrentTenant(), "file1"))
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(delete("/{tenant}/controller/artifacts/v1/filename/{filename}", tenantAware.getCurrentTenant(),
|
||||
"file1")).andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(
|
||||
post("/{tenant}/controller/artifacts/v1/filename/{filename}", tenantAware.getCurrentTenant(), "file1"))
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
// not allowed methods
|
||||
mvc.perform(put("/{tenant}/controller/artifacts/v1/filename/{filename}.MD5SUM", tenantAware.getCurrentTenant(),
|
||||
"file1")).andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(delete("/{tenant}/controller/artifacts/v1/filename/{filename}.MD5SUM",
|
||||
tenantAware.getCurrentTenant(), "file1")).andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(post("/{tenant}/controller/artifacts/v1/filename/{filename}.MD5SUM", tenantAware.getCurrentTenant(),
|
||||
"file1")).andExpect(status().isMethodNotAllowed());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "4712", authorities = "ROLE_CONTROLLER", allSpPermissions = true)
|
||||
@Description("Tests valid downloads through the artifact resource by identifying the artifact not by ID but file name.")
|
||||
@@ -257,14 +176,14 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
|
||||
ds.findFirstModuleByType(osType).get().getId(), "file1", false);
|
||||
|
||||
// download fails as artifact is not yet assigned
|
||||
mvc.perform(get("/controller/v1/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
|
||||
mvc.perform(get("/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
|
||||
target.getControllerId(), getOsModule(ds), artifact.getFilename())).andExpect(status().isNotFound());
|
||||
|
||||
// now assign and download successful
|
||||
assignDistributionSet(ds, targets);
|
||||
final MvcResult result = mvc
|
||||
.perform(
|
||||
get("/{tenant}/controller/v1/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
|
||||
get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds),
|
||||
artifact.getFilename()))
|
||||
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM))
|
||||
@@ -298,7 +217,7 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
|
||||
// download
|
||||
final MvcResult result = mvc
|
||||
.perform(
|
||||
get("/{tenant}/controller/v1/{targetid}/softwaremodules/{softwareModuleId}/artifacts/{filename}.MD5SUM",
|
||||
get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}.MD5SUM",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds),
|
||||
artifact.getFilename()))
|
||||
.andExpect(status().isOk()).andExpect(header().string("Content-Disposition",
|
||||
@@ -309,95 +228,10 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
|
||||
new String(artifact.getMd5Hash() + " " + artifact.getFilename()).getBytes(Charsets.US_ASCII));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(authorities = "ROLE_CONTROLLER_ANONYMOUS", allSpPermissions = true)
|
||||
@Description("Ensures that even an authenticated controller is not permitted to download if "
|
||||
+ "anonymous as authorization is notpossible, e.g. chekc if the controller has the artifact assigned.")
|
||||
public void downloadArtifactByNameFailsIfNotAuthenticated() throws Exception {
|
||||
downLoadProgress = 1;
|
||||
shippedBytes = 0;
|
||||
|
||||
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
|
||||
|
||||
// create target
|
||||
final Target target = testdataFactory.createTarget();
|
||||
final List<Target> targets = Lists.newArrayList(target);
|
||||
|
||||
// create ds
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
||||
|
||||
// create artifact
|
||||
final byte random[] = RandomUtils.nextBytes(ARTIFACT_SIZE);
|
||||
artifactManagement.createArtifact(new ByteArrayInputStream(random), getOsModule(ds), "file1.tar.bz2", false);
|
||||
|
||||
// download fails as artifact is not yet assigned to target
|
||||
assignDistributionSet(ds, targets);
|
||||
mvc.perform(get("/controller/artifacts/v1/filename/{filename}", "file1.tar.bz2"))
|
||||
.andExpect(status().isNotFound());
|
||||
|
||||
assertThat(downLoadProgress).isEqualTo(1);
|
||||
assertThat(shippedBytes).isEqualTo(0L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TestdataFactory.DEFAULT_CONTROLLER_ID, authorities = "ROLE_CONTROLLER", allSpPermissions = true)
|
||||
@Description("Ensures that an authenticated and named controller is permitted to download.")
|
||||
public void downloadArtifactByNameByNamedController() throws Exception {
|
||||
downLoadProgress = 1;
|
||||
shippedBytes = 0;
|
||||
|
||||
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
|
||||
|
||||
// create target
|
||||
final Target target = testdataFactory.createTarget();
|
||||
final List<Target> targets = Lists.newArrayList(target);
|
||||
|
||||
// create ds
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
||||
|
||||
// create artifact
|
||||
final byte random[] = RandomUtils.nextBytes(ARTIFACT_SIZE);
|
||||
final Artifact artifact = artifactManagement.createArtifact(new ByteArrayInputStream(random), getOsModule(ds),
|
||||
"file1", false);
|
||||
|
||||
// download fails as artifact is not yet assigned to target
|
||||
mvc.perform(get("/{tenant}/controller/artifacts/v1/filename/{filename}", tenantAware.getCurrentTenant(),
|
||||
"file1.tar.bz2")).andExpect(status().isNotFound());
|
||||
|
||||
// now assign and download successful
|
||||
assignDistributionSet(ds, targets);
|
||||
final MvcResult result = mvc
|
||||
.perform(get("/{tenant}/controller/artifacts/v1/filename/{filename}", tenantAware.getCurrentTenant(),
|
||||
"file1"))
|
||||
.andExpect(status().isOk()).andExpect(header().string("ETag", artifact.getSha1Hash()))
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM))
|
||||
.andExpect(header().string("Accept-Ranges", "bytes"))
|
||||
.andExpect(header().string("Last-Modified", dateFormat.format(new Date(artifact.getCreatedAt()))))
|
||||
.andExpect(header().string("Content-Disposition", "attachment;filename=file1")).andReturn();
|
||||
|
||||
assertTrue("The same file that was uploaded is expected when downloaded",
|
||||
Arrays.equals(result.getResponse().getContentAsByteArray(), random));
|
||||
|
||||
// one (update) action
|
||||
assertThat(deploymentManagement.countActionsByTarget(target.getControllerId())).isEqualTo(1);
|
||||
final Action action = deploymentManagement.findActionsByTarget(target.getControllerId(), pageReq).getContent()
|
||||
.get(0);
|
||||
|
||||
// one status - download
|
||||
assertThat(action.getActionStatus()).hasSize(2);
|
||||
assertThat(deploymentManagement
|
||||
.findActionStatusByAction(new PageRequest(0, 400, Direction.DESC, "id"), action.getId()).getContent()
|
||||
.get(0).getStatus()).isEqualTo(Status.DOWNLOAD);
|
||||
|
||||
// download complete
|
||||
assertThat(downLoadProgress).isEqualTo(10);
|
||||
assertThat(shippedBytes).isEqualTo(ARTIFACT_SIZE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TestdataFactory.DEFAULT_CONTROLLER_ID, authorities = "ROLE_CONTROLLER", allSpPermissions = true)
|
||||
@Description("Test various HTTP range requests for artifact download, e.g. chunk download or download resume.")
|
||||
public void rangeDownloadArtifactByName() throws Exception {
|
||||
public void rangeDownloadArtifact() throws Exception {
|
||||
// create target
|
||||
final Target target = testdataFactory.createTarget();
|
||||
final List<Target> targets = Lists.newArrayList(target);
|
||||
@@ -425,8 +259,10 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
|
||||
final String rangeString = "" + i * range + "-" + ((i + 1) * range - 1);
|
||||
|
||||
final MvcResult result = mvc
|
||||
.perform(get("/{tenant}/controller/artifacts/v1/filename/{filename}",
|
||||
tenantAware.getCurrentTenant(), "file1").header("Range", "bytes=" + rangeString))
|
||||
.perform(
|
||||
get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1")
|
||||
.header("Range", "bytes=" + rangeString))
|
||||
.andExpect(status().isPartialContent()).andExpect(header().string("ETag", artifact.getSha1Hash()))
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM))
|
||||
.andExpect(header().string("Accept-Ranges", "bytes"))
|
||||
@@ -442,8 +278,10 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
|
||||
|
||||
// return last 1000 Bytes
|
||||
MvcResult result = mvc
|
||||
.perform(get("/${tenant}/controller/artifacts/v1/filename/{filename}", tenantAware.getCurrentTenant(),
|
||||
"file1").header("Range", "bytes=-1000"))
|
||||
.perform(
|
||||
get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1")
|
||||
.header("Range", "bytes=-1000"))
|
||||
.andExpect(status().isPartialContent()).andExpect(header().string("ETag", artifact.getSha1Hash()))
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM))
|
||||
.andExpect(header().string("Accept-Ranges", "bytes"))
|
||||
@@ -458,8 +296,10 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
|
||||
|
||||
// skip first 1000 Bytes and return the rest
|
||||
result = mvc
|
||||
.perform(get("/{tenant}/controller/artifacts/v1/filename/{filename}", tenantAware.getCurrentTenant(),
|
||||
"file1").header("Range", "bytes=1000-"))
|
||||
.perform(
|
||||
get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1")
|
||||
.header("Range", "bytes=1000-"))
|
||||
.andExpect(status().isPartialContent()).andExpect(header().string("ETag", artifact.getSha1Hash()))
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM))
|
||||
.andExpect(header().string("Accept-Ranges", "bytes"))
|
||||
@@ -474,8 +314,10 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
|
||||
|
||||
// multipart download - first 20 bytes in 2 parts
|
||||
result = mvc
|
||||
.perform(get("/{tenant}/controller/artifacts/v1/filename/{filename}", tenantAware.getCurrentTenant(),
|
||||
"file1").header("Range", "bytes=0-9,10-19"))
|
||||
.perform(
|
||||
get("/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{filename}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId(), getOsModule(ds), "file1")
|
||||
.header("Range", "bytes=0-9,10-19"))
|
||||
.andExpect(status().isPartialContent()).andExpect(header().string("ETag", artifact.getSha1Hash()))
|
||||
.andExpect(content().contentType("multipart/byteranges; boundary=THIS_STRING_SEPARATES_MULTIPART"))
|
||||
.andExpect(header().string("Accept-Ranges", "bytes"))
|
||||
@@ -497,54 +339,7 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the download fails if te controller is not authenticated.")
|
||||
public void faildDownloadArtifactByNameIfAuthenticationMissing() throws Exception {
|
||||
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
|
||||
|
||||
// create target
|
||||
final Target target = testdataFactory.createTarget();
|
||||
final List<Target> targets = Lists.newArrayList(target);
|
||||
|
||||
// create ds
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
||||
|
||||
// create artifact
|
||||
final byte random[] = RandomUtils.nextBytes(5 * 1024);
|
||||
final Artifact artifact = artifactManagement.createArtifact(new ByteArrayInputStream(random), getOsModule(ds),
|
||||
"file1.tar.bz2", false);
|
||||
|
||||
// download fails as artifact is not yet assigned to target
|
||||
mvc.perform(get("/controller/artifacts/v1/filename/{filename}", "file1.tar.bz2"))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Downloads an MD5SUM file by the related artifacts filename.")
|
||||
public void downloadMd5sumFileByName() throws Exception {
|
||||
// create target
|
||||
final Target target = testdataFactory.createTarget();
|
||||
|
||||
// create ds
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
||||
|
||||
// create artifact
|
||||
final byte random[] = RandomUtils.nextBytes(5 * 1024);
|
||||
final Artifact artifact = artifactManagement.createArtifact(new ByteArrayInputStream(random), getOsModule(ds),
|
||||
"file1.tar.bz2", false);
|
||||
|
||||
// download
|
||||
final MvcResult result = mvc
|
||||
.perform(get("/{tenant}/controller/artifacts/v1/filename/file1.tar.bz2.MD5SUM",
|
||||
tenantAware.getCurrentTenant()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string("Content-Disposition", "attachment;filename=file1.tar.bz2.MD5SUM"))
|
||||
.andReturn();
|
||||
|
||||
assertThat(result.getResponse().getContentAsByteArray())
|
||||
.isEqualTo(new String(artifact.getMd5Hash() + " file1.tar.bz2").getBytes(Charsets.US_ASCII));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class DownloadTestConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -557,7 +352,7 @@ public class DdiArtifactDownloadTest extends AbstractDDiApiIntegrationTest {
|
||||
private static class Listener {
|
||||
|
||||
@EventListener(classes = DownloadProgressEvent.class)
|
||||
public void listen(final DownloadProgressEvent event) {
|
||||
public static void listen(final DownloadProgressEvent event) {
|
||||
downLoadProgress++;
|
||||
shippedBytes += event.getShippedBytesSinceLast();
|
||||
|
||||
|
||||
@@ -304,7 +304,9 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware {
|
||||
.addFilter(new DosFilter(100, 10, "127\\.0\\.0\\.1|\\[0:0:0:0:0:0:0:1\\]", "(^192\\.168\\.)",
|
||||
"X-Forwarded-For"))
|
||||
.addFilter(new ExcludePathAwareShallowETagFilter(
|
||||
"/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download", "/*/controller/artifacts/**"));
|
||||
"/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download",
|
||||
"/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/**",
|
||||
"/api/v1/downloadserver/**"));
|
||||
}
|
||||
|
||||
private static CIMySqlTestDatabase tesdatabase;
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.app;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.BasicErrorController;
|
||||
import org.springframework.boot.autoconfigure.web.ErrorAttributes;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
/**
|
||||
* Error page controller that ensures that ocet stream does not return text in
|
||||
* case of an error.
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
public class StreamAwareErrorController extends BasicErrorController {
|
||||
|
||||
/**
|
||||
* A new {@link StreamAwareErrorController}.
|
||||
*
|
||||
* @param errorAttributes
|
||||
* the error attributes
|
||||
* @param serverProperties
|
||||
* configuration properties
|
||||
*/
|
||||
public StreamAwareErrorController(final ErrorAttributes errorAttributes, final ServerProperties serverProperties) {
|
||||
super(errorAttributes, serverProperties.getError());
|
||||
}
|
||||
|
||||
@RequestMapping(produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
ResponseEntity<Void> errorStream(final HttpServletRequest request, final HttpServletResponse response) {
|
||||
final HttpStatus status = getStatus(request);
|
||||
return new ResponseEntity<>(status);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user