FileController.java

package dev.vernite.vernite.cdn;

import java.io.InputStream;
import java.sql.Blob;
import java.sql.SQLException;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import dev.vernite.vernite.utils.ObjectNotFoundException;
import lombok.AllArgsConstructor;

/**
 * Controller for file serving.
 */
@RestController
@AllArgsConstructor
@RequestMapping("/cdn")
public class FileController {

    private FileRepository fileRepository;

    /**
     * Returns file stored on the server.
     * 
     * @param req  request
     * @param hash hash of the file
     * @return file
     */
    @GetMapping("/{hash}")
    public ResponseEntity<StreamingResponseBody> getFile(NativeWebRequest req, @PathVariable String hash) {
        File f = fileRepository.findByHash(hash);
        if (f == null) {
            throw new ObjectNotFoundException();
        }
        if (req.checkNotModified(f.getHash(), f.getUploaded().getTime())) {
            return ResponseEntity.status(HttpStatus.NOT_MODIFIED).build();
        }
        try {
            Blob b = f.getFile();
            long len = b.length();
            InputStream is = b.getBinaryStream();
            return ResponseEntity.ok()
                    .contentLength(len)
                    .header("Cache-Control", "public, max-age=604800, immutable")
                    .contentType(MediaType.parseMediaType(f.getContentType()))
                    .body(out -> {
                        is.transferTo(out);
                    });
        } catch (SQLException e) {
            e.printStackTrace();
            throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "sql error");
        }
    }

}