Skip to content

Commit

Permalink
fix: Use encoded path for dev server (#12225)
Browse files Browse the repository at this point in the history
Allows project folders with spaces to work

Fixes #12221
  • Loading branch information
Artur- committed Nov 2, 2021
1 parent 8a1cad7 commit bde9fff
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 3 deletions.
Expand Up @@ -63,7 +63,8 @@ public static boolean isExternal(String url) {
public static String encodeURI(String path) {
try {
return URLEncoder.encode(path, StandardCharsets.UTF_8.name())
.replace("+", "%20").replace("%2F", "/");
.replace("+", "%20").replace("%2F", "/")
.replace("%40", "@");
} catch (UnsupportedEncodingException e) {
// Runtime exception as this doesn't really happen
throw new RuntimeException("Encoding the URI failed", e); // NOSONAR
Expand Down
Expand Up @@ -20,7 +20,7 @@

public class UrlUtilTest {

private String shouldNotBeEscaped = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/_-.*";
private String shouldNotBeEscaped = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/_-.*@";

@Test
public void isExternal_URLStartsWithTwoSlashes_returnsTrue() {
Expand Down
Expand Up @@ -42,6 +42,7 @@
import com.vaadin.flow.internal.BrowserLiveReload;
import com.vaadin.flow.internal.BrowserLiveReloadAccessor;
import com.vaadin.flow.internal.DevModeHandler;
import com.vaadin.flow.internal.UrlUtil;
import com.vaadin.flow.server.Constants;
import com.vaadin.flow.server.ExecutionFailedException;
import com.vaadin.flow.server.HandlerHelper;
Expand Down Expand Up @@ -685,7 +686,7 @@ public boolean serveDevModeRequest(HttpServletRequest request,
requestFilename = "/VAADIN/static" + requestFilename;
}

String devServerRequestPath = requestFilename;
String devServerRequestPath = UrlUtil.encodeURI(requestFilename);
if (request.getQueryString() != null) {
devServerRequestPath += "?" + request.getQueryString();
}
Expand Down
@@ -0,0 +1,102 @@
package com.vaadin.base.devserver;

import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.vaadin.base.devserver.startup.AbstractDevModeTest;
import com.vaadin.flow.internal.DevModeHandler;

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

public class AbstractDevServerRunnerTest extends AbstractDevModeTest {

private class DummyRunner extends AbstractDevServerRunner {

protected DummyRunner() {
super(lookup, 0, npmFolder,
CompletableFuture.completedFuture(null));
}

@Override
protected File getServerBinary() {
return new File("dummy.bin");
}

@Override
protected File getServerConfig() {
return new File("dummy.config");
}

@Override
protected String getServerName() {
return "Dummy server";
}

@Override
protected List<String> getServerStartupCommand(String nodeExec) {
List<String> commands = new ArrayList<>();
commands.add("echo");
return commands;
}

@Override
protected Pattern getServerSuccessPattern() {
return Pattern.compile("Dummy success");
}

@Override
protected Pattern getServerFailurePattern() {
return Pattern.compile("Dummy fail");
}

@Override
protected boolean checkConnection() {
return true;
}

@Override
public HttpURLConnection prepareConnection(String path, String method)
throws IOException {
return Mockito.mock(HttpURLConnection.class);
}

}

@Test
public void shouldPassEncodedUrlToDevServer() throws Exception {
handler = new DummyRunner();
DevModeHandler devServer = Mockito.spy(handler);

HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
Mockito.when(response.getOutputStream())
.thenReturn(Mockito.mock(ServletOutputStream.class));
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
Mockito.when(request.getRequestURI()).thenReturn("/foo%20bar");
Mockito.when(request.getPathInfo()).thenReturn("foo bar");
Mockito.when(request.getHeaderNames())
.thenReturn(Collections.emptyEnumeration());

AtomicReference<String> requestedPath = new AtomicReference<>();
Mockito.when(devServer.prepareConnection(Mockito.any(), Mockito.any()))
.then(invocation -> {
requestedPath.set((String) invocation.getArguments()[0]);
return Mockito.mock(HttpURLConnection.class);
});
devServer.serveDevModeRequest(request, response);
Assert.assertEquals("foo%20bar", requestedPath.get());

}
}

0 comments on commit bde9fff

Please sign in to comment.