Handle invalid characters in permalink URI construction (#7788)

#### What type of PR is this?

/kind bug
/area core
/milestone 2.22.x

#### What this PR does / why we need it:

This PR fixes invalid characters in permalink URI construction.

```java
java.lang.IllegalArgumentException: Invalid character ' ' for PATH in "/upload/2021/04/Web 14ecd358cce14f9f9ca0fa7a1716b5d8.pdf"
	at org.springframework.web.util.HierarchicalUriComponents.verifyUriComponent(HierarchicalUriComponents.java:422) ~[spring-web-6.2.11.jar:6.2.11]
	at org.springframework.web.util.HierarchicalUriComponents$FullPathComponent.verify(HierarchicalUriComponents.java:922) ~[spring-web-6.2.11.jar:6.2.11]
	at org.springframework.web.util.HierarchicalUriComponents.verify(HierarchicalUriComponents.java:386) ~[spring-web-6.2.11.jar:6.2.11]
	at org.springframework.web.util.HierarchicalUriComponents.<init>(HierarchicalUriComponents.java:146) ~[spring-web-6.2.11.jar:6.2.11]
	at org.springframework.web.util.UriComponentsBuilder.buildInternal(UriComponentsBuilder.java:346) ~[spring-web-6.2.11.jar:6.2.11]
	at org.springframework.web.util.UriComponentsBuilder.build(UriComponentsBuilder.java:334) ~[spring-web-6.2.11.jar:6.2.11]
	at run.halo.app.core.attachment.endpoint.LocalAttachmentUploadHandler.doGetPermalink(LocalAttachmentUploadHandler.java:296) ~[classes/:2.22.0-SNAPSHOT]
	at run.halo.app.core.attachment.endpoint.LocalAttachmentUploadHandler.getPermalink(LocalAttachmentUploadHandler.java:266) ~[classes/:2.22.0-SNAPSHOT]
	at run.halo.app.core.user.service.impl.DefaultAttachmentService.lambda$getPermalink$12(DefaultAttachmentService.java:128) ~[classes/:2.22.0-SNAPSHOT]
```

#### Does this PR introduce a user-facing change?

```release-note
修复可能无法正常获取附件链接的问题
```
pull/7794/head
John Niang 2025-10-02 13:06:25 +08:00 committed by GitHub
parent 80d407cc6d
commit 43f41c3fc2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 30 additions and 6 deletions

View File

@ -283,18 +283,27 @@ class LocalAttachmentUploadHandler implements AttachmentHandler {
return Mono.just(doGetThumbnailLinks(attachment));
}
private Optional<URI> doGetPermalink(Attachment attachment) {
protected Optional<URI> doGetPermalink(Attachment attachment) {
var annotations = attachment.getMetadata().getAnnotations();
if (annotations == null
|| !annotations.containsKey(Constant.URI_ANNO_KEY)) {
return Optional.empty();
}
var uriStr = annotations.get(Constant.URI_ANNO_KEY);
var uri = UriComponentsBuilder.fromUri(externalUrl.get())
// The URI has been encoded before, so there is no need to encode it again.
.path(uriStr)
.build(true)
.toUri();
URI uri;
try {
uri = UriComponentsBuilder.fromUri(externalUrl.get())
// The URI has been encoded before, so there is no need to encode it again.
.path(uriStr)
.build(true)
.toUri();
} catch (IllegalArgumentException e) {
// The URI may not be encoded, so we need to build with encoding.
uri = UriComponentsBuilder.fromUri(externalUrl.get())
.path(uriStr)
.build()
.toUri();
}
return Optional.of(uri);
}

View File

@ -17,6 +17,7 @@ import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
@ -32,9 +33,11 @@ import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
import run.halo.app.core.attachment.AttachmentRootGetter;
import run.halo.app.core.extension.attachment.Attachment;
import run.halo.app.core.extension.attachment.Constant;
import run.halo.app.core.extension.attachment.Policy;
import run.halo.app.core.extension.attachment.endpoint.UploadOption;
import run.halo.app.extension.ConfigMap;
import run.halo.app.extension.Metadata;
import run.halo.app.infra.ExternalUrlSupplier;
@ExtendWith(MockitoExtension.class)
@ -210,4 +213,16 @@ class LocalAttachmentUploadHandlerTest {
}
@Test
void shouldGetPermalinkWhenUriContainsIllegalChars() {
var attachment = new Attachment();
attachment.setMetadata(new Metadata());
attachment.getMetadata().setAnnotations(Map.of(
Constant.URI_ANNO_KEY, "/path/with space.png"
));
var permalink = uploadHandler.doGetPermalink(attachment);
assertTrue(permalink.isPresent());
assertEquals("/path/with%20space.png", permalink.get().toASCIIString());
}
}