1 /* 2 * Copyright (c) 1997, 2011, 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.jar; 27 28 import java.io.IOException; 29 import java.net.*; 30 import sun.net.www.ParseUtil; 31 32 /* 33 * Jar URL Handler 34 */ 35 public class Handler extends java.net.URLStreamHandler { 36 37 private static final String separator = "!/"; 38 openConnection(URL u)39 protected java.net.URLConnection openConnection(URL u) 40 throws IOException { 41 return new JarURLConnection(u, this); 42 } 43 indexOfBangSlash(String spec)44 private static int indexOfBangSlash(String spec) { 45 int indexOfBang = spec.length(); 46 while((indexOfBang = spec.lastIndexOf('!', indexOfBang)) != -1) { 47 if ((indexOfBang != (spec.length() - 1)) && 48 (spec.charAt(indexOfBang + 1) == '/')) { 49 return indexOfBang + 1; 50 } else { 51 indexOfBang--; 52 } 53 } 54 return -1; 55 } 56 57 /** 58 * Compare two jar URLs 59 */ 60 @Override sameFile(URL u1, URL u2)61 protected boolean sameFile(URL u1, URL u2) { 62 if (!u1.getProtocol().equals("jar") || !u2.getProtocol().equals("jar")) 63 return false; 64 65 String file1 = u1.getFile(); 66 String file2 = u2.getFile(); 67 int sep1 = file1.indexOf(separator); 68 int sep2 = file2.indexOf(separator); 69 70 if (sep1 == -1 || sep2 == -1) { 71 return super.sameFile(u1, u2); 72 } 73 74 String entry1 = file1.substring(sep1 + 2); 75 String entry2 = file2.substring(sep2 + 2); 76 77 if (!entry1.equals(entry2)) 78 return false; 79 80 URL enclosedURL1 = null, enclosedURL2 = null; 81 try { 82 enclosedURL1 = new URL(file1.substring(0, sep1)); 83 enclosedURL2 = new URL(file2.substring(0, sep2)); 84 } catch (MalformedURLException unused) { 85 return super.sameFile(u1, u2); 86 } 87 88 if (!super.sameFile(enclosedURL1, enclosedURL2)) { 89 return false; 90 } 91 92 return true; 93 } 94 95 @Override hashCode(URL u)96 protected int hashCode(URL u) { 97 int h = 0; 98 99 String protocol = u.getProtocol(); 100 if (protocol != null) 101 h += protocol.hashCode(); 102 103 String file = u.getFile(); 104 int sep = file.indexOf(separator); 105 106 if (sep == -1) 107 return h + file.hashCode(); 108 109 URL enclosedURL = null; 110 String fileWithoutEntry = file.substring(0, sep); 111 try { 112 enclosedURL = new URL(fileWithoutEntry); 113 h += enclosedURL.hashCode(); 114 } catch (MalformedURLException unused) { 115 h += fileWithoutEntry.hashCode(); 116 } 117 118 String entry = file.substring(sep + 2); 119 h += entry.hashCode(); 120 121 return h; 122 } 123 124 125 @Override parseURL(URL url, String spec, int start, int limit)126 protected void parseURL(URL url, String spec, 127 int start, int limit) { 128 String file = null; 129 String ref = null; 130 // first figure out if there is an anchor 131 int refPos = spec.indexOf('#', limit); 132 boolean refOnly = refPos == start; 133 if (refPos > -1) { 134 ref = spec.substring(refPos + 1, spec.length()); 135 if (refOnly) { 136 file = url.getFile(); 137 } 138 } 139 // then figure out if the spec is 140 // 1. absolute (jar:) 141 // 2. relative (i.e. url + foo/bar/baz.ext) 142 // 3. anchor-only (i.e. url + #foo), which we already did (refOnly) 143 boolean absoluteSpec = false; 144 if (spec.length() >= 4) { 145 absoluteSpec = spec.substring(0, 4).equalsIgnoreCase("jar:"); 146 } 147 spec = spec.substring(start, limit); 148 149 if (absoluteSpec) { 150 file = parseAbsoluteSpec(spec); 151 } else if (!refOnly) { 152 file = parseContextSpec(url, spec); 153 154 // Canonize the result after the bangslash 155 int bangSlash = indexOfBangSlash(file); 156 String toBangSlash = file.substring(0, bangSlash); 157 String afterBangSlash = file.substring(bangSlash); 158 sun.net.www.ParseUtil canonizer = new ParseUtil(); 159 afterBangSlash = canonizer.canonizeString(afterBangSlash); 160 file = toBangSlash + afterBangSlash; 161 } 162 setURL(url, "jar", "", -1, file, ref); 163 } 164 parseAbsoluteSpec(String spec)165 private String parseAbsoluteSpec(String spec) { 166 URL url = null; 167 int index = -1; 168 // check for !/ 169 if ((index = indexOfBangSlash(spec)) == -1) { 170 throw new NullPointerException("no !/ in spec"); 171 } 172 // test the inner URL 173 try { 174 String innerSpec = spec.substring(0, index - 1); 175 url = new URL(innerSpec); 176 } catch (MalformedURLException e) { 177 throw new NullPointerException("invalid url: " + 178 spec + " (" + e + ")"); 179 } 180 return spec; 181 } 182 parseContextSpec(URL url, String spec)183 private String parseContextSpec(URL url, String spec) { 184 String ctxFile = url.getFile(); 185 // if the spec begins with /, chop up the jar back !/ 186 if (spec.startsWith("/")) { 187 int bangSlash = indexOfBangSlash(ctxFile); 188 if (bangSlash == -1) { 189 throw new NullPointerException("malformed " + 190 "context url:" + 191 url + 192 ": no !/"); 193 } 194 ctxFile = ctxFile.substring(0, bangSlash); 195 } 196 if (!ctxFile.endsWith("/") && (!spec.startsWith("/"))){ 197 // chop up the last component 198 int lastSlash = ctxFile.lastIndexOf('/'); 199 if (lastSlash == -1) { 200 throw new NullPointerException("malformed " + 201 "context url:" + 202 url); 203 } 204 ctxFile = ctxFile.substring(0, lastSlash + 1); 205 } 206 return (ctxFile + spec); 207 } 208 } 209