Showing
1 changed file
with
40 additions
and
2 deletions
| @@ -14,6 +14,7 @@ import io.swagger.annotations.Api; | @@ -14,6 +14,7 @@ import io.swagger.annotations.Api; | ||
| 14 | import io.swagger.annotations.ApiImplicitParam; | 14 | import io.swagger.annotations.ApiImplicitParam; |
| 15 | import io.swagger.annotations.ApiOperation; | 15 | import io.swagger.annotations.ApiOperation; |
| 16 | import java.io.*; | 16 | import java.io.*; |
| 17 | +import java.net.URLDecoder; | ||
| 17 | import java.net.URLEncoder; | 18 | import java.net.URLEncoder; |
| 18 | import java.nio.charset.StandardCharsets; | 19 | import java.nio.charset.StandardCharsets; |
| 19 | import javax.validation.constraints.NotBlank; | 20 | import javax.validation.constraints.NotBlank; |
| @@ -60,6 +61,7 @@ public class SecurityDownloadController extends DefaultBaseController { | @@ -60,6 +61,7 @@ public class SecurityDownloadController extends DefaultBaseController { | ||
| 60 | 61 | ||
| 61 | String url = UploadUtil.generatePresignedUrl(record.getUploadType().getCode(), | 62 | String url = UploadUtil.generatePresignedUrl(record.getUploadType().getCode(), |
| 62 | record.getFilePath()); | 63 | record.getFilePath()); |
| 64 | + log.info("fileName===" + fileName); | ||
| 63 | if (StringUtils.isNotBlank(fileName)) { | 65 | if (StringUtils.isNotBlank(fileName)) { |
| 64 | try { | 66 | try { |
| 65 | url = url + "&fileName=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()) | 67 | url = url + "&fileName=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()) |
| @@ -68,6 +70,7 @@ public class SecurityDownloadController extends DefaultBaseController { | @@ -68,6 +70,7 @@ public class SecurityDownloadController extends DefaultBaseController { | ||
| 68 | e.printStackTrace(); | 70 | e.printStackTrace(); |
| 69 | } | 71 | } |
| 70 | } | 72 | } |
| 73 | + log.info("url===" + url); | ||
| 71 | 74 | ||
| 72 | return InvokeResultBuilder.success(url); | 75 | return InvokeResultBuilder.success(url); |
| 73 | } | 76 | } |
| @@ -89,13 +92,16 @@ public class SecurityDownloadController extends DefaultBaseController { | @@ -89,13 +92,16 @@ public class SecurityDownloadController extends DefaultBaseController { | ||
| 89 | throw new AccessDeniedException(); | 92 | throw new AccessDeniedException(); |
| 90 | } | 93 | } |
| 91 | 94 | ||
| 92 | - String downloadFileName = StringUtils.isBlank(fileName) ? file.getName() : fileName; | 95 | + log.info("fileName===" + fileName); |
| 96 | + String normalizedFileName = normalizeFileName(fileName); | ||
| 97 | + log.info("normalizedFileName===" + normalizedFileName); | ||
| 98 | + String downloadFileName = StringUtils.isBlank(normalizedFileName) ? file.getName() : normalizedFileName; | ||
| 93 | String encodedFileName = URLEncoder.encode(downloadFileName, StandardCharsets.UTF_8.name()) | 99 | String encodedFileName = URLEncoder.encode(downloadFileName, StandardCharsets.UTF_8.name()) |
| 94 | .replace("+", "%20"); | 100 | .replace("+", "%20"); |
| 95 | 101 | ||
| 96 | response.setContentType("application/octet-stream"); | 102 | response.setContentType("application/octet-stream"); |
| 97 | response.setCharacterEncoding(StandardCharsets.UTF_8.name()); | 103 | response.setCharacterEncoding(StandardCharsets.UTF_8.name()); |
| 98 | - response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName); | 104 | + response.setHeader("Content-Disposition", buildContentDisposition(downloadFileName, encodedFileName)); |
| 99 | response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); | 105 | response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); |
| 100 | 106 | ||
| 101 | try (InputStream in = new FileInputStream(file)) { | 107 | try (InputStream in = new FileInputStream(file)) { |
| @@ -107,4 +113,36 @@ public class SecurityDownloadController extends DefaultBaseController { | @@ -107,4 +113,36 @@ public class SecurityDownloadController extends DefaultBaseController { | ||
| 107 | response.getOutputStream().flush(); | 113 | response.getOutputStream().flush(); |
| 108 | } | 114 | } |
| 109 | } | 115 | } |
| 116 | + | ||
| 117 | + private String buildContentDisposition(String fileName, String encodedFileName) { | ||
| 118 | + String fallbackFileName = fileName | ||
| 119 | + .replace("\\", "_") | ||
| 120 | + .replace("\"", "_"); | ||
| 121 | + return "attachment; filename=\"" + fallbackFileName + "\"; filename*=UTF-8''" | ||
| 122 | + + encodedFileName; | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + private String normalizeFileName(String fileName) { | ||
| 126 | + if (StringUtils.isBlank(fileName)) { | ||
| 127 | + return fileName; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + String normalized = fileName; | ||
| 131 | + for (int i = 0; i < 2; i++) { | ||
| 132 | + if (!normalized.matches(".*%[0-9a-fA-F]{2}.*")) { | ||
| 133 | + break; | ||
| 134 | + } | ||
| 135 | + try { | ||
| 136 | + String decoded = URLDecoder.decode(normalized, StandardCharsets.UTF_8.name()); | ||
| 137 | + if (StringUtils.equals(decoded, normalized)) { | ||
| 138 | + break; | ||
| 139 | + } | ||
| 140 | + normalized = decoded; | ||
| 141 | + } catch (Exception e) { | ||
| 142 | + break; | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + return normalized; | ||
| 147 | + } | ||
| 110 | } | 148 | } |