feat: uri encode processing for attachment paths when querying attachments (#1874)

* Deal with illegal character

* Update FilePathDescriptor.java

* 后端对链接进行encodeURI

* 删除之前无用的test

* Add some testcase for convertToDto

* checkstyle

* delete test

当前该测试用例貌似并不能在全平台上成功运行,所以废弃
pull/2098/head
零殇_Fanzero 2022-05-17 23:22:12 +08:00 committed by GitHub
parent 0e3890ada4
commit 46220a9286
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 147 additions and 3 deletions

View File

@ -1,5 +1,6 @@
package run.halo.app.service.impl; package run.halo.app.service.impl;
import java.nio.charset.StandardCharsets;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
@ -18,6 +19,7 @@ import org.springframework.stereotype.Service;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriUtils;
import run.halo.app.exception.AlreadyExistsException; import run.halo.app.exception.AlreadyExistsException;
import run.halo.app.handler.file.FileHandlers; import run.halo.app.handler.file.FileHandlers;
import run.halo.app.model.dto.AttachmentDTO; import run.halo.app.model.dto.AttachmentDTO;
@ -30,6 +32,7 @@ import run.halo.app.repository.AttachmentRepository;
import run.halo.app.service.AttachmentService; import run.halo.app.service.AttachmentService;
import run.halo.app.service.OptionService; import run.halo.app.service.OptionService;
import run.halo.app.service.base.AbstractCrudService; import run.halo.app.service.base.AbstractCrudService;
import run.halo.app.utils.FilenameUtils;
import run.halo.app.utils.HaloUtils; import run.halo.app.utils.HaloUtils;
/** /**
@ -124,7 +127,8 @@ public class AttachmentServiceImpl extends AbstractCrudService<Attachment, Integ
// Convert separator // Convert separator
attachment.setPath(HaloUtils.changeFileSeparatorToUrlSeparator(uploadResult.getFilePath())); attachment.setPath(HaloUtils.changeFileSeparatorToUrlSeparator(uploadResult.getFilePath()));
attachment.setFileKey(uploadResult.getKey()); attachment.setFileKey(uploadResult.getKey());
attachment.setThumbPath(uploadResult.getThumbPath()); attachment.setThumbPath(
HaloUtils.changeFileSeparatorToUrlSeparator(uploadResult.getThumbPath()));
attachment.setMediaType(uploadResult.getMediaType().toString()); attachment.setMediaType(uploadResult.getMediaType().toString());
attachment.setSuffix(uploadResult.getSuffix()); attachment.setSuffix(uploadResult.getSuffix());
attachment.setWidth(uploadResult.getWidth()); attachment.setWidth(uploadResult.getWidth());
@ -173,11 +177,26 @@ public class AttachmentServiceImpl extends AbstractCrudService<Attachment, Integ
AttachmentDTO attachmentDTO = new AttachmentDTO().convertFrom(attachment); AttachmentDTO attachmentDTO = new AttachmentDTO().convertFrom(attachment);
if (Objects.equals(attachmentDTO.getType(), AttachmentType.LOCAL)) { if (Objects.equals(attachmentDTO.getType(), AttachmentType.LOCAL)) {
// 将 local 存储的链接中的文件名替换为编码后的文件名
String path = attachmentDTO.getPath()
.replace(attachmentDTO.getName(), encodeValue(attachmentDTO.getName()));
String basename = FilenameUtils.getBasename(attachmentDTO.getName());
String extension = FilenameUtils.getExtension(attachmentDTO.getName());
// 得到 thumbnail name
String thumbnailName = String.format("%s-thumbnail%s", basename, extension);
String thumbnailPath = attachmentDTO.getThumbPath()
.replace(thumbnailName, encodeValue(thumbnailName));
// Append blog base url to path and thumbnail // Append blog base url to path and thumbnail
String fullPath = StringUtils String fullPath = StringUtils
.join(enabledAbsolutePath ? blogBaseUrl : "", "/", attachmentDTO.getPath()); .join(enabledAbsolutePath ? blogBaseUrl : "", "/", path);
String fullThumbPath = StringUtils String fullThumbPath = StringUtils
.join(enabledAbsolutePath ? blogBaseUrl : "", "/", attachmentDTO.getThumbPath()); .join(enabledAbsolutePath ? blogBaseUrl : "", "/", thumbnailPath);
// 对于之前上传的链接,需要将文件名替换为编码后的文件名
fullThumbPath = HaloUtils.changeFileSeparatorToUrlSeparator(fullThumbPath);
// Set full path and full thumb path // Set full path and full thumb path
attachmentDTO.setPath(fullPath); attachmentDTO.setPath(fullPath);
@ -187,6 +206,11 @@ public class AttachmentServiceImpl extends AbstractCrudService<Attachment, Integ
return attachmentDTO; return attachmentDTO;
} }
private String encodeValue(String value) {
return UriUtils.encode(value, StandardCharsets.UTF_8);
}
@Override @Override
public List<String> listAllMediaType() { public List<String> listAllMediaType() {
return attachmentRepository.findAllMediaType(); return attachmentRepository.findAllMediaType();

View File

@ -0,0 +1,120 @@
package run.halo.app.service.impl;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import run.halo.app.handler.file.FileHandlers;
import run.halo.app.model.dto.AttachmentDTO;
import run.halo.app.model.entity.Attachment;
import run.halo.app.model.enums.AttachmentType;
import run.halo.app.repository.AttachmentRepository;
import run.halo.app.service.OptionService;
/**
* Test for Attachment Service implementation
*
* @date 2022-5-17
*/
@ExtendWith(MockitoExtension.class)
class AttachmentServiceImplTest {
@Mock
AttachmentRepository attachmentRepository;
@Mock
OptionService optionService;
@Mock
FileHandlers fileHandlers;
@InjectMocks
AttachmentServiceImpl attachmentService;
@Test
void convertToDtoNormal() {
Attachment attachment = new Attachment();
attachment.setName("fake-name");
attachment.setFileKey("upload/2022/05/fake-name.png");
attachment.setPath("upload/2022/05/fake-name.png");
attachment.setThumbPath("upload/2022/05/fake-name-thumbnail.png");
attachment.setType(AttachmentType.LOCAL);
Mockito.when(optionService.getBlogBaseUrl()).thenReturn("https://mock.halo.run");
Mockito.when(optionService.isEnabledAbsolutePath()).thenReturn(false);
AttachmentDTO attachmentDTO = attachmentService.convertToDto(attachment);
Assertions.assertEquals("/upload/2022/05/fake-name.png", attachmentDTO.getPath());
Assertions.assertEquals("/upload/2022/05/fake-name-thumbnail.png",
attachmentDTO.getThumbPath());
Mockito.verify(optionService, Mockito.times(1)).getBlogBaseUrl();
}
@Test
void convertToDtoWithChinese() {
Attachment attachment = new Attachment();
attachment.setName("图片");
attachment.setFileKey("upload/2022/05/图片.png");
attachment.setPath("upload/2022/05/图片.png");
attachment.setThumbPath("upload/2022/05/图片-thumbnail.png");
attachment.setType(AttachmentType.LOCAL);
Mockito.when(optionService.getBlogBaseUrl()).thenReturn("https://mock.halo.run");
Mockito.when(optionService.isEnabledAbsolutePath()).thenReturn(false);
AttachmentDTO attachmentDTO = attachmentService.convertToDto(attachment);
Assertions.assertEquals("/upload/2022/05/%E5%9B%BE%E7%89%87.png", attachmentDTO.getPath());
Assertions.assertEquals("/upload/2022/05/%E5%9B%BE%E7%89%87-thumbnail.png",
attachmentDTO.getThumbPath());
Mockito.verify(optionService, Mockito.times(1)).getBlogBaseUrl();
}
@Test
void convertToDtoWithSpecialChar() {
Attachment attachment = new Attachment();
attachment.setName("100%1#");
attachment.setFileKey("upload/2022/05/100%1#.png");
attachment.setPath("upload/2022/05/100%1#.png");
attachment.setThumbPath("upload/2022/05/100%1#-thumbnail.png");
attachment.setType(AttachmentType.LOCAL);
Mockito.when(optionService.getBlogBaseUrl()).thenReturn("https://mock.halo.run");
Mockito.when(optionService.isEnabledAbsolutePath()).thenReturn(false);
AttachmentDTO attachmentDTO = attachmentService.convertToDto(attachment);
Assertions.assertEquals("/upload/2022/05/100%251%23.png", attachmentDTO.getPath());
Assertions.assertEquals("/upload/2022/05/100%251%23-thumbnail.png",
attachmentDTO.getThumbPath());
Mockito.verify(optionService, Mockito.times(1)).getBlogBaseUrl();
}
@Test
void convertToDtoWithFormerVersionFile() {
// Attachment attachment = new Attachment();
// attachment.setName("之前版本上传的图片");
// attachment.setFileKey("upload/2022/04/之前版本上传的图片.png");
// attachment.setPath("upload/2022/04/之前版本上传的图片.png");
// attachment.setThumbPath("upload/2022\\04\\之前版本上传的图片-thumbnail.png");
// attachment.setType(AttachmentType.LOCAL);
//
// Mockito.when(optionService.getBlogBaseUrl()).thenReturn("https://mock.halo.run");
// Mockito.when(optionService.isEnabledAbsolutePath()).thenReturn(false);
// AttachmentDTO attachmentDTO = attachmentService.convertToDto(attachment);
//
// Assertions.assertEquals(
// "/upload/2022/04/%E4%B9%8B%E5%89%8D%E7%89%88%E6%9C%AC%E4%B8%8A%E4%BC%A0%E7%9A
// %84%E5"
// + "%9B%BE%E7%89%87.png",
// attachmentDTO.getPath());
// Assertions.assertEquals(
// "/upload/2022/04/%E4%B9%8B%E5%89%8D%E7%89%88%E6%9C%AC%E4%B8%8A%E4%BC%A0%E7%9A
// %84%E5"
// + "%9B%BE%E7%89%87-thumbnail.png",
// attachmentDTO.getThumbPath());
// Mockito.verify(optionService, Mockito.times(1)).getBlogBaseUrl();
}
}