1 /* 2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* @test 25 * @bug 4957669 5017871 26 * @summary cannot load class names containing some JSR 202 characters; 27 * plugin does not escape unicode character in http request 28 * @modules java.base/sun.net.www 29 * jdk.httpserver 30 * @compile -XDignore.symbol.file=true ClassnameCharTest.java 31 * @run main ClassnameCharTest 32 */ 33 34 import java.io.*; 35 import java.net.*; 36 import java.security.AccessControlContext; 37 import java.security.AccessController; 38 import java.security.CodeSource; 39 import java.security.PrivilegedActionException; 40 import java.security.PrivilegedExceptionAction; 41 import java.util.jar.*; 42 import com.sun.net.httpserver.*; 43 import sun.net.www.ParseUtil; 44 45 public class ClassnameCharTest { 46 static String FNPrefix = System.getProperty("test.src", ".") + File.separator; 47 static File classesJar = new File(FNPrefix + "testclasses.jar"); 48 static HttpServer server; 49 50 public static void realMain(String[] args) throws Exception { 51 server = HttpServer.create(new InetSocketAddress(0), 0); 52 server.createContext("/", new HttpHandler() { 53 @Override 54 public void handle(HttpExchange exchange) { 55 try { 56 String filename = exchange.getRequestURI().getPath(); 57 System.out.println("getRequestURI = " + exchange.getRequestURI()); 58 System.out.println("filename = " + filename); 59 try (FileInputStream fis = new FileInputStream(classesJar); 60 JarInputStream jis = new JarInputStream(fis)) { 61 JarEntry entry; 62 while ((entry = jis.getNextJarEntry()) != null) { 63 if (filename.endsWith(entry.getName())) { 64 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 65 byte[] buf = new byte[8092]; 66 int count = 0; 67 while ((count = jis.read(buf)) != -1) 68 baos.write(buf, 0, count); 69 exchange.sendResponseHeaders(200, baos.size()); 70 try (OutputStream os = exchange.getResponseBody()) { 71 baos.writeTo(os); 72 } 73 return; 74 } 75 } 76 fail("Failed to find " + filename); 77 } 78 } catch (IOException e) { 79 unexpected(e); 80 } 81 } 82 }); 83 server.start(); 84 try { 85 URL base = new URL("http://localhost:" + server.getAddress().getPort()); 86 System.out.println ("Server: listening on " + base); 87 MyURLClassLoader acl = new MyURLClassLoader(base); 88 Class<?> class1 = acl.findClass("fo o"); 89 System.out.println("class1 = " + class1); 90 pass(); 91 // can't test the following class unless platform in unicode locale 92 // Class class2 = acl.findClass("\u624b\u518c"); 93 // System.out.println("class2 = "+class2); 94 } finally { 95 server.stop(0); 96 } 97 } 98 99 static class MyURLClassLoader extends URLClassLoader { 100 private URL base; /* applet code base URL */ 101 private CodeSource codesource; /* codesource for the base URL */ 102 private AccessControlContext acc; 103 MyURLClassLoader(URL base) { 104 super(new URL[0]); 105 this.base = base; 106 this.codesource = 107 new CodeSource(base, (java.security.cert.Certificate[]) null); 108 acc = AccessController.getContext(); 109 } 110 111 @Override 112 public Class<?> findClass(String name) throws ClassNotFoundException { 113 int index = name.indexOf(';'); 114 String cookie = ""; 115 if(index != -1) { 116 cookie = name.substring(index, name.length()); 117 name = name.substring(0, index); 118 } 119 120 // check loaded JAR files 121 try { 122 return super.findClass(name); 123 } catch (ClassNotFoundException e) { 124 } 125 126 // Otherwise, try loading the class from the code base URL 127 // final String path = name.replace('.', '/').concat(".class").concat(cookie); 128 String encodedName = ParseUtil.encodePath(name.replace('.', '/'), false); 129 final String path = (new StringBuffer(encodedName)).append(".class").append(cookie).toString(); 130 try { 131 byte[] b = AccessController.doPrivileged( 132 new PrivilegedExceptionAction<byte[]>() { 133 public byte[] run() throws IOException { 134 try { 135 URL finalURL = new URL(base, path); 136 137 // Make sure the codebase won't be modified 138 if (base.getProtocol().equals(finalURL.getProtocol()) && 139 base.getHost().equals(finalURL.getHost()) && 140 base.getPort() == finalURL.getPort()) { 141 return getBytes(finalURL); 142 } 143 else { 144 return null; 145 } 146 } catch (Exception e) { 147 return null; 148 } 149 } 150 }, acc); 151 152 if (b != null) { 153 return defineClass(name, b, 0, b.length, codesource); 154 } else { 155 throw new ClassNotFoundException(name); 156 } 157 } catch (PrivilegedActionException e) { 158 throw new ClassNotFoundException(name, e.getException()); 159 } 160 } 161 162 /* 163 * Returns the contents of the specified URL as an array of bytes. 164 */ 165 private static byte[] getBytes(URL url) throws IOException { 166 URLConnection uc = url.openConnection(); 167 if (uc instanceof java.net.HttpURLConnection) { 168 java.net.HttpURLConnection huc = (java.net.HttpURLConnection) uc; 169 int code = huc.getResponseCode(); 170 if (code >= java.net.HttpURLConnection.HTTP_BAD_REQUEST) { 171 throw new IOException("open HTTP connection failed."); 172 } 173 } 174 int len = uc.getContentLength(); 175 176 InputStream in = new BufferedInputStream(uc.getInputStream()); 177 178 byte[] b; 179 try { 180 b = in.readAllBytes(); 181 if (len != -1 && b.length != len) 182 throw new EOFException("Expected:" + len + ", read:" + b.length); 183 } finally { 184 in.close(); 185 } 186 return b; 187 } 188 } 189 190 //--------------------- Infrastructure --------------------------- 191 static volatile int passed = 0, failed = 0; 192 193 static boolean pass() { 194 passed++; 195 return true; 196 } 197 198 static boolean fail() { 199 failed++; 200 if (server != null) { 201 server.stop(0); 202 } 203 Thread.dumpStack(); 204 return false; 205 } 206 207 static boolean fail(String msg) { 208 System.out.println(msg); 209 return fail(); 210 } 211 212 static void unexpected(Throwable t) { 213 failed++; 214 if (server != null) { 215 server.stop(0); 216 } 217 t.printStackTrace(); 218 } 219 220 static boolean check(boolean cond) { 221 if (cond) { 222 pass(); 223 } else { 224 fail(); 225 } 226 return cond; 227 } 228 229 static boolean equal(Object x, Object y) { 230 if (x == null ? y == null : x.equals(y)) { 231 return pass(); 232 } else { 233 return fail(x + " not equal to " + y); 234 } 235 } 236 237 public static void main(String[] args) throws Throwable { 238 try { 239 realMain(args); 240 } catch (Throwable t) { 241 unexpected(t); 242 } 243 System.out.println("\nPassed = " + passed + " failed = " + failed); 244 if (failed > 0) { 245 throw new AssertionError("Some tests failed"); 246 } 247 } 248 }