diff --git a/temporal-sdk/src/main/java/io/temporal/internal/common/LinkConverter.java b/temporal-sdk/src/main/java/io/temporal/internal/common/LinkConverter.java index d1ee56f0d..6d270eec6 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/common/LinkConverter.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/common/LinkConverter.java @@ -32,11 +32,19 @@ public class LinkConverter { public static io.temporal.api.nexus.v1.Link workflowEventToNexusLink(Link.WorkflowEvent we) { try { + String url = String.format( linkPathFormat, URLEncoder.encode(we.getNamespace(), StandardCharsets.UTF_8.toString()), - URLEncoder.encode(we.getWorkflowId(), StandardCharsets.UTF_8.toString()), + // The 'replace' below handles spaces - the encoder will convert them to a plus, + // which the UI then handles as a plus, thus breaking the link as the + // space is lost. + // It's a known quirk with the URLEncoder as it encodes for forms, not general URIs. + // Only done for the WorkflowId as the other two are values we control, + // and will never have spaces. + URLEncoder.encode(we.getWorkflowId(), StandardCharsets.UTF_8.toString()) + .replace("+", "%20"), URLEncoder.encode(we.getRunId(), StandardCharsets.UTF_8.toString())); List> queryParams = new ArrayList<>(); diff --git a/temporal-sdk/src/test/java/io/temporal/internal/common/LinkConverterTest.java b/temporal-sdk/src/test/java/io/temporal/internal/common/LinkConverterTest.java index b9bc4a6e3..60b67b1b8 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/common/LinkConverterTest.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/common/LinkConverterTest.java @@ -6,6 +6,9 @@ import io.temporal.api.common.v1.Link; import io.temporal.api.enums.v1.EventType; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import org.junit.Test; public class LinkConverterTest { @@ -98,6 +101,35 @@ public void testConvertWorkflowEventToNexus_ValidSlash() { assertEquals(expected, actual); } + @Test + public void testConvertWorkflowEventToNexus_ValidSpace() throws UnsupportedEncodingException { + Link.WorkflowEvent input = + Link.WorkflowEvent.newBuilder() + .setNamespace("ns") + .setWorkflowId("wf space+plus") + .setRunId("run-id") + .setEventRef( + Link.WorkflowEvent.EventReference.newBuilder() + .setEventId(1) + .setEventType(EventType.EVENT_TYPE_WORKFLOW_EXECUTION_STARTED)) + .build(); + + io.temporal.api.nexus.v1.Link expected = + io.temporal.api.nexus.v1.Link.newBuilder() + .setUrl( + "temporal:///namespaces/ns/workflows/wf%20space%2Bplus/run-id/history?referenceType=EventReference&eventID=1&eventType=WorkflowExecutionStarted") + .setType("temporal.api.common.v1.Link.WorkflowEvent") + .build(); + + io.temporal.api.nexus.v1.Link actual = workflowEventToNexusLink(input); + assertEquals(expected, actual); + + String decoded = URLDecoder.decode(actual.getUrl(), StandardCharsets.UTF_8.toString()); + assertEquals( + "temporal:///namespaces/ns/workflows/wf space+plus/run-id/history?referenceType=EventReference&eventID=1&eventType=WorkflowExecutionStarted", + decoded); + } + @Test public void testConvertWorkflowEventToNexus_ValidEventIDMissing() { Link.WorkflowEvent input =