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