com.xlrit.gears.server.rest.ContentController Maven / Gradle / Ivy
package com.xlrit.gears.server.rest;
import com.google.common.base.Strings;
import com.xlrit.gears.base.content.Content;
import com.xlrit.gears.base.content.ContentStore;
import com.xlrit.gears.base.exception.NotFoundException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.util.UrlPathHelper;
@Controller
@RequiredArgsConstructor
public class ContentController {
private static final Logger LOG = LoggerFactory.getLogger(ContentController.class);
private static final String CONTENT_PREFIX = "/content/";
private static final String CONTENT_PATH = CONTENT_PREFIX + "**";
private final ContentStore contentStore;
private final UrlPathHelper urlPathHelper;
@GetMapping(CONTENT_PATH)
@ResponseBody
@Transactional
@PreAuthorize("isAuthenticated()")
public ResponseEntity getContent(HttpServletRequest request, @RequestParam(required = false, defaultValue = "false") boolean open) {
String decodedRequestUri = urlPathHelper.getRequestUri(request);
LOG.debug("getContent: decodedRequestUri={}, open={}", decodedRequestUri, open);
String path = extractContentPath(decodedRequestUri);
return getContentResponse(path, open);
}
private ResponseEntity getContentResponse(String path, boolean open) {
LOG.debug("getContentResponse: path={}", path);
if (Strings.isNullOrEmpty(path)) throw new IllegalArgumentException("Parameter 'path' is required");
Content content = contentStore.findContent(path);
if (content == null) {
LOG.error("getContentResponse: content with path '{}' not found", path);
throw new NotFoundException("content", "path", path);
}
String filename = content.getFilename();
String disposition = (open ? "inline" : "attachment") + "; filename=\"" + filename + "\"";
String contentType = refineContentType(content.getContentType(), filename);
LOG.info("getContentResponse: returning content with path '{}', filename '{}', contentType '{}'", path, filename, contentType);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, contentType)
.header(HttpHeaders.CONTENT_DISPOSITION, disposition)
.body(content.getData());
}
private static String refineContentType(String contentType, String filename) {
if (!Strings.isNullOrEmpty(contentType) && !"application/octet-stream".equals(contentType) || filename == null)
return contentType;
if (filename.endsWith(".msg"))
return "application/vnd.ms-outlook";
return contentType;
}
static String extractContentPath(String requestUri) {
int index = requestUri.indexOf(CONTENT_PREFIX);
if (index == -1) throw new IllegalArgumentException("Invalid content URI: " + requestUri);
return requestUri.substring(index + CONTENT_PREFIX.length());
}
/*
// This approach doesn't work, because `path` cannot contain slashes, even if encoded as %2F.
// See https://stackoverflow.com/questions/13482020/encoded-slash-2f-with-spring-requestmapping-path-param-gives-http-400
@GetMapping("/content/{path}")
@ResponseBody
@Transactional
@PreAuthorize("isAuthenticated()")
public ResponseEntity getContent(@PathVariable String path, @RequestParam(required = false, defaultValue = "false") boolean open) {
LOG.info("getContent: path={}, open={}", path, open);
return getContentResponse(path, open);
}
*/
}