ResourcePredicateHandlerTestCase.java
/*
* JBoss, Home of Professional Open Source.
* Copyright 2023 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.undertow.server.handlers;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileAttribute;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import io.undertow.Handlers;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.builder.PredicatedHandler;
import io.undertow.server.handlers.builder.PredicatedHandlersParser;
import io.undertow.testutils.DefaultServer;
import io.undertow.testutils.TestHttpClient;
import io.undertow.util.StatusCodes;
/**
* Test basic resource serving via predicate handlers
*
* @author baranowb
*
*/
@RunWith(DefaultServer.class)
public class ResourcePredicateHandlerTestCase {
private static final String DIR_PREFIXED = "prefix-resource-dir";
private static final String DIR_PATH = "path-resource-dir";
private static final String FILE_NAME_LEVEL_0 = "file0";
private static final String FILE_NAME_LEVEL_1 = "file1";
private static final String DIR_SUB = "sub_dir";
private static final String GIBBERISH = "Gibberish, what did you expect?";
private static final String TEST_PREFIX = "prefixToTest";
@Test
public void testPrefixMatchWithURIAltering() throws IOException {
final PathsRetainer pathsRetainer = createTestDir(DIR_PREFIXED, false);
DefaultServer.setRootHandler(Handlers.predicates(
PredicatedHandlersParser
.parse("path-prefix(/" + TEST_PREFIX + ")-> { set(attribute=%U,value=${remaining}); resource(location='"
+ pathsRetainer.root.toString() + "',allow-listing=true) }", getClass().getClassLoader()),
new HttpHandler() {
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
}
}));
testURLListing(pathsRetainer, true);
}
@Test
public void testPrefixMatchNoURIAltering() throws IOException {
final PathsRetainer pathsRetainer = createTestDir(DIR_PREFIXED, true);
DefaultServer.setRootHandler(Handlers.predicates(
PredicatedHandlersParser
.parse("path-prefix(/" + TEST_PREFIX + ")-> { resource(location='"
+ pathsRetainer.root.toString() + "',allow-listing=true) }", getClass().getClassLoader()),
new HttpHandler() {
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
}
}));
testURLListing(pathsRetainer, true);
}
@Test
public void testPathMatchNoURIAltering() throws IOException {
final PathsRetainer pathsRetainer = createTestDir(DIR_PATH, true);
//No idea why parsing does not work in one go
final List<PredicatedHandler> lst = new ArrayList<>();
lst.addAll(PredicatedHandlersParser
.parse("path(/" + TEST_PREFIX + ")-> { resource(location='"
+ pathsRetainer.root.toString() + "',allow-listing=true)", getClass().getClassLoader()));
lst.addAll(PredicatedHandlersParser
.parse("path(/" + TEST_PREFIX + "/" +pathsRetainer.sub.getFileName() + ")-> { resource(location='"
+ pathsRetainer.root.toString() + "',allow-listing=true) }", getClass().getClassLoader()));
DefaultServer.setRootHandler(Handlers.predicates(lst,
new HttpHandler() {
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
Assert.assertFalse(true);
}
}));
testURLListing(pathsRetainer, false);
}
private void testURLListing(final PathsRetainer pathsRetainer, boolean testFile) throws IOException {
TestHttpClient client = new TestHttpClient();
HttpGet get = new HttpGet(DefaultServer.getDefaultServerURL() + "/" + TEST_PREFIX+"/");
HttpResponse result = client.execute(get);
Assert.assertEquals(StatusCodes.OK, result.getStatusLine().getStatusCode());
String bodyToTest = EntityUtils.toString(result.getEntity());
//this is not optimal...
Assert.assertTrue(bodyToTest.contains("href='/"+TEST_PREFIX+"/"+pathsRetainer.sub.getFileName()+"/'>"+pathsRetainer.sub.getFileName()+"</a>"));
Assert.assertTrue(bodyToTest.contains("href='/"+TEST_PREFIX+"/"+pathsRetainer.rootFile.getFileName()+"'>"+pathsRetainer.rootFile.getFileName()+"</a>"));
get = new HttpGet(DefaultServer.getDefaultServerURL() + "/" + TEST_PREFIX+ "/" +pathsRetainer.sub.getFileName()+ "/");
result = client.execute(get);
Assert.assertEquals(StatusCodes.OK, result.getStatusLine().getStatusCode());
bodyToTest = EntityUtils.toString(result.getEntity());
Assert.assertTrue(bodyToTest.contains("href='/"+TEST_PREFIX+"/'>[..]</a>"));
Assert.assertTrue(bodyToTest.contains("href='/"+TEST_PREFIX+"/"+pathsRetainer.sub.getFileName()+"/"+pathsRetainer.subFile.getFileName()+"'>"+pathsRetainer.subFile.getFileName()+"</a>"));
if(testFile) {
get = new HttpGet(DefaultServer.getDefaultServerURL() + "/"+TEST_PREFIX+"/"+pathsRetainer.sub.getFileName()+"/"+pathsRetainer.subFile.getFileName());
result = client.execute(get);
Assert.assertEquals(StatusCodes.OK, result.getStatusLine().getStatusCode());
bodyToTest = EntityUtils.toString(result.getEntity());
Assert.assertEquals(GIBBERISH, bodyToTest);
}
}
private PathsRetainer createTestDir(final String dirName, final boolean prefixDirectory) throws IOException {
final FileAttribute<?>[] attribs = new FileAttribute<?>[] {};
final PathsRetainer pathsRetainer = new PathsRetainer();
Path dir = Files.createTempDirectory(dirName);
if (prefixDirectory) {
//dont use temp, as it will add random stuff
//parent is already temp
File f = dir.toFile();
f = new File(f,TEST_PREFIX);
Assert.assertTrue(f.mkdir());
pathsRetainer.root = dir;
dir = f.toPath();
} else {
pathsRetainer.root = dir;
}
Path file = Files.createTempFile(dir, FILE_NAME_LEVEL_0,".txt", attribs);
pathsRetainer.rootFile = file;
writeGibberish(file);
final Path subdir = Files.createTempDirectory(dir, DIR_SUB);
pathsRetainer.sub = subdir;
file = Files.createTempFile(subdir, FILE_NAME_LEVEL_1,".txt", attribs);
pathsRetainer.subFile = file;
writeGibberish(file);
return pathsRetainer;
}
private void writeGibberish(final Path p) throws IOException {
Files.write(p,GIBBERISH.getBytes());
}
private static class PathsRetainer{
private Path root;
private Path rootFile;
private Path sub;
private Path subFile;
}
}