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 }