1/* 2 * Copyright (c) 2014, 2017, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package sun.net.www.protocol.jrt; 27 28import java.io.ByteArrayInputStream; 29import java.io.IOException; 30import java.io.InputStream; 31import java.net.MalformedURLException; 32import java.net.URL; 33import java.security.AccessController; 34import java.security.Permission; 35import java.security.PrivilegedAction; 36 37import jdk.internal.jimage.ImageLocation; 38import jdk.internal.jimage.ImageReader; 39import jdk.internal.jimage.ImageReaderFactory; 40 41import jdk.internal.loader.URLClassPath; 42import jdk.internal.loader.Resource; 43import sun.net.www.ParseUtil; 44import sun.net.www.URLConnection; 45 46/** 47 * URLConnection implementation that can be used to connect to resources 48 * contained in the runtime image. 49 */ 50public class JavaRuntimeURLConnection extends URLConnection { 51 52 // ImageReader to access resources in jimage 53 private static final ImageReader reader; 54 static { 55 PrivilegedAction<ImageReader> pa = ImageReaderFactory::getImageReader; 56 reader = AccessController.doPrivileged(pa); 57 } 58 59 // the module and resource name in the URL 60 private final String module; 61 private final String name; 62 63 // the Resource when connected 64 private volatile Resource resource; 65 66 JavaRuntimeURLConnection(URL url) throws IOException { 67 super(url); 68 String path = url.getPath(); 69 if (path.length() == 0 || path.charAt(0) != '/') 70 throw new MalformedURLException(url + " missing path or /"); 71 if (path.length() == 1) { 72 this.module = null; 73 this.name = null; 74 } else { 75 int pos = path.indexOf('/', 1); 76 if (pos == -1) { 77 this.module = path.substring(1); 78 this.name = null; 79 } else { 80 this.module = path.substring(1, pos); 81 this.name = ParseUtil.decode(path.substring(pos+1)); 82 } 83 } 84 } 85 86 /** 87 * Finds a resource in a module, returning {@code null} if the resource 88 * is not found. 89 */ 90 private static Resource findResource(String module, String name) { 91 if (reader != null) { 92 URL url = toJrtURL(module, name); 93 ImageLocation location = reader.findLocation(module, name); 94 if (location != null && URLClassPath.checkURL(url) != null) { 95 return new Resource() { 96 @Override 97 public String getName() { 98 return name; 99 } 100 @Override 101 public URL getURL() { 102 return url; 103 } 104 @Override 105 public URL getCodeSourceURL() { 106 return toJrtURL(module); 107 } 108 @Override 109 public InputStream getInputStream() throws IOException { 110 byte[] resource = reader.getResource(location); 111 return new ByteArrayInputStream(resource); 112 } 113 @Override 114 public int getContentLength() { 115 long size = location.getUncompressedSize(); 116 return (size > Integer.MAX_VALUE) ? -1 : (int) size; 117 } 118 }; 119 } 120 } 121 return null; 122 } 123 124 @Override 125 public synchronized void connect() throws IOException { 126 if (!connected) { 127 if (name == null) { 128 String s = (module == null) ? "" : module; 129 throw new IOException("cannot connect to jrt:/" + s); 130 } 131 resource = findResource(module, name); 132 if (resource == null) 133 throw new IOException(module + "/" + name + " not found"); 134 connected = true; 135 } 136 } 137 138 @Override 139 public InputStream getInputStream() throws IOException { 140 connect(); 141 return resource.getInputStream(); 142 } 143 144 @Override 145 public long getContentLengthLong() { 146 try { 147 connect(); 148 return resource.getContentLength(); 149 } catch (IOException ioe) { 150 return -1L; 151 } 152 } 153 154 @Override 155 public int getContentLength() { 156 long len = getContentLengthLong(); 157 return len > Integer.MAX_VALUE ? -1 : (int)len; 158 } 159 160 @Override 161 public Permission getPermission() { 162 return new RuntimePermission("accessSystemModules"); 163 } 164 165 /** 166 * Returns a jrt URL for the given module and resource name. 167 */ 168 private static URL toJrtURL(String module, String name) { 169 try { 170 return new URL("jrt:/" + module + "/" + name); 171 } catch (MalformedURLException e) { 172 throw new InternalError(e); 173 } 174 } 175 176 /** 177 * Returns a jrt URL for the given module. 178 */ 179 private static URL toJrtURL(String module) { 180 try { 181 return new URL("jrt:/" + module); 182 } catch (MalformedURLException e) { 183 throw new InternalError(e); 184 } 185 } 186} 187