1 /* 2 * Copyright (c) 1997, 2013, 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 java.net; 27 28 import java.io.IOException; 29 import java.util.jar.JarFile; 30 import java.util.jar.JarEntry; 31 import java.util.jar.Attributes; 32 import java.util.jar.Manifest; 33 import java.security.Permission; 34 import sun.net.www.ParseUtil; 35 36 /** 37 * A URL Connection to a Java ARchive (JAR) file or an entry in a JAR 38 * file. 39 * 40 * <p>The syntax of a JAR URL is: 41 * 42 * <pre> 43 * jar:<url>!/{entry} 44 * </pre> 45 * 46 * <p>for example: 47 * 48 * <p>{@code jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class} 49 * 50 * <p>Jar URLs should be used to refer to a JAR file or entries in 51 * a JAR file. The example above is a JAR URL which refers to a JAR 52 * entry. If the entry name is omitted, the URL refers to the whole 53 * JAR file: 54 * 55 * {@code jar:http://www.foo.com/bar/baz.jar!/} 56 * 57 * <p>Users should cast the generic URLConnection to a 58 * JarURLConnection when they know that the URL they created is a JAR 59 * URL, and they need JAR-specific functionality. For example: 60 * 61 * <pre> 62 * URL url = new URL("jar:file:/home/duke/duke.jar!/"); 63 * JarURLConnection jarConnection = (JarURLConnection)url.openConnection(); 64 * Manifest manifest = jarConnection.getManifest(); 65 * </pre> 66 * 67 * <p>JarURLConnection instances can only be used to read from JAR files. 68 * It is not possible to get a {@link java.io.OutputStream} to modify or write 69 * to the underlying JAR file using this class. 70 * <p>Examples: 71 * 72 * <dl> 73 * 74 * <dt>A Jar entry 75 * <dd>{@code jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class} 76 * 77 * <dt>A Jar file 78 * <dd>{@code jar:http://www.foo.com/bar/baz.jar!/} 79 * 80 * <dt>A Jar directory 81 * <dd>{@code jar:http://www.foo.com/bar/baz.jar!/COM/foo/} 82 * 83 * </dl> 84 * 85 * <p>{@code !/} is referred to as the <em>separator</em>. 86 * 87 * <p>When constructing a JAR url via {@code new URL(context, spec)}, 88 * the following rules apply: 89 * 90 * <ul> 91 * 92 * <li>if there is no context URL and the specification passed to the 93 * URL constructor doesn't contain a separator, the URL is considered 94 * to refer to a JarFile. 95 * 96 * <li>if there is a context URL, the context URL is assumed to refer 97 * to a JAR file or a Jar directory. 98 * 99 * <li>if the specification begins with a '/', the Jar directory is 100 * ignored, and the spec is considered to be at the root of the Jar 101 * file. 102 * 103 * <p>Examples: 104 * 105 * <dl> 106 * 107 * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/</b>, 108 * spec:<b>baz/entry.txt</b> 109 * 110 * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/baz/entry.txt</b> 111 * 112 * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/baz</b>, 113 * spec:<b>entry.txt</b> 114 * 115 * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/baz/entry.txt</b> 116 * 117 * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/baz</b>, 118 * spec:<b>/entry.txt</b> 119 * 120 * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/entry.txt</b> 121 * 122 * </dl> 123 * 124 * </ul> 125 * 126 * @see java.net.URL 127 * @see java.net.URLConnection 128 * 129 * @see java.util.jar.JarFile 130 * @see java.util.jar.JarInputStream 131 * @see java.util.jar.Manifest 132 * @see java.util.zip.ZipEntry 133 * 134 * @author Benjamin Renaud 135 * @since 1.2 136 */ 137 public abstract class JarURLConnection extends URLConnection { 138 139 private URL jarFileURL; 140 private String entryName; 141 142 /** 143 * The connection to the JAR file URL, if the connection has been 144 * initiated. This should be set by connect. 145 */ 146 protected URLConnection jarFileURLConnection; 147 148 /** 149 * Creates the new JarURLConnection to the specified URL. 150 * @param url the URL 151 * @throws MalformedURLException if no legal protocol 152 * could be found in a specification string or the 153 * string could not be parsed. 154 */ 155 JarURLConnection(URL url)156 protected JarURLConnection(URL url) throws MalformedURLException { 157 super(url); 158 parseSpecs(url); 159 } 160 161 /* get the specs for a given url out of the cache, and compute and 162 * cache them if they're not there. 163 */ parseSpecs(URL url)164 private void parseSpecs(URL url) throws MalformedURLException { 165 String spec = url.getFile(); 166 167 int separator = spec.indexOf("!/"); 168 /* 169 * REMIND: we don't handle nested JAR URLs 170 */ 171 if (separator == -1) { 172 throw new MalformedURLException("no !/ found in url spec:" + spec); 173 } 174 175 jarFileURL = new URL(spec.substring(0, separator++)); 176 entryName = null; 177 178 /* if ! is the last letter of the innerURL, entryName is null */ 179 if (++separator != spec.length()) { 180 entryName = spec.substring(separator, spec.length()); 181 entryName = ParseUtil.decode (entryName); 182 } 183 } 184 185 /** 186 * Returns the URL for the Jar file for this connection. 187 * 188 * @return the URL for the Jar file for this connection. 189 */ getJarFileURL()190 public URL getJarFileURL() { 191 return jarFileURL; 192 } 193 194 /** 195 * Return the entry name for this connection. This method 196 * returns null if the JAR file URL corresponding to this 197 * connection points to a JAR file and not a JAR file entry. 198 * 199 * @return the entry name for this connection, if any. 200 */ getEntryName()201 public String getEntryName() { 202 return entryName; 203 } 204 205 /** 206 * Return the JAR file for this connection. 207 * 208 * @return the JAR file for this connection. If the connection is 209 * a connection to an entry of a JAR file, the JAR file object is 210 * returned 211 * 212 * @exception IOException if an IOException occurs while trying to 213 * connect to the JAR file for this connection. 214 * 215 * @see #connect 216 */ getJarFile()217 public abstract JarFile getJarFile() throws IOException; 218 219 /** 220 * Returns the Manifest for this connection, or null if none. 221 * 222 * @return the manifest object corresponding to the JAR file object 223 * for this connection. 224 * 225 * @exception IOException if getting the JAR file for this 226 * connection causes an IOException to be thrown. 227 * 228 * @see #getJarFile 229 */ getManifest()230 public Manifest getManifest() throws IOException { 231 return getJarFile().getManifest(); 232 } 233 234 /** 235 * Return the JAR entry object for this connection, if any. This 236 * method returns null if the JAR file URL corresponding to this 237 * connection points to a JAR file and not a JAR file entry. 238 * 239 * @return the JAR entry object for this connection, or null if 240 * the JAR URL for this connection points to a JAR file. 241 * 242 * @exception IOException if getting the JAR file for this 243 * connection causes an IOException to be thrown. 244 * 245 * @see #getJarFile 246 * @see #getJarEntry 247 */ getJarEntry()248 public JarEntry getJarEntry() throws IOException { 249 return getJarFile().getJarEntry(entryName); 250 } 251 252 /** 253 * Return the Attributes object for this connection if the URL 254 * for it points to a JAR file entry, null otherwise. 255 * 256 * @return the Attributes object for this connection if the URL 257 * for it points to a JAR file entry, null otherwise. 258 * 259 * @exception IOException if getting the JAR entry causes an 260 * IOException to be thrown. 261 * 262 * @see #getJarEntry 263 */ getAttributes()264 public Attributes getAttributes() throws IOException { 265 JarEntry e = getJarEntry(); 266 return e != null ? e.getAttributes() : null; 267 } 268 269 /** 270 * Returns the main Attributes for the JAR file for this 271 * connection. 272 * 273 * @return the main Attributes for the JAR file for this 274 * connection. 275 * 276 * @exception IOException if getting the manifest causes an 277 * IOException to be thrown. 278 * 279 * @see #getJarFile 280 * @see #getManifest 281 */ getMainAttributes()282 public Attributes getMainAttributes() throws IOException { 283 Manifest man = getManifest(); 284 return man != null ? man.getMainAttributes() : null; 285 } 286 287 /** 288 * Return the Certificate object for this connection if the URL 289 * for it points to a JAR file entry, null otherwise. This method 290 * can only be called once 291 * the connection has been completely verified by reading 292 * from the input stream until the end of the stream has been 293 * reached. Otherwise, this method will return {@code null} 294 * 295 * @return the Certificate object for this connection if the URL 296 * for it points to a JAR file entry, null otherwise. 297 * 298 * @exception IOException if getting the JAR entry causes an 299 * IOException to be thrown. 300 * 301 * @see #getJarEntry 302 */ getCertificates()303 public java.security.cert.Certificate[] getCertificates() 304 throws IOException 305 { 306 JarEntry e = getJarEntry(); 307 return e != null ? e.getCertificates() : null; 308 } 309 } 310