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