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