1 /* 2 * Copyright (c) 2014, 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 26 package sun.net.www.protocol.jrt; 27 28 import java.io.ByteArrayInputStream; 29 import java.io.File; 30 import java.io.FilePermission; 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.net.MalformedURLException; 34 import java.net.URL; 35 import java.security.AccessController; 36 import java.security.Permission; 37 import java.security.PrivilegedAction; 38 39 import jdk.internal.jimage.ImageLocation; 40 import jdk.internal.jimage.ImageReader; 41 import jdk.internal.jimage.ImageReaderFactory; 42 43 import jdk.internal.loader.URLClassPath; 44 import jdk.internal.loader.Resource; 45 import sun.net.www.ParseUtil; 46 import sun.net.www.URLConnection; 47 import sun.security.action.GetPropertyAction; 48 49 /** 50 * URLConnection implementation that can be used to connect to resources 51 * contained in the runtime image. 52 */ 53 public class JavaRuntimeURLConnection extends URLConnection { 54 55 // ImageReader to access resources in jimage 56 private static final ImageReader reader; 57 static { 58 PrivilegedAction<ImageReader> pa = ImageReaderFactory::getImageReader; 59 reader = AccessController.doPrivileged(pa); 60 } 61 62 // the module and resource name in the URL 63 private final String module; 64 private final String name; 65 66 // the Resource when connected 67 private volatile Resource resource; 68 69 // the permission to access resources in the runtime image, created lazily 70 private static volatile Permission permission; 71 72 JavaRuntimeURLConnection(URL url) throws IOException { 73 super(url); 74 String path = url.getPath(); 75 if (path.length() == 0 || path.charAt(0) != '/') 76 throw new MalformedURLException(url + " missing path or /"); 77 if (path.length() == 1) { 78 this.module = null; 79 this.name = null; 80 } else { 81 int pos = path.indexOf('/', 1); 82 if (pos == -1) { 83 this.module = path.substring(1); 84 this.name = null; 85 } else { 86 this.module = path.substring(1, pos); 87 this.name = ParseUtil.decode(path.substring(pos+1)); 88 } 89 } 90 } 91 92 /** 93 * Finds a resource in a module, returning {@code null} if the resource 94 * is not found. 95 */ 96 private static Resource findResource(String module, String name) { 97 if (reader != null) { 98 URL url = toJrtURL(module, name); 99 ImageLocation location = reader.findLocation(module, name); 100 if (location != null && URLClassPath.checkURL(url) != null) { 101 return new Resource() { 102 @Override 103 public String getName() { 104 return name; 105 } 106 @Override 107 public URL getURL() { 108 return url; 109 } 110 @Override 111 public URL getCodeSourceURL() { 112 return toJrtURL(module); 113 } 114 @Override 115 public InputStream getInputStream() throws IOException { 116 byte[] resource = reader.getResource(location); 117 return new ByteArrayInputStream(resource); 118 } 119 @Override 120 public int getContentLength() { 121 long size = location.getUncompressedSize(); 122 return (size > Integer.MAX_VALUE) ? -1 : (int) size; 123 } 124 }; 125 } 126 } 127 return null; 128 } 129 130 @Override 131 public synchronized void connect() throws IOException { 132 if (!connected) { 133 if (name == null) { 134 String s = (module == null) ? "" : module; 135 throw new IOException("cannot connect to jrt:/" + s); 136 } 137 resource = findResource(module, name); 138 if (resource == null) 139 throw new IOException(module + "/" + name + " not found"); 140 connected = true; 141 } 142 } 143 144 @Override 145 public InputStream getInputStream() throws IOException { 146 connect(); 147 return resource.getInputStream(); 148 } 149 150 @Override 151 public long getContentLengthLong() { 152 try { 153 connect(); 154 return resource.getContentLength(); 155 } catch (IOException ioe) { 156 return -1L; 157 } 158 } 159 160 @Override 161 public int getContentLength() { 162 long len = getContentLengthLong(); 163 return len > Integer.MAX_VALUE ? -1 : (int)len; 164 } 165 166 @Override 167 public Permission getPermission() throws IOException { 168 Permission p = permission; 169 if (p == null) { 170 String home = GetPropertyAction.privilegedGetProperty("java.home"); 171 p = new FilePermission(home + File.separator + "-", "read"); 172 permission = p; 173 } 174 return p; 175 } 176 177 /** 178 * Returns a jrt URL for the given module and resource name. 179 */ 180 private static URL toJrtURL(String module, String name) { 181 try { 182 return new URL("jrt:/" + module + "/" + name); 183 } catch (MalformedURLException e) { 184 throw new InternalError(e); 185 } 186 } 187 188 /** 189 * Returns a jrt URL for the given module. 190 */ 191 private static URL toJrtURL(String module) { 192 try { 193 return new URL("jrt:/" + module); 194 } catch (MalformedURLException e) { 195 throw new InternalError(e); 196 } 197 } 198 }