001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020 package javax.servlet.http; 021 022 import javax.servlet.ServletInputStream; 023 import java.util.Hashtable; 024 import java.util.ResourceBundle; 025 import java.util.StringTokenizer; 026 import java.io.IOException; 027 028 /** 029 * @deprecated As of Java(tm) Servlet API 2.3. 030 * These methods were only useful 031 * with the default encoding and have been moved 032 * to the request interfaces. 033 * 034 */ 035 036 037 public class HttpUtils { 038 039 private static final String LSTRING_FILE = 040 "javax.servlet.http.LocalStrings"; 041 private static ResourceBundle lStrings = 042 ResourceBundle.getBundle(LSTRING_FILE); 043 044 045 046 /** 047 * Constructs an empty <code>HttpUtils</code> object. 048 * 049 */ 050 051 public HttpUtils() {} 052 053 054 055 056 057 /** 058 * 059 * Parses a query string passed from the client to the 060 * server and builds a <code>HashTable</code> object 061 * with key-value pairs. 062 * The query string should be in the form of a string 063 * packaged by the GET or POST method, that is, it 064 * should have key-value pairs in the form <i>key=value</i>, 065 * with each pair separated from the next by a & character. 066 * 067 * <p>A key can appear more than once in the query string 068 * with different values. However, the key appears only once in 069 * the hashtable, with its value being 070 * an array of strings containing the multiple values sent 071 * by the query string. 072 * 073 * <p>The keys and values in the hashtable are stored in their 074 * decoded form, so 075 * any + characters are converted to spaces, and characters 076 * sent in hexadecimal notation (like <i>%xx</i>) are 077 * converted to ASCII characters. 078 * 079 * @param s a string containing the query to be parsed 080 * 081 * @return a <code>HashTable</code> object built 082 * from the parsed key-value pairs 083 * 084 * @exception IllegalArgumentException if the query string 085 * is invalid 086 * 087 */ 088 089 static public Hashtable parseQueryString(String s) { 090 091 String valArray[] = null; 092 093 if (s == null) { 094 throw new IllegalArgumentException(); 095 } 096 Hashtable ht = new Hashtable(); 097 StringBuffer sb = new StringBuffer(); 098 StringTokenizer st = new StringTokenizer(s, "&"); 099 while (st.hasMoreTokens()) { 100 String pair = (String)st.nextToken(); 101 int pos = pair.indexOf('='); 102 if (pos == -1) { 103 // XXX 104 // should give more detail about the illegal argument 105 throw new IllegalArgumentException(); 106 } 107 String key = parseName(pair.substring(0, pos), sb); 108 String val = parseName(pair.substring(pos+1, pair.length()), sb); 109 if (ht.containsKey(key)) { 110 String oldVals[] = (String []) ht.get(key); 111 valArray = new String[oldVals.length + 1]; 112 for (int i = 0; i < oldVals.length; i++) 113 valArray[i] = oldVals[i]; 114 valArray[oldVals.length] = val; 115 } else { 116 valArray = new String[1]; 117 valArray[0] = val; 118 } 119 ht.put(key, valArray); 120 } 121 return ht; 122 } 123 124 125 126 127 /** 128 * 129 * Parses data from an HTML form that the client sends to 130 * the server using the HTTP POST method and the 131 * <i>application/x-www-form-urlencoded</i> MIME type. 132 * 133 * <p>The data sent by the POST method contains key-value 134 * pairs. A key can appear more than once in the POST data 135 * with different values. However, the key appears only once in 136 * the hashtable, with its value being 137 * an array of strings containing the multiple values sent 138 * by the POST method. 139 * 140 * <p>The keys and values in the hashtable are stored in their 141 * decoded form, so 142 * any + characters are converted to spaces, and characters 143 * sent in hexadecimal notation (like <i>%xx</i>) are 144 * converted to ASCII characters. 145 * 146 * 147 * 148 * @param len an integer specifying the length, 149 * in characters, of the 150 * <code>ServletInputStream</code> 151 * object that is also passed to this 152 * method 153 * 154 * @param in the <code>ServletInputStream</code> 155 * object that contains the data sent 156 * from the client 157 * 158 * @return a <code>HashTable</code> object built 159 * from the parsed key-value pairs 160 * 161 * 162 * @exception IllegalArgumentException if the data 163 * sent by the POST method is invalid 164 * 165 */ 166 167 168 static public Hashtable parsePostData(int len, 169 ServletInputStream in) 170 { 171 // XXX 172 // should a length of 0 be an IllegalArgumentException 173 174 if (len <=0) 175 return new Hashtable(); // cheap hack to return an empty hash 176 177 if (in == null) { 178 throw new IllegalArgumentException(); 179 } 180 181 // 182 // Make sure we read the entire POSTed body. 183 // 184 byte[] postedBytes = new byte [len]; 185 try { 186 int offset = 0; 187 188 do { 189 int inputLen = in.read (postedBytes, offset, len - offset); 190 if (inputLen <= 0) { 191 String msg = lStrings.getString("err.io.short_read"); 192 throw new IllegalArgumentException (msg); 193 } 194 offset += inputLen; 195 } while ((len - offset) > 0); 196 197 } catch (IOException e) { 198 throw new IllegalArgumentException(e.getMessage()); 199 } 200 201 // XXX we shouldn't assume that the only kind of POST body 202 // is FORM data encoded using ASCII or ISO Latin/1 ... or 203 // that the body should always be treated as FORM data. 204 // 205 206 try { 207 String postedBody = new String(postedBytes, 0, len, "8859_1"); 208 return parseQueryString(postedBody); 209 } catch (java.io.UnsupportedEncodingException e) { 210 // XXX function should accept an encoding parameter & throw this 211 // exception. Otherwise throw something expected. 212 throw new IllegalArgumentException(e.getMessage()); 213 } 214 } 215 216 217 218 219 /* 220 * Parse a name in the query string. 221 */ 222 223 static private String parseName(String s, StringBuffer sb) { 224 sb.setLength(0); 225 for (int i = 0; i < s.length(); i++) { 226 char c = s.charAt(i); 227 switch (c) { 228 case '+': 229 sb.append(' '); 230 break; 231 case '%': 232 try { 233 sb.append((char) Integer.parseInt(s.substring(i+1, i+3), 234 16)); 235 i += 2; 236 } catch (NumberFormatException e) { 237 // XXX 238 // need to be more specific about illegal arg 239 throw new IllegalArgumentException(); 240 } catch (StringIndexOutOfBoundsException e) { 241 String rest = s.substring(i); 242 sb.append(rest); 243 if (rest.length()==2) 244 i++; 245 } 246 247 break; 248 default: 249 sb.append(c); 250 break; 251 } 252 } 253 return sb.toString(); 254 } 255 256 257 258 259 /** 260 * 261 * Reconstructs the URL the client used to make the request, 262 * using information in the <code>HttpServletRequest</code> object. 263 * The returned URL contains a protocol, server name, port 264 * number, and server path, but it does not include query 265 * string parameters. 266 * 267 * <p>Because this method returns a <code>StringBuffer</code>, 268 * not a string, you can modify the URL easily, for example, 269 * to append query parameters. 270 * 271 * <p>This method is useful for creating redirect messages 272 * and for reporting errors. 273 * 274 * @param req a <code>HttpServletRequest</code> object 275 * containing the client's request 276 * 277 * @return a <code>StringBuffer</code> object containing 278 * the reconstructed URL 279 * 280 */ 281 282 public static StringBuffer getRequestURL (HttpServletRequest req) { 283 StringBuffer url = new StringBuffer (); 284 String scheme = req.getScheme (); 285 int port = req.getServerPort (); 286 String urlPath = req.getRequestURI(); 287 288 //String servletPath = req.getServletPath (); 289 //String pathInfo = req.getPathInfo (); 290 291 url.append (scheme); // http, https 292 url.append ("://"); 293 url.append (req.getServerName ()); 294 if ((scheme.equals ("http") && port != 80) 295 || (scheme.equals ("https") && port != 443)) { 296 url.append (':'); 297 url.append (req.getServerPort ()); 298 } 299 //if (servletPath != null) 300 // url.append (servletPath); 301 //if (pathInfo != null) 302 // url.append (pathInfo); 303 url.append(urlPath); 304 return url; 305 } 306 } 307 308 309