1 /* 2 * $Id$ 3 * 4 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Oracle designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Oracle in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 24 * or visit www.oracle.com if you need additional information or have any 25 * questions. 26 */ 27 package com.sun.javatest.httpd; 28 29 import java.util.Dictionary; 30 import java.util.Properties; 31 32 /** 33 * URL object including support for key-value pairs. 34 */ 35 36 public class httpURL { 37 public httpURL(String url) { 38 firstQ = url.indexOf('?'); 39 file = url; 40 fileLen = file.length(); 41 42 resetIterator(); 43 44 if (firstQ != -1) { 45 parseURLKeys(); 46 } 47 } 48 49 /** 50 * Get the next part of the requested path. This is an iterator. 51 * Ex: from /harness/foo/, it may return "harness" or "foo". 52 * 53 * @return null if the end of the file path has been reached 54 */ 55 public String getNextFile() { 56 // XXX 4 May 2000 rewrite this method so it is not so complex! 57 if (pathPos == fileLen) return null; 58 59 String ss; // the substring of the whole file name 60 if (pathPos == fileLen - 1) { // * special cases 61 if (fileLen == 1 && file.charAt(0) == '/') { // should only happen when full URL is "/" 62 ss = "/"; 63 pathPos = fileLen; 64 } 65 else { 66 ss = file.substring(pathPos, fileLen); 67 pathPos = fileLen; 68 } 69 } 70 else { // * normal cases 71 int nextPos = file.indexOf('/', pathPos+1); 72 73 if (nextPos == -1) { 74 // give the remainder of the string up to: 75 // 1) the first question mark ahead 76 // 2) the end of the string 77 String result = file.substring(pathPos, (firstQ == -1 ? fileLen : firstQ)); 78 pathPos = fileLen; 79 ss = result; 80 } 81 else { 82 ss = file.substring(pathPos, nextPos); 83 pathPos = nextPos + 1; 84 } 85 } 86 87 //System.out.println("next file is: " + ss); 88 return ss; 89 } 90 91 public void resetIterator() { 92 // if the URL is only a slash, we let that through 93 // otherwise we ignore the leading slash 94 // this allows the web server root page to work, eg. http://foo:1903/ 95 if (file.indexOf('/') == 0 && fileLen > 1) 96 pathPos = 1; 97 else 98 pathPos = 0; 99 } 100 101 /** 102 * Returns the URL, minus the protocol, hostname and port. 103 */ 104 public String getFullPath() { 105 return file; 106 } 107 108 /** 109 * Get the host portion of the URL. 110 * 111 * @throws Fault This info is not always available, so this exception may 112 * be thrown. 113 */ 114 public String getLocalHost() throws Fault { 115 if (lHost == null) 116 throw new Fault("Local hostname for URL not available"); 117 else 118 return lHost; 119 } 120 121 /** 122 * Get the local hostname portion of the URL. 123 * 124 * @throws Fault This info is not always available, so this exception may 125 * be thrown. 126 */ 127 public int getLocalPort() throws Fault { 128 if (lPort == -1) 129 throw new Fault("Local port for URL not available"); 130 else 131 return lPort; 132 } 133 134 /** 135 * Get the remote hostname. Fully resolved host names are not required. 136 * 137 * @throws Fault This info is not always available, so this exception may 138 * be thrown. 139 */ 140 public String getRemoteHost() throws Fault { 141 if (rHost == null) 142 throw new Fault("Remote hostname for URL not available"); 143 else 144 return rHost; 145 } 146 147 // ------- Key-Value Processing --------- 148 /** 149 * Set the key-value pairs encoded in this URL. 150 * Not implemented yet. 151 */ 152 public void setProperties(Dictionary<String, String> props) { 153 } 154 155 /** 156 * Not implemented yet. 157 */ 158 public String[] getKeys() { 159 return null; 160 } 161 162 /** 163 * Not implemented yet. 164 */ 165 public String[] getValues() { 166 return null; 167 } 168 169 /** 170 * Not implemented yet. 171 */ 172 public String getValue(String key) { 173 return urlValues.getProperty(key); 174 } 175 176 // ----------- Utility ----------- 177 /** 178 * Assembles a slash separated path from the elements of the given array. 179 * Null entries in the array are ignored. 180 * 181 * @param path An empty or null array results in a zero length string. 182 * @param leadingSlash Whether or not to put a slash at the beginning of the path 183 * @param trailSlash Whether or not to put a slash at the end of the path 184 */ 185 public static String reassemblePath(String[] path, boolean leadingSlash, 186 boolean trailSlash) { 187 if (path == null || path.length == 0) 188 return ""; 189 190 StringBuffer result = new StringBuffer(); 191 192 if (leadingSlash) result.append("/"); 193 194 for (int i = 0; i < path.length; i++) { 195 if (path[i] != null) { 196 result.append(path[i]); 197 result.append("/"); 198 } 199 } // for 200 201 // remove trailing slash if needed 202 if (!trailSlash && result.length() > 1) result.setLength(result.length()-1); 203 204 return result.toString(); 205 } 206 207 // ----------- NON-PUBLIC ------------ 208 209 void setRemoteHost(String name) { 210 rHost = name; 211 } 212 213 void setLocalHost(String name) { 214 lHost = name; 215 } 216 217 void setLocalPort(int port) { 218 lPort = port; 219 } 220 221 private void parseURLKeys() { 222 String data = file.substring(firstQ + 1, fileLen); 223 224 if (data.length() == 0) return; 225 226 String key = null; 227 int pos = 0; 228 int dataLen = data.length(); // optimization 229 230 while ((key = readSegment(data, pos, dataLen)) != null) { 231 pos = pos + key.length(); 232 if (debug) System.out.println(" Read key: " + key); 233 234 if (pos >= dataLen || data.charAt(pos) == '&') { 235 // there is no value with this key 236 if (debug) System.out.println("key: " + key + " value: null"); 237 urlValues.put(key, "true"); 238 } 239 else { 240 // char at pos must be '=' 241 String val = readSegment(data, ++pos, dataLen); 242 if (debug) System.out.println("key: " + key + " value: " + val); 243 urlValues.put(key, val); 244 245 // assume that the resulting value will either jump over 246 // the & or put us past the end of the string 247 // http://machine1:1904/version?apple=orange&grape=apricot 248 // ^ 249 // pos 250 pos = pos + val.length() + 1; 251 252 // end of data string 253 if (pos > dataLen) break; 254 } 255 } // while 256 } 257 258 private String readSegment(String data, int position, int dataLen) { 259 StringBuffer buf = new StringBuffer(); 260 int i = position; 261 262 // loop until you hit end of string, a & or a = 263 while (i < dataLen && data.charAt(i) != '&' && 264 data.charAt(i) != '=') { 265 buf.append(data.charAt(i)); 266 i++; 267 } // while 268 269 // a zero length string is not acceptable 270 return (buf.length() == 0 ? null : buf.toString()); 271 } 272 273 private String lHost; 274 private int lPort = -1; 275 private String rHost; 276 private int pathPos; 277 private int firstQ; // location of the first question mark in the file path 278 protected static final boolean debug = Boolean.getBoolean("debug." + httpURL.class.getName()); 279 280 /** 281 * The URL, of the format: 282 * <tt>/harness/foo/index.html?key1=value1?key2=value2</tt> 283 */ 284 private String file; 285 286 /** 287 * The length of the file string. Used often. 288 */ 289 private int fileLen; 290 291 /** 292 * Any key-values encoded in the URL string. 293 */ 294 private Properties urlValues = new Properties(); 295 296 public static class Fault extends Exception { 297 public Fault(String s) { 298 super(s); 299 } 300 301 /** 302 * Provide description and pass-thru exception 303 */ 304 public Fault(String s, Throwable e) { 305 super(s); 306 } 307 308 /** 309 * Get the original exception. 310 */ 311 public Throwable getException() { 312 return orig; 313 } 314 315 private Throwable orig; 316 } 317 } 318