Hello, the method LocalReference.createFileReference(rootDirectory) does not return a valid root path for a Directory restlet with version 2.2.3, contrary to version 2.2.2. There is a workaround by tweaking the URI manually (use file:///C:/ rather than file:///C%3A/) and passing this string to the Directory constructor. Test 2.2.2 ``` Testsuite: org.restlet.test.TestRestletDirectory Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0,191 sec ------------- Standard Output --------------- -- TestRestletDirectory.testDirectory : restletVersion [2.2.2] -- TestRestletDirectory.testDirectory : rootDirectory [C:\Users\oparent\AppData\Local\Temp\restlet-test] test result httpStatus rootDirUri mime uri upper case plain OK 200 file:///C:/Users/oparent/AppData/Local/Temp/restlet-test text/html http://localhost:28092/hello.html upper case plain OK 200 file:///C:/Users/oparent/AppData/Local/Temp/restlet-test application/x-javascript http://localhost:28092/test.js upper case plain KO 404 file:///C:/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test-1.2.js lower case plain OK 200 file:///c:/Users/oparent/AppData/Local/Temp/restlet-test text/html http://localhost:28092/hello.html lower case plain OK 200 file:///c:/Users/oparent/AppData/Local/Temp/restlet-test application/x-javascript http://localhost:28092/test.js lower case plain KO 404 file:///c:/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test-1.2.js lower case uri encoded OK 200 file:///c%3A/Users/oparent/AppData/Local/Temp/restlet-test text/html http://localhost:28092/hello.html lower case uri encoded OK 200 file:///c%3A/Users/oparent/AppData/Local/Temp/restlet-test application/x-javascript http://localhost:28092/test.js lower case uri encoded KO 404 file:///c%3A/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test-1.2.js upper case uri encoded OK 200 file:///C%3A/Users/oparent/AppData/Local/Temp/restlet-test text/html http://localhost:28092/hello.html upper case uri encoded OK 200 file:///C%3A/Users/oparent/AppData/Local/Temp/restlet-test application/x-javascript http://localhost:28092/test.js upper case uri encoded KO 404 file:///C%3A/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test-1.2.js no drive letter OK 200 file:///Users/oparent/AppData/Local/Temp/restlet-test text/html http://localhost:28092/hello.html no drive letter OK 200 file:///Users/oparent/AppData/Local/Temp/restlet-test application/x-javascript http://localhost:28092/test.js no drive letter KO 404 file:///Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test-1.2.js localref.createref OK 200 file:///C%3A/Users/oparent/AppData/Local/Temp/restlet-test text/html http://localhost:28092/hello.html localref.createref OK 200 file:///C%3A/Users/oparent/AppData/Local/Temp/restlet-test application/x-javascript http://localhost:28092/test.js localref.createref KO 404 file:///C%3A/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test-1.2.js ------------- ---------------- --------------- Testcase: testDirectoryWithDriveLetter took 0,189 sec ``` Test 2.2.3 ``` Testsuite: org.restlet.test.TestRestletDirectory Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0,141 sec ------------- Standard Output --------------- -- TestRestletDirectory.testDirectory : restletVersion [2.2.3] -- TestRestletDirectory.testDirectory : rootDirectory [C:\Users\oparent\AppData\Local\Temp\restlet-test] test result httpStatus rootDirUri mime uri upper case plain OK 200 file:///C:/Users/oparent/AppData/Local/Temp/restlet-test text/html http://localhost:28092/hello.html upper case plain OK 200 file:///C:/Users/oparent/AppData/Local/Temp/restlet-test application/x-javascript http://localhost:28092/test.js upper case plain KO 404 file:///C:/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test-1.2.js lower case plain OK 200 file:///c:/Users/oparent/AppData/Local/Temp/restlet-test text/html http://localhost:28092/hello.html lower case plain OK 200 file:///c:/Users/oparent/AppData/Local/Temp/restlet-test application/x-javascript http://localhost:28092/test.js lower case plain KO 404 file:///c:/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test-1.2.js lower case uri encoded KO 403 file:///c%3A/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/hello.html lower case uri encoded KO 403 file:///c%3A/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test.js lower case uri encoded KO 403 file:///c%3A/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test-1.2.js upper case uri encoded KO 403 file:///C%3A/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/hello.html upper case uri encoded KO 403 file:///C%3A/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test.js upper case uri encoded KO 403 file:///C%3A/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test-1.2.js no drive letter OK 200 file:///Users/oparent/AppData/Local/Temp/restlet-test text/html http://localhost:28092/hello.html no drive letter OK 200 file:///Users/oparent/AppData/Local/Temp/restlet-test application/x-javascript http://localhost:28092/test.js no drive letter KO 404 file:///Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test-1.2.js localref.createref KO 403 file:///C%3A/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/hello.html localref.createref KO 403 file:///C%3A/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test.js localref.createref KO 403 file:///C%3A/Users/oparent/AppData/Local/Temp/restlet-test - http://localhost:28092/test-1.2.js ------------- ---------------- --------------- Testcase: testDirectoryWithDriveLetter took 0,14 sec ``` Junit Test Case ``` java |package org.restlet.test; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.URLEncoder; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; import junit.framework.TestCase; import org.restlet.Application; import org.restlet.Client; import org.restlet.Component; import org.restlet.Request; import org.restlet.Response; import org.restlet.Restlet; import org.restlet.data.CharacterSet; import org.restlet.data.LocalReference; import org.restlet.data.Method; import org.restlet.data.Protocol; import org.restlet.data.Reference; import org.restlet.data.Status; import org.restlet.engine.Engine; import org.restlet.representation.Representation; import org.restlet.resource.Directory; import org.restlet.routing.Router; /** * Tests Restlet {@link Directory} with different root URIs, issue on Windows with drive letter for 2.2.3. * * * <!-- creation 2014-11-28 --> * @author Olivier Parent */ public class TestRestletDirectory extends TestCase { /** DEBUG constant. */ private static final boolean DEBUG = false; static final Charset CHARSET = Charset.forName("utf-8"); static final Protocol PROTOCOL = Protocol.HTTP; /** * Tests {@link Directory} with a directory starting with a drive letter (Windows). * @throws Exception */ public void testDirectoryWithDriveLetter() throws Exception { final String restletVersion = getRestletVersion(); System.out.println("-- TestRestletDirectory.testDirectory : restletVersion [" + restletVersion + "]"); final String host = "localhost"; final int port = 28092; // Creates the root directory in tmp folder // ex C:\Users\{user}\AppData\Local\Temp\restlet-test final File rootDirectory; { rootDirectory = new File(System.getProperty("java.io.tmpdir") + "restlet-test").getCanonicalFile(); if(!rootDirectory.exists()) { if(!rootDirectory.mkdirs()) { fail("cannot create the root directory [" + rootDirectory + "]"); } } } final String rootPath = rootDirectory.getAbsolutePath(); System.out.println("-- TestRestletDirectory.testDirectory : rootDirectory [" + rootDirectory.getAbsolutePath() + "]"); // Creates same root directory URIs, with drive part modifications final String[][] rootDirUris = createRootPaths(rootDirectory, CHARSET); if(rootDirUris.length == 0) { System.out.println("-- TestRestletDirectory.testDirectory : no drive letter [" + rootPath + "] -> skip test"); return; } // Some test files to be retrieved final List<FileNameContent> fileNameContents; { final List<FileNameContent> list = new ArrayList<FileNameContent>(); list.add(new FileNameContent(rootDirectory, "hello.html" , "<!DOCTYPE html><html><head><meta charset=\"" + CHARSET.name() + "\"></head><body><h1>Hello World!</h1></body></html>")); list.add(new FileNameContent(rootDirectory, "test.js" , "function test() {return 'test';}")); // could not be retrieved with restlet-jse-2.2.2 ( 1.2 issue with tunneling maybe ?) // ok with restlet-jse-2.2.3 list.add(new FileNameContent(rootDirectory, "test-1.2.js" , "function test1_2() {return 'test-1.2';}")); fileNameContents = Collections.unmodifiableList(list); } // create local resources { for(FileNameContent f: fileNameContents) { f.ensurePresent(); } } final Client client = new Client(PROTOCOL); final Reference baseRef = new Reference(PROTOCOL.getSchemeName()+ "://" + host + ":" + port); if(DEBUG) System.out.println("-- TestRestletDirectory.testDirectory : base ref [" + baseRef + "]"); final List<List<String>> results = new ArrayList<List<String>>(); final Component component = createComponent(host, port); component.start(); for (int i = 0; i < rootDirUris.length;) { final String testName = rootDirUris[i ][0]; final String rootDirUri = rootDirUris[i++][1]; if(DEBUG) { System.out.println("-- TestRestletDirectory.testDirectory : test [" + testName + "]"); System.out.println(" [" + rootDirUri + "]"); } final Application application = createApplication(rootDirUri); component.getDefaultHost().attach(application); for(FileNameContent f: fileNameContents) { final Reference ref = new Reference(baseRef, f.getFileName()); if(DEBUG) System.out.println("-- TestRestletDirectory.testDirectory : ref [" + ref.getTargetRef() + "]"); final Request request = new Request(Method.GET, ref); final Response response = client.handle(request); if(DEBUG) System.out.println("-- TestRestletDirectory.testDirectory : response status [" + response + "]"); final String contentType; if(response.getStatus().getCode() == Status.SUCCESS_OK.getCode()) { final Representation rep = response.getEntity(); if(DEBUG) System.out.println("-- TestRestletDirectory.testDirectory : rep [" + rep + "]"); contentType = rep.getMediaType().getName(); } else { contentType = "-"; } final List<String> result = new ArrayList<String>(); result.add(testName); result.add(response.getStatus().getCode() == Status.SUCCESS_OK.getCode() ? "OK" : "KO" ); result.add(String.valueOf(response.getStatus().getCode())); result.add(rootDirUri); result.add(contentType); result.add(ref.getTargetRef().toString()); results.add(result); } component.getDefaultHost().detach(application); } component.stop(); final char separator = '\t'; final List<String> headers = Arrays.asList( "test", "result", "httpStatus", "rootDirUri", "mime", "uri" ); System.out.println(join(headers, separator)); for(List<String> result: results) { System.out.println(join(result, separator)); } } private static final String join(Collection<?> values, char separator) { final StringBuilder sb = new StringBuilder(); boolean isFirst = true; for(Object value: values) { if(isFirst) { isFirst = false; } else { sb.append(separator); } sb.append(String.valueOf(value)); } return sb.toString(); } /** * @return the restlet version */ private static final String getRestletVersion() throws Exception { // { // final ClassLoader classLoader = Restlet.class.getClassLoader(); // //final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // final URL url = classLoader.getResource(Restlet.class.getName().replace('.', '/') + ".class"); // if(DEBUG) System.out.println("-- TestRestletDirectory.getRestletVersion : url [" + url + "]"); // // final Pattern pattern = Pattern.compile("/(restlet[^/]+)"); // final Matcher matcher = pattern.matcher(url.toString()); // if(matcher.find()) { // restletVersion = matcher.group(1); // } // else { // restletVersion = (String) Engine.class.getField("VERSION").get(null); // } // return (String) Engine.class.getField("VERSION").get(null); // return Engine.VERSION; } /** * @param rootDirectory * @param uriCharset * @return test paths * @throws UnsupportedEncodingException */ private static final String[][] createRootPaths(File rootDirectory, Charset uriCharset) throws UnsupportedEncodingException { final Pattern pattern = Pattern.compile("^((?i)[A-Z]):(.+)$"); final Matcher matcher = pattern.matcher(rootDirectory.getAbsolutePath()); if(matcher.matches()) { final String driveLetter = matcher.group(1); final String pathUri = toUri(matcher.group(2), uriCharset); // format(test name, path)+ return new String[][] { {"lower case plain" , "file:///" + driveLetter.toLowerCase(Locale.ENGLISH) + ":" + pathUri}, {"upper case plain" , "file:///" + driveLetter.toUpperCase(Locale.ENGLISH) + ":" + pathUri}, {"lower case uri encoded" , "file:///" + driveLetter.toLowerCase(Locale.ENGLISH) + toUri(":", uriCharset) + pathUri}, {"upper case uri encoded" , "file:///" + driveLetter.toUpperCase(Locale.ENGLISH) + toUri(":", uriCharset) + pathUri}, {"no drive letter" , "file://" + pathUri}, {"localref.createref" , LocalReference.createFileReference(rootDirectory).toString()} }; } return new String[0][0]; } /** * @param value * @throws UnsupportedEncodingException */ private static final String toUri(String value, Charset charset) throws UnsupportedEncodingException { final String delim = "/"; value = value.replace('\\', delim.charAt(0)); final StringBuilder sb = new StringBuilder(); //sb.append(); final StringTokenizer tokenizer = new StringTokenizer(value, delim, true); while(tokenizer.hasMoreElements()) { String token = tokenizer.nextToken(); if(!token.equals(delim)) { token = URLEncoder.encode(token, charset.name()); } sb.append(token); } return sb.toString(); } private static final Component createComponent(final String host, final int port) { final Component component = new Component(); component.getClients().add(Protocol.FILE); component.getClients().add(Protocol.CLAP); component.getClients().add(Protocol.HTTP); component.getServers().add(PROTOCOL, host, port); return component; } /** * Creates a component with a server and and application with a router built with a single directory. * @param rootDirUri * @param host * @param port * @return a test component */ private static final Application createApplication(final String rootDirUri) { final Application application = new Application() { public Restlet createInboundRoot() { final Router router = new Router(getContext()); final Directory directory = new Directory(getContext(), rootDirUri); directory.setListingAllowed(true); router.attachDefault(directory); return router; } }; application.getMetadataService().setDefaultCharacterSet(new CharacterSet(CHARSET)); return application; } /** * File name and content */ private static final class FileNameContent { private final File directory; private final String fileName; private final String content; public FileNameContent(File directory, String fileName, String content) { this.directory = directory; this.fileName = fileName; this.content = content; } /** * */ public void ensurePresent() throws IOException { final File file = new File(directory, fileName); if(file.exists()) { return; } if(DEBUG) System.out.println("-- FileNameContent.ensurePresent : create [" + file + "]"); writeTextIfNotPresent(file, content); } public final String getFileName() { return fileName; } // public final String getContent() { // return content; // } private static final void writeTextIfNotPresent(File file, String text) throws IOException { OutputStream output = null; Writer writer = null; try { output = new FileOutputStream(file); writer = new OutputStreamWriter(output, CHARSET); writer.write(text); writer.close(); } finally { if(writer != null) { try { writer.close(); } catch (IOException e) { } } if(output != null) { try { output.close(); } catch (IOException e) { } } } } } } ```