package de.is24.infrastructure.gridfs.http.web.controller; import de.is24.infrastructure.gridfs.http.domain.RepoEntry; import de.is24.infrastructure.gridfs.http.gridfs.StorageService; import de.is24.infrastructure.gridfs.http.repos.RepoService; import de.is24.util.monitoring.spring.TimeMeasurement; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import static de.is24.infrastructure.gridfs.http.domain.RepoType.VIRTUAL; import static org.springframework.http.HttpStatus.CREATED; import static org.springframework.http.HttpStatus.NO_CONTENT; import static org.springframework.web.bind.annotation.RequestMethod.DELETE; import static org.springframework.web.bind.annotation.RequestMethod.GET; import static org.springframework.web.bind.annotation.RequestMethod.POST; @Controller @RequestMapping("/repo/virtual") @TimeMeasurement public class VirtualRepositoryController { private final RepoService repoService; private final FileController fileController; public VirtualRepositoryController() { this.repoService = null; this.fileController = null; } @Autowired public VirtualRepositoryController(RepoService repoService, FileController fileController) { this.repoService = repoService; this.fileController = fileController; } @RequestMapping(method = POST) @ResponseStatus(CREATED) public void createVirtualRepo(@RequestParam("name") String reponame, @RequestParam("destination") String destination) throws IOException { repoService.createVirtualRepo(reponame, destination); } @RequestMapping(value = "/{reponame}", method = DELETE) @ResponseStatus(NO_CONTENT) public void deleteVirtualRepo(@PathVariable("reponame") String reponame) { repoService.deleteVirtual(reponame); } @RequestMapping(value = "/{repo}/{arch}/{filename:.+}", method = GET) public ResponseEntity<InputStreamResource> deliverFile(@PathVariable("repo") String repo, @PathVariable("arch") String arch, @PathVariable("filename") String filename) throws IOException { return deliverFileInternal(repo, arch, filename, null); } @RequestMapping(value = "/{repo}/{arch}/{filename:.+}", method = GET, headers = { "Range" }) public ResponseEntity<InputStreamResource> deliverRangeOfFile(@PathVariable("repo") String repo, @PathVariable("arch") String arch, @PathVariable("filename") String filename, @RequestHeader("Range") String rangeHeader) throws IOException { return deliverFileInternal(repo, arch, filename, rangeHeader); } private ResponseEntity<InputStreamResource> deliverFileInternal(String repo, String arch, String filename, String rangeHeader) throws IOException { RepoEntry entry = repoService.getRepo(repo, VIRTUAL); if (entry.isExternal()) { return createRedirect(getExternalUri(entry.getTarget(), arch, filename)); } if (rangeHeader != null) { return fileController.deliverRangeOfFile(entry.getTarget(), arch, filename, rangeHeader); } return fileController.deliverFile(entry.getTarget(), arch, filename); } private ResponseEntity<InputStreamResource> createRedirect(URI uri) { HttpHeaders headers = new HttpHeaders(); headers.setLocation(uri); return new ResponseEntity<>(headers, HttpStatus.valueOf(302)); } private URI getExternalUri(String target, String arch, String filename) { String url = target.endsWith("/") ? target : (target + "/"); url += arch + "/" + filename; URI location; try { location = new URI(url); } catch (URISyntaxException e) { throw new IllegalArgumentException("Could not build external target url."); } return location; } }