From 2275c857e930010c5555091e6169fad7352daa07 Mon Sep 17 00:00:00 2001 From: sdw086 Date: Mon, 9 Mar 2026 11:40:04 +0900 Subject: [PATCH] =?UTF-8?q?[=ED=8C=8C=EC=9D=BC=20=EC=97=85=EB=A1=9C?= =?UTF-8?q?=EB=93=9C]=20tusHook=20=EC=9E=91=EC=97=85=20-=20=EB=A6=AC?= =?UTF-8?q?=EC=A4=8C=20=ED=82=A4=EB=A1=9C=20=EB=8B=A4=EB=A5=B8=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=98=AC=EB=A6=B4=EB=95=8C=20=EB=A7=89=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/modules/file/FileController.java | 4 ++ .../modules/file/dto/UploadTokenDto.java | 7 ++ .../modules/file/service/FileService.java | 64 ++++++++++++++----- .../mapper/common/file/FileMapper.xml | 12 +++- 4 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/alist/api/common/modules/file/FileController.java b/src/main/java/com/alist/api/common/modules/file/FileController.java index 6975200..ef58b78 100644 --- a/src/main/java/com/alist/api/common/modules/file/FileController.java +++ b/src/main/java/com/alist/api/common/modules/file/FileController.java @@ -64,6 +64,8 @@ public class FileController { public ResponseEntity> uploadAuth( @RequestHeader(value = "Authorization", required = false) String uploadToken , @RequestHeader(value = "x-File-Uuid", required = false) String fileUuid + , @RequestHeader(value = "Upload-Metadata", required = false) String uploadMetadata + , @RequestHeader(value = "Upload-Length", required = false) String uploadLength ) { if (uploadToken == null || !uploadToken.startsWith("Bearer ")) { return ApiResponse.entity("", ApiResponseCode.CODE_401); @@ -75,6 +77,8 @@ public class FileController { UploadTokenDto uploadTokenDto = new UploadTokenDto(); uploadTokenDto.setUploadToken(uploadToken.substring(7).trim()); uploadTokenDto.setFileUuid(fileUuid.trim()); + uploadTokenDto.setUploadMetadataRaw(uploadMetadata); + uploadTokenDto.setUploadLengthRaw(uploadLength); UploadTokenDto uploadTokenCheck = fileService.isUploadTokenCheck(uploadTokenDto); diff --git a/src/main/java/com/alist/api/common/modules/file/dto/UploadTokenDto.java b/src/main/java/com/alist/api/common/modules/file/dto/UploadTokenDto.java index 8cca4c0..3151163 100644 --- a/src/main/java/com/alist/api/common/modules/file/dto/UploadTokenDto.java +++ b/src/main/java/com/alist/api/common/modules/file/dto/UploadTokenDto.java @@ -11,6 +11,13 @@ public class UploadTokenDto { private String fileUuid; private String uploadToken; + private String uploadMetadataRaw; + private String uploadLengthRaw; + + private String originName; + private Long sizeBytes; + private String contentType; + @JsonIgnore private int resultCode; } diff --git a/src/main/java/com/alist/api/common/modules/file/service/FileService.java b/src/main/java/com/alist/api/common/modules/file/service/FileService.java index 465dd22..6bceda9 100644 --- a/src/main/java/com/alist/api/common/modules/file/service/FileService.java +++ b/src/main/java/com/alist/api/common/modules/file/service/FileService.java @@ -88,7 +88,9 @@ public class FileService { return uploadTokenDto; } - String cacheKey = buildAuthCacheKey(uploadTokenDto.getFileUuid(), uploadTokenDto.getUploadToken()); + applyTusMeta(uploadTokenDto); + + String cacheKey = buildAuthCacheKey(uploadTokenDto); try { String cached = stringRedisTemplate.opsForValue().get(cacheKey); @@ -122,6 +124,34 @@ public class FileService { return uploadTokenDto; } + private void applyTusMeta(UploadTokenDto dto) { + String len = dto.getUploadLengthRaw(); + if (len != null && !len.isBlank()) { + try { dto.setSizeBytes(Long.parseLong(len.trim())); } catch (Exception ignored) {} + } + + String raw = dto.getUploadMetadataRaw(); + if (raw == null || raw.isBlank()) return; + + for (String part : raw.split(",")) { + String p = part.trim(); + int sp = p.indexOf(' '); + if (sp <= 0) continue; + + String key = p.substring(0, sp).trim(); + String val = p.substring(sp + 1).trim(); + String decoded; + try { + decoded = new String(java.util.Base64.getDecoder().decode(val), java.nio.charset.StandardCharsets.UTF_8); + } catch (Exception e) { + continue; + } + + if ("filename".equals(key)) dto.setOriginName(decoded); + else if ("filetype".equals(key)) dto.setContentType(decoded); + } + } + public UploadStatusDto getUploadStatus(UploadStatusDto uploadStatusDto) { String key = buildUploadStatusKey(uploadStatusDto.getFileUuid()); Map map = stringRedisTemplate.opsForHash().entries(key); @@ -341,8 +371,24 @@ public class FileService { } } - private String buildAuthCacheKey(String fileUuid, String uploadToken) { - return "upload:alist:auth:" + fileUuid + ":" + sha256(uploadToken); + private String buildAuthCacheKey(UploadTokenDto dto) { + String normalizedName = normalize(dto.getOriginName()); + String normalizedType = normalize(dto.getContentType()); + String normalizedSize = (dto.getSizeBytes() == null) ? "" : String.valueOf(dto.getSizeBytes()); + + String raw = String.join("|", + normalize(dto.getFileUuid()), + dto.getUploadToken() == null ? "" : dto.getUploadToken(), + normalizedName, + normalizedType, + normalizedSize + ); + + return "upload:alist:auth:" + sha256(raw); + } + + private String normalize(String v) { + return (v == null) ? "" : v.trim().toLowerCase(); } private String sha256(String value) { @@ -355,18 +401,6 @@ public class FileService { } } - private void evictUploadAuthCacheByFileUuid(String fileUuid) { - try { - String pattern = "upload:alist:auth:" + fileUuid + ":*"; - var keys = stringRedisTemplate.keys(pattern); - if (!keys.isEmpty()) { - stringRedisTemplate.delete(keys); - } - } catch (Exception e) { - log.warn("uploadAuth cache evict fail. fileUuid={}", fileUuid, e); - } - } - private long safeTtlSeconds() { // 설정 실수 방어: 0/음수면 기본값 20초 사용 return (uploadAuthCacheTtlSeconds > 0) ? uploadAuthCacheTtlSeconds : 20L; diff --git a/src/main/resources/mapper/common/file/FileMapper.xml b/src/main/resources/mapper/common/file/FileMapper.xml index 0dd293f..f780d33 100644 --- a/src/main/resources/mapper/common/file/FileMapper.xml +++ b/src/main/resources/mapper/common/file/FileMapper.xml @@ -130,12 +130,18 @@ /*FileMapper.selectFileDetailCountByFileUuidUserToKenIdx*/ SELECT COUNT(*) FROM ALISTLMS.FILE_DETAIL LFD - INNER JOIN ALISTLMS.test_user_token LTUT - ON LTUT.user_idx = LFD.CREATE_MEMBER + INNER JOIN ALISTLMS.test_user_token LTUT ON LTUT.user_idx = LFD.CREATE_MEMBER WHERE LFD.DEL_YN = 'N' AND LFD.FILE_UUID = #{fileUuid} - AND LFD.STATUS IN (0,1,2,3) AND LTUT.user_token_idx = #{userTokenIdx} + AND LFD.STATUS IN (0,1,2,3) + AND (#{sizeBytes} IS NULL OR LFD.SIZE_BYTES = #{sizeBytes}) + AND (#{originName} IS NULL OR #{originName} = '' OR LFD.ORIGIN_NAME = #{originName}) + AND ( + #{contentType} IS NULL OR #{contentType} = '' + OR LFD.CONTENT_TYPE IS NULL OR LFD.CONTENT_TYPE = '' + OR LOWER(LFD.CONTENT_TYPE) = LOWER(#{contentType}) + )