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 126 @SuppressWarnings("deprecation") parseURL(URL url, String spec, int start, int limit)127 protected void parseURL(URL url, String spec, 128 int start, int limit) { 129 String file = null; 130 String ref = null; 131 // first figure out if there is an anchor 132 int refPos = spec.indexOf('#', limit); 133 boolean refOnly = refPos == start; 134 if (refPos > -1) { 135 ref = spec.substring(refPos + 1, spec.length()); 136 if (refOnly) { 137 file = url.getFile(); 138 } 139 } 140 // then figure out if the spec is 141 // 1. absolute (jar:) 142 // 2. relative (i.e. url + foo/bar/baz.ext) 143 // 3. anchor-only (i.e. url + #foo), which we already did (refOnly) 144 boolean absoluteSpec = false; 145 if (spec.length() >= 4) { 146 absoluteSpec = spec.substring(0, 4).equalsIgnoreCase("jar:"); 147 } 148 spec = spec.substring(start, limit); 149 150 if (absoluteSpec) { 151 file = parseAbsoluteSpec(spec); 152 } else if (!refOnly) { 153 file = parseContextSpec(url, spec); 154 155 // Canonize the result after the bangslash 156 int bangSlash = indexOfBangSlash(file); 157 String toBangSlash = file.substring(0, bangSlash); 158 String afterBangSlash = file.substring(bangSlash); 159 sun.net.www.ParseUtil canonizer = new ParseUtil(); 160 afterBangSlash = canonizer.canonizeString(afterBangSlash); 161 file = toBangSlash + afterBangSlash; 162 } 163 setURL(url, "jar", "", -1, file, ref); 164 } 165 parseAbsoluteSpec(String spec)166 private String parseAbsoluteSpec(String spec) { 167 URL url = null; 168 int index = -1; 169 // check for !/ 170 if ((index = indexOfBangSlash(spec)) == -1) { 171 throw new NullPointerException("no !/ in spec"); 172 } 173 // test the inner URL 174 try { 175 String innerSpec = spec.substring(0, index - 1); 176 url = new URL(innerSpec); 177 } catch (MalformedURLException e) { 178 throw new NullPointerException("invalid url: " + 179 spec + " (" + e + ")"); 180 } 181 return spec; 182 } 183 parseContextSpec(URL url, String spec)184 private String parseContextSpec(URL url, String spec) { 185 String ctxFile = url.getFile(); 186 // if the spec begins with /, chop up the jar back !/ 187 if (spec.startsWith("/")) { 188 int bangSlash = indexOfBangSlash(ctxFile); 189 if (bangSlash == -1) { 190 throw new NullPointerException("malformed " + 191 "context url:" + 192 url + 193 ": no !/"); 194 } 195 ctxFile = ctxFile.substring(0, bangSlash); 196 } 197 if (!ctxFile.endsWith("/") && (!spec.startsWith("/"))){ 198 // chop up the last component 199 int lastSlash = ctxFile.lastIndexOf('/'); 200 if (lastSlash == -1) { 201 throw new NullPointerException("malformed " + 202 "context url:" + 203 url); 204 } 205 ctxFile = ctxFile.substring(0, lastSlash + 1); 206 } 207 return (ctxFile + spec); 208 } 209 } 210