Skip to content

Commit

Permalink
Initial commit for issue: #40 Handling of double slashes
Browse files Browse the repository at this point in the history
  • Loading branch information
mcweba committed Jun 26, 2017
1 parent f000d1c commit ee08c2c
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 12 deletions.
27 changes: 17 additions & 10 deletions src/main/java/org/swisspush/reststorage/RestStorageHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private void getResourceNotFound(RoutingContext ctx) {
}

private void getResource(RoutingContext ctx) {
final String path = cleanPath(ctx.request().path().substring(prefixFixed.length()));
final String path = cleanPath(ctx);
final String etag = ctx.request().headers().get(IF_NONE_MATCH_HEADER.getName());
if (log.isTraceEnabled()) {
log.trace("RestStorageHandler got GET Request path: " + path + " etag: " + etag);
Expand Down Expand Up @@ -299,7 +299,7 @@ private List<String> sortedNames(CollectionResource collection) {

private void putResource(RoutingContext ctx) {
ctx.request().pause();
final String path = cleanPath(ctx.request().path().substring(prefixFixed.length()));
final String path = cleanPath(ctx);

MultiMap headers = ctx.request().headers();

Expand Down Expand Up @@ -460,7 +460,7 @@ private void putResource(RoutingContext ctx) {
}

private void deleteResource(RoutingContext ctx) {
final String path = cleanPath(ctx.request().path().substring(prefixFixed.length()));
final String path = cleanPath(ctx);
if (log.isTraceEnabled()) {
log.trace("RestStorageHandler delete resource: " + ctx.request().uri());
}
Expand Down Expand Up @@ -550,7 +550,7 @@ public void handle(Buffer event) {
return;
}

final String path = cleanPath(ctx.request().path().substring(prefixFixed.length()));
final String path = cleanPath(ctx);
final String etag = ctx.request().headers().get(IF_NONE_MATCH_HEADER.getName());
storage.storageExpand(path, etag, subResourceNames, resource -> {

Expand Down Expand Up @@ -624,15 +624,22 @@ public void handle(Buffer event) {
// End Router handling //
////////////////////////////

private String cleanPath(String value) {
value = value.replaceAll("\\.\\.", "").replaceAll("\\/\\/", "/");
while (value.endsWith("/")) {
value = value.substring(0, value.length() - 1);
private String cleanPath(RoutingContext ctx) {
String path = ctx.request().path().substring(prefixFixed.length());
path = path.replaceAll("\\.\\.", "");

boolean keepDoubleSlashes = Boolean.parseBoolean(ctx.request().headers().get(KEEP_DOUBLE_SLASHES_HEADER.getName()));
if(!keepDoubleSlashes){
path = path.replaceAll("\\/\\/", "/");
}

while (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
if (value.isEmpty()) {
if (path.isEmpty()) {
return "/";
}
return value;
return path;
}

public static class OffsetLimit {
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/org/swisspush/reststorage/RestStorageRunner.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.swisspush.reststorage;

import io.vertx.core.DeploymentOptions;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.LoggerFactory;
import org.swisspush.reststorage.util.ModuleConfiguration;

/**
* Created by florian kammermann on 23.05.2016.
Expand All @@ -12,8 +15,16 @@
public class RestStorageRunner {

public static void main(String[] args) {
Vertx.vertx().deployVerticle("org.swisspush.reststorage.RestStorageMod", event -> {

JsonObject mainStorageConfig = ModuleConfiguration.with()
.storageType(ModuleConfiguration.StorageType.redis)
.build()
.asJsonObject();

DeploymentOptions storageOptions = new DeploymentOptions().setConfig(mainStorageConfig).setInstances(4);

Vertx.vertx().deployVerticle("org.swisspush.reststorage.RestStorageMod", storageOptions, event -> {
LoggerFactory.getLogger(RestStorageMod.class).info("rest-storage started");
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public enum HttpRequestHeader {
EXPIRE_AFTER_HEADER("x-expire-after"),
IMPORTANCE_LEVEL_HEADER("x-importance-level"),
COMPRESS_HEADER("x-stored-compressed"),
KEEP_DOUBLE_SLASHES_HEADER("x-keep-double-slashes"),
CONTENT_TYPE("Content-Type"),
CONTENT_LENGTH("Content-Length");

Expand Down
128 changes: 128 additions & 0 deletions src/test/java/org/swisspush/reststorage/RestStorageHandlerTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.swisspush.reststorage;

import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.CaseInsensitiveHeaders;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerRequest;
Expand All @@ -13,6 +15,8 @@
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.swisspush.reststorage.util.HttpRequestHeader;
import org.swisspush.reststorage.util.HttpRequestParam;
import org.swisspush.reststorage.util.LockMode;
import org.swisspush.reststorage.util.StatusCode;

import java.util.Optional;
Expand Down Expand Up @@ -142,4 +146,128 @@ public void testRejectPUTRequestWhenMemoryUsageHigherThanImportanceLevel(TestCon
verify(log, times(1)).info(
eq("Rejecting PUT request to /some/resource because current memory usage of 75% is higher than provided importance level of 50%"));
}

@Test
public void testGETRequestsDoubleSlashesHandlingNoHeader(TestContext testContext) {
restStorageHandler = new RestStorageHandler(vertx, log, storage, "/", null,
false, false);

/*
* - no 'x-keep-double-slashes' header
* - path contains double slashes
* -> expectation: storage called with path containing single slashes only
*/
when(request.method()).thenReturn(HttpMethod.GET);
when(request.headers()).thenReturn(new CaseInsensitiveHeaders());
when(request.uri()).thenReturn("/some//collection/resource");
when(request.path()).thenReturn("/some//collection/resource");
restStorageHandler.handle(request);
verify(storage, times(1)).get(eq("/some/collection/resource"), anyString(), anyInt(), anyInt(), any(Handler.class));
}

@Test
public void testGETRequestsDoubleSlashesHandlingWithHeader(TestContext testContext) {
restStorageHandler = new RestStorageHandler(vertx, log, storage, "/", null,
false, false);

/*
* - 'x-keep-double-slashes' header
* - path contains double slashes
* -> expectation: storage called with path containing double slashes
*/
when(request.method()).thenReturn(HttpMethod.GET);
when(request.headers()).thenReturn(new CaseInsensitiveHeaders().add(HttpRequestHeader.KEEP_DOUBLE_SLASHES_HEADER.getName(), "true"));
when(request.uri()).thenReturn("/some//collection/resource");
when(request.path()).thenReturn("/some//collection/resource");
restStorageHandler.handle(request);
verify(storage, times(1)).get(eq("/some//collection/resource"), anyString(), anyInt(), anyInt(), any(Handler.class));
}

@Test
public void testPUTRequestsDoubleSlashesHandlingNoHeader(TestContext testContext) {
restStorageHandler = new RestStorageHandler(vertx, log, storage, "/", null,
false, false);

/*
* - no 'x-keep-double-slashes' header
* - path contains double slashes
* -> expectation: storage called with path containing single slashes only
*/
when(request.method()).thenReturn(HttpMethod.PUT);
when(request.headers()).thenReturn(new CaseInsensitiveHeaders());
when(request.uri()).thenReturn("/some//collection/resource");
when(request.path()).thenReturn("/some//collection/resource");
restStorageHandler.handle(request);
verify(storage, times(1)).put(eq("/some/collection/resource"), anyString(),
anyBoolean(), anyLong(), anyString(), any(LockMode.class), anyLong(), anyBoolean(), any(Handler.class));
}

@Test
public void testPUTRequestsDoubleSlashesHandlingWithHeader(TestContext testContext) {
restStorageHandler = new RestStorageHandler(vertx, log, storage, "/", null,
false, false);

/*
* - 'x-keep-double-slashes' header
* - path contains double slashes
* -> expectation: storage called with path containing double slashes
*/
when(request.method()).thenReturn(HttpMethod.PUT);
when(request.headers()).thenReturn(new CaseInsensitiveHeaders().add(HttpRequestHeader.KEEP_DOUBLE_SLASHES_HEADER.getName(), "true"));
when(request.uri()).thenReturn("/some//collection/resource");
when(request.path()).thenReturn("/some//collection/resource");
restStorageHandler.handle(request);
verify(storage, times(1)).put(eq("/some//collection/resource"), anyString(),
anyBoolean(), anyLong(), anyString(), any(LockMode.class), anyLong(), anyBoolean(), any(Handler.class));
}

@Test
public void testStorageExpandRequestsDoubleSlashesHandlingNoHeader(TestContext testContext) {
restStorageHandler = new RestStorageHandler(vertx, log, storage, "/", null,
false, false);

/*
* - no 'x-keep-double-slashes' header
* - path contains double slashes
* -> expectation: storage called with path containing single slashes only
*/
when(request.method()).thenReturn(HttpMethod.POST);
when(request.params()).thenReturn(new CaseInsensitiveHeaders().add(HttpRequestParam.STORAGE_EXPAND_PARAMETER.getName(), "true"));
when(request.headers()).thenReturn(new CaseInsensitiveHeaders());

doAnswer(invocation -> {
((Handler)invocation.getArguments()[0]).handle(Buffer.buffer("{ \"subResources\": [\"res1\", \"res2\", \"res3\"] }"));
return null;
}).when(request).bodyHandler(any());

when(request.uri()).thenReturn("/some//collection/resource");
when(request.path()).thenReturn("/some//collection/resource");
restStorageHandler.handle(request);
verify(storage, times(1)).storageExpand(eq("/some/collection/resource"), anyString(), anyList(), any(Handler.class));
}

@Test
public void testStorageExpandRequestsDoubleSlashesHandlingWithHeader(TestContext testContext) {
restStorageHandler = new RestStorageHandler(vertx, log, storage, "/", null,
false, false);

/*
* - 'x-keep-double-slashes' header
* - path contains double slashes
* -> expectation: storage called with path containing double slashes
*/
when(request.method()).thenReturn(HttpMethod.POST);
when(request.params()).thenReturn(new CaseInsensitiveHeaders().add(HttpRequestParam.STORAGE_EXPAND_PARAMETER.getName(), "true"));
when(request.headers()).thenReturn(new CaseInsensitiveHeaders().add(HttpRequestHeader.KEEP_DOUBLE_SLASHES_HEADER.getName(), "true"));

doAnswer(invocation -> {
((Handler)invocation.getArguments()[0]).handle(Buffer.buffer("{ \"subResources\": [\"res1\", \"res2\", \"res3\"] }"));
return null;
}).when(request).bodyHandler(any());

when(request.uri()).thenReturn("/some//collection/resource");
when(request.path()).thenReturn("/some//collection/resource");
restStorageHandler.handle(request);
verify(storage, times(1)).storageExpand(eq("/some//collection/resource"), anyString(), anyList(), any(Handler.class));
}
}

0 comments on commit ee08c2c

Please sign in to comment.