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 18 package javax.servlet.http; 19 20 import javax.servlet.ServletInputStream; 21 import java.util.Hashtable; 22 import java.util.ResourceBundle; 23 import java.util.StringTokenizer; 24 import java.io.IOException; 25 26 /** 27 * @deprecated As of Java(tm) Servlet API 2.3. 28 * These methods were only useful 29 * with the default encoding and have been moved 30 * to the request interfaces. 31 * 32 */ 33 34 35 public class HttpUtils { 36 37 private static final String LSTRING_FILE = 38 "javax.servlet.http.LocalStrings"; 39 private static ResourceBundle lStrings = 40 ResourceBundle.getBundle(LSTRING_FILE); 41 42 43 44 /** 45 * Constructs an empty <code>HttpUtils</code> object. 46 * 47 */ 48 49 public HttpUtils() {} 50 51 52 53 54 55 /** 56 * 57 * Parses a query string passed from the client to the 58 * server and builds a <code>HashTable</code> object 59 * with key-value pairs. 60 * The query string should be in the form of a string 61 * packaged by the GET or POST method, that is, it 62 * should have key-value pairs in the form <i>key=value</i>, 63 * with each pair separated from the next by a & character. 64 * 65 * <p>A key can appear more than once in the query string 66 * with different values. However, the key appears only once in 67 * the hashtable, with its value being 68 * an array of strings containing the multiple values sent 69 * by the query string. 70 * 71 * <p>The keys and values in the hashtable are stored in their 72 * decoded form, so 73 * any + characters are converted to spaces, and characters 74 * sent in hexadecimal notation (like <i>%xx</i>) are 75 * converted to ASCII characters. 76 * 77 * @param s a string containing the query to be parsed 78 * 79 * @return a <code>HashTable</code> object built 80 * from the parsed key-value pairs 81 * 82 * @exception IllegalArgumentException if the query string 83 * is invalid 84 * 85 */ 86 87 static public Hashtable parseQueryString(String s) { 88 89 String valArray[] = null; 90 91 if (s == null) { 92 throw new IllegalArgumentException(); 93 } 94 Hashtable ht = new Hashtable(); 95 StringBuffer sb = new StringBuffer(); 96 StringTokenizer st = new StringTokenizer(s, "&"); 97 while (st.hasMoreTokens()) { 98 String pair = (String)st.nextToken(); 99 int pos = pair.indexOf('='); 100 if (pos == -1) { 101 // XXX 102 // should give more detail about the illegal argument 103 throw new IllegalArgumentException(); 104 } 105 String key = parseName(pair.substring(0, pos), sb); 106 String val = parseName(pair.substring(pos+1, pair.length()), sb); 107 if (ht.containsKey(key)) { 108 String oldVals[] = (String []) ht.get(key); 109 valArray = new String[oldVals.length + 1]; 110 for (int i = 0; i < oldVals.length; i++) 111 valArray[i] = oldVals[i]; 112 valArray[oldVals.length] = val; 113 } else { 114 valArray = new String[1]; 115 valArray[0] = val; 116 } 117 ht.put(key, valArray); 118 } 119 return ht; 120 } 121 122 123 124 125 /** 126 * 127 * Parses data from an HTML form that the client sends to 128 * the server using the HTTP POST method and the 129 * <i>application/x-www-form-urlencoded</i> MIME type. 130 * 131 * <p>The data sent by the POST method contains key-value 132 * pairs. A key can appear more than once in the POST data 133 * with different values. However, the key appears only once in 134 * the hashtable, with its value being 135 * an array of strings containing the multiple values sent 136 * by the POST method. 137 * 138 * <p>The keys and values in the hashtable are stored in their 139 * decoded form, so 140 * any + characters are converted to spaces, and characters 141 * sent in hexadecimal notation (like <i>%xx</i>) are 142 * converted to ASCII characters. 143 * 144 * 145 * 146 * @param len an integer specifying the length, 147 * in characters, of the 148 * <code>ServletInputStream</code> 149 * object that is also passed to this 150 * method 151 * 152 * @param in the <code>ServletInputStream</code> 153 * object that contains the data sent 154 * from the client 155 * 156 * @return a <code>HashTable</code> object built 157 * from the parsed key-value pairs 158 * 159 * 160 * @exception IllegalArgumentException if the data 161 * sent by the POST method is invalid 162 * 163 */ 164 165 166 static public Hashtable parsePostData(int len, 167 ServletInputStream in) 168 { 169 // XXX 170 // should a length of 0 be an IllegalArgumentException 171 172 if (len <=0) 173 return new Hashtable(); // cheap hack to return an empty hash 174 175 if (in == null) { 176 throw new IllegalArgumentException(); 177 } 178 179 // 180 // Make sure we read the entire POSTed body. 181 // 182 byte[] postedBytes = new byte [len]; 183 try { 184 int offset = 0; 185 186 do { 187 int inputLen = in.read (postedBytes, offset, len - offset); 188 if (inputLen <= 0) { 189 String msg = lStrings.getString("err.io.short_read"); 190 throw new IllegalArgumentException (msg); 191 } 192 offset += inputLen; 193 } while ((len - offset) > 0); 194 195 } catch (IOException e) { 196 throw new IllegalArgumentException(e.getMessage()); 197 } 198 199 // XXX we shouldn't assume that the only kind of POST body 200 // is FORM data encoded using ASCII or ISO Latin/1 ... or 201 // that the body should always be treated as FORM data. 202 // 203 204 try { 205 String postedBody = new String(postedBytes, 0, len, "8859_1"); 206 return parseQueryString(postedBody); 207 } catch (java.io.UnsupportedEncodingException e) { 208 // XXX function should accept an encoding parameter & throw this 209 // exception. Otherwise throw something expected. 210 throw new IllegalArgumentException(e.getMessage()); 211 } 212 } 213 214 215 216 217 /* 218 * Parse a name in the query string. 219 */ 220 221 static private String parseName(String s, StringBuffer sb) { 222 sb.setLength(0); 223 for (int i = 0; i < s.length(); i++) { 224 char c = s.charAt(i); 225 switch (c) { 226 case '+': 227 sb.append(' '); 228 break; 229 case '%': 230 try { 231 sb.append((char) Integer.parseInt(s.substring(i+1, i+3), 232 16)); 233 i += 2; 234 } catch (NumberFormatException e) { 235 // XXX 236 // need to be more specific about illegal arg 237 throw new IllegalArgumentException(); 238 } catch (StringIndexOutOfBoundsException e) { 239 String rest = s.substring(i); 240 sb.append(rest); 241 if (rest.length()==2) 242 i++; 243 } 244 245 break; 246 default: 247 sb.append(c); 248 break; 249 } 250 } 251 return sb.toString(); 252 } 253 254 255 256 257 /** 258 * 259 * Reconstructs the URL the client used to make the request, 260 * using information in the <code>HttpServletRequest</code> object. 261 * The returned URL contains a protocol, server name, port 262 * number, and server path, but it does not include query 263 * string parameters. 264 * 265 * <p>Because this method returns a <code>StringBuffer</code>, 266 * not a string, you can modify the URL easily, for example, 267 * to append query parameters. 268 * 269 * <p>This method is useful for creating redirect messages 270 * and for reporting errors. 271 * 272 * @param req a <code>HttpServletRequest</code> object 273 * containing the client's request 274 * 275 * @return a <code>StringBuffer</code> object containing 276 * the reconstructed URL 277 * 278 */ 279 280 public static StringBuffer getRequestURL (HttpServletRequest req) { 281 StringBuffer url = new StringBuffer (); 282 String scheme = req.getScheme (); 283 int port = req.getServerPort (); 284 String urlPath = req.getRequestURI(); 285 286 //String servletPath = req.getServletPath (); 287 //String pathInfo = req.getPathInfo (); 288 289 url.append (scheme); // http, https 290 url.append ("://"); 291 url.append (req.getServerName ()); 292 if ((scheme.equals ("http") && port != 80) 293 || (scheme.equals ("https") && port != 443)) { 294 url.append (':'); 295 url.append (req.getServerPort ()); 296 } 297 //if (servletPath != null) 298 // url.append (servletPath); 299 //if (pathInfo != null) 300 // url.append (pathInfo); 301 url.append(urlPath); 302 return url; 303 } 304 } 305 306 307