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 // 021 // This source code implements specifications defined by the Java 022 // Community Process. In order to remain compliant with the specification 023 // DO NOT add / change / or delete method signatures! 024 // 025 026 package javax.servlet.http; 027 028 import java.io.IOException; 029 import java.util.Hashtable; 030 import java.util.ResourceBundle; 031 import java.util.StringTokenizer; 032 import javax.servlet.ServletInputStream; 033 034 /** 035 * @deprecated As of Java(tm) Servlet API 2.3. These methods were only useful 036 * with the default encoding and have been moved to the request interfaces. 037 * 038 * @version $Rev: 467553 $ $Date: 2006-10-25 06:01:51 +0200 (Mi, 25. Okt 2006) $ 039 */ 040 public class HttpUtils { 041 private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings"; 042 private static ResourceBundle lStrings = ResourceBundle.getBundle(LSTRING_FILE); 043 044 /** 045 * Constructs an empty <code>HttpUtils</code> object. 046 */ 047 public HttpUtils() { 048 } 049 050 /** 051 * Parses a query string passed from the client to the server and builds a 052 * <code>HashTable</code> object with key-value pairs. The query string 053 * should be in the form of a string packaged by the GET or POST method, 054 * that is, it should have key-value pairs in the form <i>key=value</i>, 055 * with each pair separated from the next by a & character. 056 * 057 * <p>A key can appear more than once in the query string with different 058 * values. However, the key appears only once in the hashtable, with its 059 * value being an array of strings containing the multiple values sent 060 * by the query string. 061 * 062 * <p>The keys and values in the hashtable are stored in their decoded 063 * form, so any + characters are converted to spaces, and characters 064 * sent in hexadecimal notation (like <i>%xx</i>) are converted to ASCII 065 * characters. 066 * 067 * @param s a string containing the query to be parsed 068 * 069 * @return a <code>HashTable</code> object built from the parsed key-value 070 * pairs 071 * 072 * @exception IllegalArgumentException if the query string is invalid 073 */ 074 static public Hashtable parseQueryString(String s) { 075 076 String valArray[] = null; 077 078 if (s == null) { 079 throw new IllegalArgumentException(); 080 } 081 Hashtable ht = new Hashtable(); 082 StringBuffer sb = new StringBuffer(); 083 StringTokenizer st = new StringTokenizer(s, "&"); 084 while (st.hasMoreTokens()) { 085 String pair = (String) st.nextToken(); 086 int pos = pair.indexOf('='); 087 if (pos == -1) { 088 // XXX 089 // should give more detail about the illegal argument 090 throw new IllegalArgumentException(); 091 } 092 String key = parseName(pair.substring(0, pos), sb); 093 String val = parseName(pair.substring(pos + 1, pair.length()), sb); 094 if (ht.containsKey(key)) { 095 String oldVals[] = (String[]) ht.get(key); 096 valArray = new String[oldVals.length + 1]; 097 for (int i = 0; i < oldVals.length; i++) 098 valArray[i] = oldVals[i]; 099 valArray[oldVals.length] = val; 100 } else { 101 valArray = new String[1]; 102 valArray[0] = val; 103 } 104 ht.put(key, valArray); 105 } 106 return ht; 107 } 108 109 /** 110 * Parses data from an HTML form that the client sends to the server using 111 * the HTTP POST method and the <i>application/x-www-form-urlencoded</i> 112 * MIME type. 113 * 114 * <p>The data sent by the POST method contains key-value pairs. A key can 115 * appear more than once in the POST data with different values. However, 116 * the key appears only once in the hashtable, with its value being an 117 * array of strings containing the multiple values sent by the POST method. 118 * 119 * <p>The keys and values in the hashtable are stored in their decoded 120 * form, so any + characters are converted to spaces, and characters sent 121 * in hexadecimal notation (like <i>%xx</i>) are converted to ASCII 122 * characters. 123 * 124 * @param len an integer specifying the length, in characters, of the 125 * <code>ServletInputStream</code> object that is also passed to this 126 * method 127 * 128 * @param in the <code>ServletInputStream</code> object that contains the 129 * data sent from the client 130 * 131 * @return a <code>HashTable</code> object built from the parsed key-value 132 * pairs 133 * 134 * @exception IllegalArgumentException if the data sent by the POST 135 * method is invalid 136 */ 137 static public Hashtable parsePostData(int len, ServletInputStream in) { 138 // XXX 139 // should a length of 0 be an IllegalArgumentException 140 141 if (len <= 0) { 142 return new Hashtable(); // cheap hack to return an empty hash 143 } 144 145 if (in == null) { 146 throw new IllegalArgumentException(); 147 } 148 149 // 150 // Make sure we read the entire POSTed body. 151 // 152 byte[] postedBytes = new byte[len]; 153 try { 154 int offset = 0; 155 156 do { 157 int inputLen = in.read(postedBytes, offset, len - offset); 158 if (inputLen <= 0) { 159 String msg = lStrings.getString("err.io.short_read"); 160 throw new IllegalArgumentException(msg); 161 } 162 offset += inputLen; 163 } while ((len - offset) > 0); 164 165 } catch (IOException e) { 166 throw new IllegalArgumentException(e.getMessage()); 167 } 168 169 // XXX we shouldn't assume that the only kind of POST body 170 // is FORM data encoded using ASCII or ISO Latin/1 ... or 171 // that the body should always be treated as FORM data. 172 // 173 174 try { 175 String postedBody = new String(postedBytes, 0, len, "8859_1"); 176 return parseQueryString(postedBody); 177 } catch (java.io.UnsupportedEncodingException e) { 178 // XXX function should accept an encoding parameter & throw this 179 // exception. Otherwise throw something expected. 180 throw new IllegalArgumentException(e.getMessage()); 181 } 182 } 183 184 /** 185 * Parse a name in the query string. 186 */ 187 static private String parseName(String s, StringBuffer sb) { 188 sb.setLength(0); 189 for (int i = 0; i < s.length(); i++) { 190 char c = s.charAt(i); 191 switch (c) { 192 case '+': 193 sb.append(' '); 194 break; 195 case '%': 196 try { 197 sb.append((char) Integer.parseInt(s.substring(i + 1, i + 3), 198 16)); 199 i += 2; 200 } catch (NumberFormatException e) { 201 // XXX 202 // need to be more specific about illegal arg 203 throw new IllegalArgumentException(); 204 } catch (StringIndexOutOfBoundsException e) { 205 String rest = s.substring(i); 206 sb.append(rest); 207 if (rest.length() == 2) 208 i++; 209 } 210 211 break; 212 default: 213 sb.append(c); 214 break; 215 } 216 } 217 return sb.toString(); 218 } 219 220 /** 221 * Reconstructs the URL the client used to make the request, using 222 * information in the <code>HttpServletRequest</code> object. The returned 223 * URL contains a protocol, server name, port number, and server path, but 224 * it does not include query string parameters. 225 * 226 * <p>Because this method returns a <code>StringBuffer</code>, not a 227 * string, you can modify the URL easily, for example, to append query 228 * parameters. 229 * 230 * <p>This method is useful for creating redirect messages and for 231 * reporting errors. 232 * 233 * @param req a <code>HttpServletRequest</code> object containing the 234 * client's request 235 * 236 * @return a <code>StringBuffer</code> object containing the reconstructed 237 * URL 238 */ 239 public static StringBuffer getRequestURL(HttpServletRequest req) { 240 StringBuffer url = new StringBuffer(); 241 String scheme = req.getScheme(); 242 int port = req.getServerPort(); 243 String urlPath = req.getRequestURI(); 244 245 //String servletPath = req.getServletPath (); 246 //String pathInfo = req.getPathInfo (); 247 248 url.append(scheme); // http, https 249 url.append("://"); 250 url.append(req.getServerName()); 251 if ((scheme.equals("http") && port != 80) 252 || (scheme.equals("https") && port != 443)) { 253 url.append(':'); 254 url.append(req.getServerPort()); 255 } 256 //if (servletPath != null) 257 // url.append (servletPath); 258 //if (pathInfo != null) 259 // url.append (pathInfo); 260 url.append(urlPath); 261 return url; 262 } 263 } 264 265 266