| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.util.resource; |
| |
| import java.io.File; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.net.URI; |
| import java.net.URL; |
| import java.nio.ByteBuffer; |
| import java.nio.channels.ReadableByteChannel; |
| import java.nio.file.FileSystemException; |
| import java.nio.file.Files; |
| import java.nio.file.InvalidPathException; |
| import java.nio.file.Path; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import org.eclipse.jetty.toolchain.test.FS; |
| import org.eclipse.jetty.toolchain.test.IO; |
| import org.eclipse.jetty.toolchain.test.OS; |
| import org.eclipse.jetty.toolchain.test.TestingDir; |
| import org.eclipse.jetty.util.BufferUtil; |
| import org.eclipse.jetty.util.CollectionAssert; |
| import org.junit.Assert; |
| import org.junit.Rule; |
| import org.junit.Test; |
| |
| import static org.hamcrest.Matchers.is; |
| import static org.hamcrest.Matchers.notNullValue; |
| import static org.hamcrest.Matchers.nullValue; |
| import static org.junit.Assert.assertThat; |
| import static org.junit.Assert.fail; |
| import static org.junit.Assume.assumeFalse; |
| import static org.junit.Assume.assumeNoException; |
| |
| public abstract class AbstractFSResourceTest |
| { |
| @Rule |
| public TestingDir testdir = new TestingDir(); |
| |
| public abstract Resource newResource(URI uri) throws IOException; |
| |
| public abstract Resource newResource(File file) throws IOException; |
| |
| private URI createEmptyFile(String name) throws IOException |
| { |
| File file = testdir.getFile(name); |
| file.createNewFile(); |
| return file.toURI(); |
| } |
| |
| @Test(expected = IllegalArgumentException.class) |
| public void testNonAbsoluteURI() throws Exception |
| { |
| newResource(new URI("path/to/resource")); |
| } |
| |
| @Test(expected = IllegalArgumentException.class) |
| public void testNotFileURI() throws Exception |
| { |
| newResource(new URI("http://www.eclipse.org/jetty/")); |
| } |
| |
| @Test(expected = IllegalArgumentException.class) |
| public void testBogusFilename() throws Exception |
| { |
| if (OS.IS_UNIX) |
| { |
| // A windows path is invalid under unix |
| newResource(new URI("file://Z:/:")); |
| } |
| else if (OS.IS_WINDOWS) |
| { |
| // "CON" is a reserved name under windows |
| newResource(new URI("file://CON")); |
| } |
| else |
| { |
| assumeFalse("Unknown OS type",false); |
| } |
| } |
| |
| @Test |
| public void testIsContainedIn() throws Exception |
| { |
| createEmptyFile("foo"); |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource res = base.addPath("foo"); |
| assertThat("is contained in",res.isContainedIn(base),is(false)); |
| } |
| } |
| |
| @Test |
| public void testAddPath() throws Exception |
| { |
| File dir = testdir.getDir(); |
| File subdir = new File(dir,"sub"); |
| FS.ensureDirExists(subdir); |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource sub = base.addPath("sub"); |
| assertThat("sub/.isDirectory",sub.isDirectory(),is(true)); |
| |
| Resource tmp = sub.addPath("/tmp"); |
| assertThat("No root",tmp.exists(),is(false)); |
| } |
| } |
| |
| @Test |
| public void testIsDirectory() throws Exception |
| { |
| File dir = testdir.getDir(); |
| createEmptyFile("foo"); |
| |
| File subdir = new File(dir,"sub"); |
| FS.ensureDirExists(subdir); |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource res = base.addPath("foo"); |
| assertThat("foo.isDirectory",res.isDirectory(),is(false)); |
| |
| Resource sub = base.addPath("sub"); |
| assertThat("sub/.isDirectory",sub.isDirectory(),is(true)); |
| } |
| } |
| |
| @Test |
| public void testLastModified() throws Exception |
| { |
| File file = testdir.getFile("foo"); |
| file.createNewFile(); |
| |
| long expected = file.lastModified(); |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource res = base.addPath("foo"); |
| assertThat("foo.lastModified",res.lastModified(),is(expected)); |
| } |
| } |
| |
| @Test |
| public void testLastModified_NotExists() throws Exception |
| { |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource res = base.addPath("foo"); |
| assertThat("foo.lastModified",res.lastModified(),is(0L)); |
| } |
| } |
| |
| @Test |
| public void testLength() throws Exception |
| { |
| File file = testdir.getFile("foo"); |
| file.createNewFile(); |
| |
| try (StringReader reader = new StringReader("foo"); FileWriter writer = new FileWriter(file)) |
| { |
| IO.copy(reader,writer); |
| } |
| |
| long expected = file.length(); |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource res = base.addPath("foo"); |
| assertThat("foo.length",res.length(),is(expected)); |
| } |
| } |
| |
| @Test |
| public void testLength_NotExists() throws Exception |
| { |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource res = base.addPath("foo"); |
| assertThat("foo.length",res.length(),is(0L)); |
| } |
| } |
| |
| @Test |
| public void testDelete() throws Exception |
| { |
| File file = testdir.getFile("foo"); |
| file.createNewFile(); |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| // Is it there? |
| Resource res = base.addPath("foo"); |
| assertThat("foo.exists",res.exists(),is(true)); |
| // delete it |
| assertThat("foo.delete",res.delete(),is(true)); |
| // is it there? |
| assertThat("foo.exists",res.exists(),is(false)); |
| } |
| } |
| |
| @Test |
| public void testDelete_NotExists() throws Exception |
| { |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| // Is it there? |
| Resource res = base.addPath("foo"); |
| assertThat("foo.exists",res.exists(),is(false)); |
| // delete it |
| assertThat("foo.delete",res.delete(),is(false)); |
| // is it there? |
| assertThat("foo.exists",res.exists(),is(false)); |
| } |
| } |
| |
| @Test |
| public void testName() throws Exception |
| { |
| String expected = testdir.getDir().getAbsolutePath(); |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| assertThat("base.name",base.getName(),is(expected)); |
| } |
| } |
| |
| @Test |
| public void testInputStream() throws Exception |
| { |
| File file = testdir.getFile("foo"); |
| file.createNewFile(); |
| |
| String content = "Foo is here"; |
| |
| try (StringReader reader = new StringReader(content); FileWriter writer = new FileWriter(file)) |
| { |
| IO.copy(reader,writer); |
| } |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource foo = base.addPath("foo"); |
| try (InputStream stream = foo.getInputStream(); InputStreamReader reader = new InputStreamReader(stream); StringWriter writer = new StringWriter()) |
| { |
| IO.copy(reader,writer); |
| assertThat("Stream",writer.toString(),is(content)); |
| } |
| } |
| } |
| |
| @Test |
| public void testReadableByteChannel() throws Exception |
| { |
| File file = testdir.getFile("foo"); |
| file.createNewFile(); |
| |
| String content = "Foo is here"; |
| |
| try (StringReader reader = new StringReader(content); FileWriter writer = new FileWriter(file)) |
| { |
| IO.copy(reader,writer); |
| } |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource foo = base.addPath("foo"); |
| try (ReadableByteChannel channel = foo.getReadableByteChannel()) |
| { |
| ByteBuffer buf = ByteBuffer.allocate(256); |
| channel.read(buf); |
| buf.flip(); |
| String actual = BufferUtil.toUTF8String(buf); |
| assertThat("ReadableByteChannel content",actual,is(content)); |
| } |
| } |
| } |
| |
| @Test |
| public void testGetURI() throws Exception |
| { |
| File file = testdir.getFile("foo"); |
| file.createNewFile(); |
| |
| URI expected = file.toURI(); |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource foo = base.addPath("foo"); |
| assertThat("getURI",foo.getURI(),is(expected)); |
| } |
| } |
| |
| @Test |
| public void testGetURL() throws Exception |
| { |
| File file = testdir.getFile("foo"); |
| file.createNewFile(); |
| |
| URL expected = file.toURI().toURL(); |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource foo = base.addPath("foo"); |
| assertThat("getURL",foo.getURL(),is(expected)); |
| } |
| } |
| |
| @Test |
| public void testList() throws Exception |
| { |
| File dir = testdir.getDir(); |
| FS.touch(new File(dir, "foo")); |
| FS.touch(new File(dir, "bar")); |
| FS.ensureDirExists(new File(dir, "tick")); |
| FS.ensureDirExists(new File(dir, "tock")); |
| |
| List<String> expected = new ArrayList<>(); |
| expected.add("foo"); |
| expected.add("bar"); |
| expected.add("tick/"); |
| expected.add("tock/"); |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| String list[] = base.list(); |
| List<String> actual = Arrays.asList(list); |
| |
| CollectionAssert.assertContainsUnordered("Resource Directory Listing", |
| expected,actual); |
| } |
| } |
| |
| @Test |
| public void testSymlink() throws Exception |
| { |
| File dir = testdir.getDir(); |
| |
| Path foo = new File(dir, "foo").toPath(); |
| Path bar = new File(dir, "bar").toPath(); |
| |
| try |
| { |
| Files.createFile(foo); |
| Files.createSymbolicLink(bar,foo); |
| } |
| catch (UnsupportedOperationException | FileSystemException e) |
| { |
| // if unable to create symlink, no point testing the rest |
| // this is the path that Microsoft Windows takes. |
| assumeNoException(e); |
| } |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource resFoo = base.addPath("foo"); |
| Resource resBar = base.addPath("bar"); |
| |
| // Access to the same resource, but via a symlink means that they are not equivalent |
| assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false)); |
| |
| assertThat("foo.alias", resFoo.getAlias(), nullValue()); |
| assertThat("bar.alias", resBar.getAlias(), is(foo.toUri())); |
| } |
| } |
| |
| @Test |
| public void testSemicolon() throws Exception |
| { |
| File dir = testdir.getDir(); |
| |
| try |
| { |
| // attempt to create file |
| Path foo = new File(dir, "foo;").toPath(); |
| Files.createFile(foo); |
| } |
| catch (Exception e) |
| { |
| // if unable to create file, no point testing the rest |
| // this is the path that Microsoft Windows takes. |
| assumeNoException(e); |
| } |
| |
| try (Resource base = newResource(testdir.getDir())) |
| { |
| Resource res = base.addPath("foo;"); |
| assertThat("Alias: " + res,res.getAlias(),nullValue()); |
| } |
| } |
| |
| @Test |
| public void testExist_Normal() throws Exception |
| { |
| createEmptyFile("a.jsp"); |
| |
| URI ref = testdir.getDir().toURI().resolve("a.jsp"); |
| try (Resource fileres = newResource(ref)) |
| { |
| assertThat("Resource: " + fileres,fileres.exists(),is(true)); |
| } |
| } |
| |
| @Test |
| public void testSingleQuoteInFileName() throws Exception |
| { |
| createEmptyFile("foo's.txt"); |
| createEmptyFile("f o's.txt"); |
| |
| URI refQuoted = testdir.getDir().toURI().resolve("foo's.txt"); |
| |
| try (Resource fileres = newResource(refQuoted)) |
| { |
| assertThat("Exists: " + refQuoted,fileres.exists(),is(true)); |
| assertThat("Alias: " + refQuoted,fileres.getAlias(),nullValue()); |
| } |
| |
| URI refEncoded = testdir.getDir().toURI().resolve("foo%27s.txt"); |
| |
| try (Resource fileres = newResource(refEncoded)) |
| { |
| assertThat("Exists: " + refEncoded,fileres.exists(),is(true)); |
| assertThat("Alias: " + refEncoded,fileres.getAlias(),nullValue()); |
| } |
| |
| URI refQuoteSpace = testdir.getDir().toURI().resolve("f%20o's.txt"); |
| |
| try (Resource fileres = newResource(refQuoteSpace)) |
| { |
| assertThat("Exists: " + refQuoteSpace,fileres.exists(),is(true)); |
| assertThat("Alias: " + refQuoteSpace,fileres.getAlias(),nullValue()); |
| } |
| |
| URI refEncodedSpace = testdir.getDir().toURI().resolve("f%20o%27s.txt"); |
| |
| try (Resource fileres = newResource(refEncodedSpace)) |
| { |
| assertThat("Exists: " + refEncodedSpace,fileres.exists(),is(true)); |
| assertThat("Alias: " + refEncodedSpace,fileres.getAlias(),nullValue()); |
| } |
| |
| URI refA = testdir.getDir().toURI().resolve("foo's.txt"); |
| URI refB = testdir.getDir().toURI().resolve("foo%27s.txt"); |
| |
| StringBuilder msg = new StringBuilder(); |
| msg.append("URI[a].equals(URI[b])").append(System.lineSeparator()); |
| msg.append("URI[a] = ").append(refA).append(System.lineSeparator()); |
| msg.append("URI[b] = ").append(refB); |
| |
| // show that simple URI.equals() doesn't work |
| assertThat(msg.toString(),refA.equals(refB),is(false)); |
| |
| // now show that Resource.equals() does work |
| try (Resource a = newResource(refA); Resource b = newResource(refB);) |
| { |
| assertThat("A.equals(B)",a.equals(b),is(true)); |
| } |
| } |
| |
| @Test |
| public void testExist_BadNull() throws Exception |
| { |
| createEmptyFile("a.jsp"); |
| |
| try |
| { |
| // request with null at end |
| URI ref = testdir.getDir().toURI().resolve("a.jsp%00"); |
| assertThat("Null URI",ref,notNullValue()); |
| |
| newResource(ref); |
| fail("Should have thrown " + InvalidPathException.class); |
| } |
| catch (InvalidPathException e) |
| { |
| // Expected path |
| } |
| } |
| |
| @Test |
| public void testExist_BadNullX() throws Exception |
| { |
| createEmptyFile("a.jsp"); |
| |
| try |
| { |
| // request with null and x at end |
| URI ref = testdir.getDir().toURI().resolve("a.jsp%00x"); |
| assertThat("NullX URI",ref,notNullValue()); |
| |
| newResource(ref); |
| fail("Should have thrown " + InvalidPathException.class); |
| } |
| catch (InvalidPathException e) |
| { |
| // Expected path |
| } |
| } |
| |
| @Test |
| public void testExist_BadControlChars_Encoded() throws Exception |
| { |
| createEmptyFile("a.jsp"); |
| |
| try |
| { |
| // request with control characters |
| URI ref = testdir.getDir().toURI().resolve("a.jsp%1F%10"); |
| assertThat("ControlCharacters URI",ref,notNullValue()); |
| |
| Resource fileref = newResource(ref); |
| assertThat("File Resource should not exists", fileref.exists(), is(false)); |
| } |
| catch (InvalidPathException e) |
| { |
| // Expected path |
| } |
| } |
| |
| @Test |
| public void testExist_BadControlChars_Decoded() throws Exception |
| { |
| createEmptyFile("a.jsp"); |
| |
| try |
| { |
| // request with control characters |
| File badFile = new File(testdir.getDir(), "a.jsp\014\010"); |
| newResource(badFile); |
| fail("Should have thrown " + InvalidPathException.class); |
| } |
| catch (InvalidPathException e) |
| { |
| // Expected path |
| } |
| } |
| |
| @Test |
| public void testExist_AddPath_BadControlChars_Decoded() throws Exception |
| { |
| createEmptyFile("a.jsp"); |
| |
| try |
| { |
| // base resource |
| URI ref = testdir.getDir().toURI(); |
| Resource base = newResource(ref); |
| assertThat("Base Resource URI",ref,notNullValue()); |
| |
| // add path with control characters (raw/decoded control characters) |
| // This MUST fail |
| base.addPath("/a.jsp\014\010"); |
| fail("Should have thrown " + InvalidPathException.class); |
| } |
| catch (InvalidPathException e) |
| { |
| // Expected path |
| } |
| } |
| |
| @Test |
| public void testExist_AddPath_BadControlChars_Encoded() throws Exception |
| { |
| createEmptyFile("a.jsp"); |
| |
| try |
| { |
| // base resource |
| URI ref = testdir.getDir().toURI(); |
| Resource base = newResource(ref); |
| assertThat("Base Resource URI",ref,notNullValue()); |
| |
| // add path with control characters |
| Resource fileref = base.addPath("/a.jsp%14%10"); |
| assertThat("File Resource should not exists", fileref.exists(), is(false)); |
| } |
| catch (InvalidPathException e) |
| { |
| // Expected path |
| } |
| } |
| |
| @Test |
| public void testUtf8Dir() throws Exception |
| { |
| File dir=new File(testdir.getDir(),"bãm"); |
| dir.mkdir(); |
| File file = new File(dir,"file.txt"); |
| file.createNewFile(); |
| |
| Resource base = newResource(dir); |
| Assert.assertNull(base.getAlias()); |
| |
| Resource r = base.addPath("file.txt"); |
| Assert.assertNull(r.getAlias()); |
| |
| } |
| } |