1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.net; 19 20import java.io.IOException; 21import java.nio.charset.StandardCharsets; 22import java.security.cert.Certificate; 23import java.util.jar.Attributes; 24import java.util.jar.JarEntry; 25import java.util.jar.JarFile; 26import java.util.jar.Manifest; 27import libcore.net.UriCodec; 28 29/** 30 * This class establishes a connection to a {@code jar:} URL using the {@code 31 * JAR} protocol. A {@code JarURLConnection} instance can refer to either a JAR 32 * archive file or to an entry of such a file. {@code jar:} URLs are specified 33 * as follows: <i>jar:{archive-url}!/{entry}</i> where "!/" is called a 34 * separator. This separator is important to determine if an archive or an entry 35 * of an archive is referred. 36 * <p> 37 * Examples: 38 * <li>Archive: {@code jar:http://www.example.com/applets/archive.jar!/}</li> 39 * <li>File Entry: {@code 40 * jar:http://www.example.com/applets/archive.jar!/test.class}</li> 41 * <li>Directory Entry: {@code 42 * jar:http://www.example.com/applets/archive.jar!/applets/}</li> 43 */ 44public abstract class JarURLConnection extends URLConnection { 45 46 /** 47 * The location part of the represented URL. 48 */ 49 protected URLConnection jarFileURLConnection; 50 51 private String entryName; 52 53 private URL fileURL; 54 55 // the file component of the URL 56 private String file; 57 58 /** 59 * Constructs an instance of {@code JarURLConnection} that refers to the 60 * specified URL. 61 * 62 * @param url 63 * the URL that contains the location to connect to. 64 * @throws MalformedURLException 65 * if an invalid URL has been entered. 66 */ 67 protected JarURLConnection(URL url) throws MalformedURLException { 68 super(url); 69 file = decode(url.getFile()); 70 71 int sepIdx; 72 if ((sepIdx = file.indexOf("!/")) < 0) { 73 throw new MalformedURLException(); 74 } 75 fileURL = new URL(file.substring(0, sepIdx)); 76 sepIdx += 2; 77 if (file.length() == sepIdx) { 78 return; 79 } 80 entryName = file.substring(sepIdx, file.length()); 81 if (url.getRef() != null) { 82 entryName += "#" + url.getRef(); 83 } 84 } 85 86 /** 87 * Returns all attributes of the {@code JarEntry} referenced by this {@code 88 * JarURLConnection}. 89 * 90 * @return the attributes of the referenced {@code JarEntry}. 91 * @throws IOException 92 * if an I/O exception occurs while retrieving the 93 * JAR-entries. 94 */ 95 public Attributes getAttributes() throws java.io.IOException { 96 JarEntry jEntry = getJarEntry(); 97 return (jEntry == null) ? null : jEntry.getAttributes(); 98 } 99 100 /** 101 * Returns all certificates of the {@code JarEntry} referenced by this 102 * {@code JarURLConnection} instance. This method will return {@code null} 103 * until the {@code InputStream} has been completely verified. 104 * 105 * @return the certificates of the {@code JarEntry} as an array. 106 * @throws IOException 107 * if there is an I/O exception occurs while getting the 108 * {@code JarEntry}. 109 */ 110 public Certificate[] getCertificates() throws java.io.IOException { 111 JarEntry jEntry = getJarEntry(); 112 if (jEntry == null) { 113 return null; 114 } 115 116 return jEntry.getCertificates(); 117 } 118 119 /** 120 * Gets the name of the entry referenced by this {@code JarURLConnection}. 121 * The return value will be {@code null} if this instance refers to a JAR 122 * file rather than an JAR file entry. 123 * 124 * @return the {@code JarEntry} name this instance refers to. 125 */ 126 public String getEntryName() { 127 return entryName; 128 } 129 130 /** 131 * Gets the {@code JarEntry} object of the entry referenced by this {@code 132 * JarURLConnection}. 133 * 134 * @return the referenced {@code JarEntry} object or {@code null} if no 135 * entry name is specified. 136 * @throws IOException 137 * if an error occurs while getting the file or file-entry. 138 */ 139 public JarEntry getJarEntry() throws IOException { 140 if (!connected) { 141 connect(); 142 } 143 if (entryName == null) { 144 return null; 145 } 146 // The entry must exist since the connect succeeded 147 return getJarFile().getJarEntry(entryName); 148 } 149 150 /** 151 * Gets the manifest file associated with this JAR-URL. 152 * 153 * @return the manifest of the referenced JAR-file. 154 * @throws IOException 155 * if an error occurs while getting the manifest file. 156 */ 157 public Manifest getManifest() throws java.io.IOException { 158 return (Manifest)getJarFile().getManifest().clone(); 159 } 160 161 /** 162 * Gets the {@code JarFile} object referenced by this {@code 163 * JarURLConnection}. 164 * 165 * @return the referenced JarFile object. 166 * @throws IOException 167 * if an I/O exception occurs while retrieving the JAR-file. 168 */ 169 public abstract JarFile getJarFile() throws java.io.IOException; 170 171 /** 172 * Gets the URL to the JAR-file referenced by this {@code JarURLConnection}. 173 * 174 * @return the URL to the JAR-file or {@code null} if there was an error 175 * retrieving the URL. 176 */ 177 public URL getJarFileURL() { 178 return fileURL; 179 } 180 181 /** 182 * Gets all attributes of the manifest file referenced by this {@code 183 * JarURLConnection}. If this instance refers to a JAR-file rather than a 184 * JAR-file entry, {@code null} will be returned. 185 * 186 * @return the attributes of the manifest file or {@code null}. 187 * @throws IOException 188 * if an I/O exception occurs while retrieving the {@code 189 * JarFile}. 190 */ 191 public Attributes getMainAttributes() throws java.io.IOException { 192 Manifest m = getJarFile().getManifest(); 193 return (m == null) ? null : m.getMainAttributes(); 194 } 195 196 private static String decode(String encoded) throws MalformedURLException { 197 try { 198 // "+" means "+" in URLs. i.e. like RFC 3986, not like 199 // MIME application/x-www-form-urlencoded 200 final boolean convertPlus = false; 201 return UriCodec.decode( 202 encoded, convertPlus, StandardCharsets.UTF_8, true /* throwOnFailure */); 203 } catch (IllegalArgumentException e) { 204 throw new MalformedURLException("Unable to decode URL", e); 205 } 206 } 207 208} 209