Skip to content
GetFileController.java 4.03 KiB
Newer Older
Sonia Zorba's avatar
Sonia Zorba committed
/*
 * This file is part of vospace-file-service
 * Copyright (C) 2021 Istituto Nazionale di Astrofisica
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
Sonia Zorba's avatar
Sonia Zorba committed
package it.inaf.ia2.transfer.controller;

import it.inaf.ia2.transfer.auth.GmsClient;
import it.inaf.ia2.transfer.auth.TokenPrincipal;
import it.inaf.ia2.transfer.persistence.FileDAO;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
Sonia Zorba's avatar
Sonia Zorba committed
import java.util.Optional;
import javax.servlet.http.HttpServletResponse;
Sonia Zorba's avatar
Sonia Zorba committed
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Sonia Zorba's avatar
Sonia Zorba committed
import org.springframework.beans.factory.annotation.Autowired;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.UNAUTHORIZED;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GetFileController extends FileController {
Sonia Zorba's avatar
Sonia Zorba committed

Sonia Zorba's avatar
Sonia Zorba committed
    private static final Logger LOG = LoggerFactory.getLogger(GetFileController.class);

Sonia Zorba's avatar
Sonia Zorba committed
    @Autowired
    private FileDAO fileDAO;

    @Autowired
    private GmsClient gmsClient;

    @Autowired
    private HttpServletResponse response;

    @GetMapping("/**")
    public ResponseEntity<?> getFile() {

        String path = getPath();
        
        LOG.debug("getFile called for path {}", path);
        
Sonia Zorba's avatar
Sonia Zorba committed
        Optional<FileInfo> optFileInfo = fileDAO.getFileInfo(path);

        if (optFileInfo.isPresent()) {

            FileInfo fileInfo = optFileInfo.get();

            if (!fileInfo.isIsPublic() && !privateButDownloadable(fileInfo)) {
                return new ResponseEntity<>("Unauthorized", UNAUTHORIZED);
            }

            return getFileResponse(fileInfo);
        } else {
            return new ResponseEntity<>("File " + path + " not found", NOT_FOUND);
        }
    }

    private boolean privateButDownloadable(FileInfo fileInfo) {

        TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal();

        String token = principal.getToken();
Sonia Zorba's avatar
Sonia Zorba committed
        if (token == null) {
            return false;
        }

        if (principal.getName().equals(fileInfo.getOwnerId())) {
            return true;
        }

Sonia Zorba's avatar
Sonia Zorba committed
        // TODO: configure cache
        if (fileInfo.getGroupRead() == null) {
            return false;
        }
        for (String group : fileInfo.getGroupRead()) {
            if (gmsClient.isMemberOf(token, group)) {
                return true;
            }
        }
        return false;
    }

    private ResponseEntity<?> getFileResponse(FileInfo fileInfo) {

        File file = new File(fileInfo.getOsPath());
Sonia Zorba's avatar
Sonia Zorba committed

        if (!file.exists()) {
Sonia Zorba's avatar
Sonia Zorba committed
            LOG.error("File not found: " + file.getAbsolutePath());
Sonia Zorba's avatar
Sonia Zorba committed
            return new ResponseEntity<>("File " + file.getName() + " not found", NOT_FOUND);
        }

        if (!file.canRead()) {
Sonia Zorba's avatar
Sonia Zorba committed
            LOG.error("File not readable: " + file.getAbsolutePath());
Sonia Zorba's avatar
Sonia Zorba committed
            return new ResponseEntity<>("File " + file.getName() + " is not readable", INTERNAL_SERVER_ERROR);
        }

        String vosName = fileInfo.getVirtualPath().substring(fileInfo.getVirtualPath().lastIndexOf("/") + 1);
        
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(vosName, StandardCharsets.UTF_8));
Sonia Zorba's avatar
Sonia Zorba committed
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setCharacterEncoding("UTF-8");
Sonia Zorba's avatar
Sonia Zorba committed

        byte[] bytes = new byte[1024];
        try (OutputStream out = response.getOutputStream();
                InputStream is = new FileInputStream(file)) {
Sonia Zorba's avatar
Sonia Zorba committed
            int read;
            while ((read = is.read(bytes)) != -1) {
                out.write(bytes, 0, read);
            }
        } catch (IOException ex) {
            throw new UncheckedIOException(ex);
        }
        return null;
    }
}