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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package javax.servlet.http;
20 import java.io.IOException;
21 import java.util.Hashtable;
22 import java.util.ResourceBundle;
23 import java.util.StringTokenizer;
25 import javax.servlet.ServletInputStream;
28 * @deprecated As of Java(tm) Servlet API 2.3.
29 * These methods were only useful
30 * with the default encoding and have been moved
31 * to the request interfaces.
33 @SuppressWarnings("dep-ann") // Spec API does not use @Deprecated
34 public class HttpUtils {
36 private static final String LSTRING_FILE =
37 "javax.servlet.http.LocalStrings";
38 private static final ResourceBundle lStrings =
39 ResourceBundle.getBundle(LSTRING_FILE);
43 * Constructs an empty <code>HttpUtils</code> object.
53 * Parses a query string passed from the client to the
54 * server and builds a <code>HashTable</code> object
55 * with key-value pairs.
56 * The query string should be in the form of a string
57 * packaged by the GET or POST method, that is, it
58 * should have key-value pairs in the form <i>key=value</i>,
59 * with each pair separated from the next by a & character.
61 * <p>A key can appear more than once in the query string
62 * with different values. However, the key appears only once in
63 * the hashtable, with its value being
64 * an array of strings containing the multiple values sent
65 * by the query string.
67 * <p>The keys and values in the hashtable are stored in their
69 * any + characters are converted to spaces, and characters
70 * sent in hexadecimal notation (like <i>%xx</i>) are
71 * converted to ASCII characters.
73 * @param s a string containing the query to be parsed
75 * @return a <code>HashTable</code> object built
76 * from the parsed key-value pairs
78 * @exception IllegalArgumentException if the query string
82 public static Hashtable<String,String[]> parseQueryString(String s) {
84 String valArray[] = null;
87 throw new IllegalArgumentException();
89 Hashtable<String,String[]> ht = new Hashtable<>();
90 StringBuilder sb = new StringBuilder();
91 StringTokenizer st = new StringTokenizer(s, "&");
92 while (st.hasMoreTokens()) {
93 String pair = st.nextToken();
94 int pos = pair.indexOf('=');
97 // should give more detail about the illegal argument
98 throw new IllegalArgumentException();
100 String key = parseName(pair.substring(0, pos), sb);
101 String val = parseName(pair.substring(pos+1, pair.length()), sb);
102 if (ht.containsKey(key)) {
103 String oldVals[] = ht.get(key);
104 valArray = new String[oldVals.length + 1];
105 for (int i = 0; i < oldVals.length; i++)
106 valArray[i] = oldVals[i];
107 valArray[oldVals.length] = val;
109 valArray = new String[1];
112 ht.put(key, valArray);
120 * Parses data from an HTML form that the client sends to
121 * the server using the HTTP POST method and the
122 * <i>application/x-www-form-urlencoded</i> MIME type.
124 * <p>The data sent by the POST method contains key-value
125 * pairs. A key can appear more than once in the POST data
126 * with different values. However, the key appears only once in
127 * the hashtable, with its value being
128 * an array of strings containing the multiple values sent
129 * by the POST method.
131 * <p>The keys and values in the hashtable are stored in their
133 * any + characters are converted to spaces, and characters
134 * sent in hexadecimal notation (like <i>%xx</i>) are
135 * converted to ASCII characters.
139 * @param len an integer specifying the length,
140 * in characters, of the
141 * <code>ServletInputStream</code>
142 * object that is also passed to this
145 * @param in the <code>ServletInputStream</code>
146 * object that contains the data sent
149 * @return a <code>HashTable</code> object built
150 * from the parsed key-value pairs
153 * @exception IllegalArgumentException if the data
154 * sent by the POST method is invalid
157 public static Hashtable<String,String[]> parsePostData(int len,
158 ServletInputStream in) {
160 // should a length of 0 be an IllegalArgumentException
162 // cheap hack to return an empty hash
164 return new Hashtable<>();
167 throw new IllegalArgumentException();
170 // Make sure we read the entire POSTed body.
171 byte[] postedBytes = new byte [len];
176 int inputLen = in.read (postedBytes, offset, len - offset);
178 String msg = lStrings.getString("err.io.short_read");
179 throw new IllegalArgumentException (msg);
182 } while ((len - offset) > 0);
184 } catch (IOException e) {
185 throw new IllegalArgumentException(e.getMessage(), e);
188 // XXX we shouldn't assume that the only kind of POST body
189 // is FORM data encoded using ASCII or ISO Latin/1 ... or
190 // that the body should always be treated as FORM data.
192 String postedBody = new String(postedBytes, 0, len, "8859_1");
193 return parseQueryString(postedBody);
194 } catch (java.io.UnsupportedEncodingException e) {
195 // XXX function should accept an encoding parameter & throw this
196 // exception. Otherwise throw something expected.
197 throw new IllegalArgumentException(e.getMessage(), e);
203 * Parse a name in the query string.
205 private static String parseName(String s, StringBuilder sb) {
207 for (int i = 0; i < s.length(); i++) {
208 char c = s.charAt(i);
215 sb.append((char) Integer.parseInt(s.substring(i+1, i+3),
218 } catch (NumberFormatException e) {
220 // need to be more specific about illegal arg
221 throw new IllegalArgumentException();
222 } catch (StringIndexOutOfBoundsException e) {
223 String rest = s.substring(i);
225 if (rest.length()==2)
235 return sb.toString();
241 * Reconstructs the URL the client used to make the request,
242 * using information in the <code>HttpServletRequest</code> object.
243 * The returned URL contains a protocol, server name, port
244 * number, and server path, but it does not include query
247 * <p>Because this method returns a <code>StringBuffer</code>,
248 * not a string, you can modify the URL easily, for example,
249 * to append query parameters.
251 * <p>This method is useful for creating redirect messages
252 * and for reporting errors.
254 * @param req a <code>HttpServletRequest</code> object
255 * containing the client's request
257 * @return a <code>StringBuffer</code> object containing
258 * the reconstructed URL
261 public static StringBuffer getRequestURL (HttpServletRequest req) {
262 StringBuffer url = new StringBuffer ();
263 String scheme = req.getScheme ();
264 int port = req.getServerPort ();
265 String urlPath = req.getRequestURI();
267 url.append (scheme); // http, https
269 url.append (req.getServerName ());
270 if ((scheme.equals ("http") && port != 80)
271 || (scheme.equals ("https") && port != 443)) {
273 url.append (req.getServerPort ());