1 /**
2 *
3 * Copyright 2003-2004 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
18
19
20
21
22
23
24 package javax.servlet.http;
25
26 import java.io.IOException;
27 import java.util.Hashtable;
28 import java.util.ResourceBundle;
29 import java.util.StringTokenizer;
30 import javax.servlet.ServletInputStream;
31
32 /**
33 * @deprecated As of Java(tm) Servlet API 2.3. These methods were only useful
34 * with the default encoding and have been moved to the request interfaces.
35 *
36 * @version $Rev: 46019 $ $Date: 2004-09-14 02:56:06 -0700 (Tue, 14 Sep 2004) $
37 */
38 public class HttpUtils {
39 private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
40 private static ResourceBundle lStrings = ResourceBundle.getBundle(LSTRING_FILE);
41
42 /**
43 * Constructs an empty <code>HttpUtils</code> object.
44 */
45 public HttpUtils() {
46 }
47
48 /**
49 * Parses a query string passed from the client to the server and builds a
50 * <code>HashTable</code> object with key-value pairs. The query string
51 * should be in the form of a string packaged by the GET or POST method,
52 * that is, it should have key-value pairs in the form <i>key=value</i>,
53 * with each pair separated from the next by a & character.
54 *
55 * <p>A key can appear more than once in the query string with different
56 * values. However, the key appears only once in the hashtable, with its
57 * value being an array of strings containing the multiple values sent
58 * by the query string.
59 *
60 * <p>The keys and values in the hashtable are stored in their decoded
61 * form, so any + characters are converted to spaces, and characters
62 * sent in hexadecimal notation (like <i>%xx</i>) are converted to ASCII
63 * characters.
64 *
65 * @param s a string containing the query to be parsed
66 *
67 * @return a <code>HashTable</code> object built from the parsed key-value
68 * pairs
69 *
70 * @exception IllegalArgumentException if the query string is invalid
71 */
72 static public Hashtable parseQueryString(String s) {
73
74 String valArray[] = null;
75
76 if (s == null) {
77 throw new IllegalArgumentException();
78 }
79 Hashtable ht = new Hashtable();
80 StringBuffer sb = new StringBuffer();
81 StringTokenizer st = new StringTokenizer(s, "&");
82 while (st.hasMoreTokens()) {
83 String pair = (String) st.nextToken();
84 int pos = pair.indexOf('=');
85 if (pos == -1) {
86
87
88 throw new IllegalArgumentException();
89 }
90 String key = parseName(pair.substring(0, pos), sb);
91 String val = parseName(pair.substring(pos + 1, pair.length()), sb);
92 if (ht.containsKey(key)) {
93 String oldVals[] = (String[]) ht.get(key);
94 valArray = new String[oldVals.length + 1];
95 for (int i = 0; i < oldVals.length; i++)
96 valArray[i] = oldVals[i];
97 valArray[oldVals.length] = val;
98 } else {
99 valArray = new String[1];
100 valArray[0] = val;
101 }
102 ht.put(key, valArray);
103 }
104 return ht;
105 }
106
107 /**
108 * Parses data from an HTML form that the client sends to the server using
109 * the HTTP POST method and the <i>application/x-www-form-urlencoded</i>
110 * MIME type.
111 *
112 * <p>The data sent by the POST method contains key-value pairs. A key can
113 * appear more than once in the POST data with different values. However,
114 * the key appears only once in the hashtable, with its value being an
115 * array of strings containing the multiple values sent by the POST method.
116 *
117 * <p>The keys and values in the hashtable are stored in their decoded
118 * form, so any + characters are converted to spaces, and characters sent
119 * in hexadecimal notation (like <i>%xx</i>) are converted to ASCII
120 * characters.
121 *
122 * @param len an integer specifying the length, in characters, of the
123 * <code>ServletInputStream</code> object that is also passed to this
124 * method
125 *
126 * @param in the <code>ServletInputStream</code> object that contains the
127 * data sent from the client
128 *
129 * @return a <code>HashTable</code> object built from the parsed key-value
130 * pairs
131 *
132 * @exception IllegalArgumentException if the data sent by the POST
133 * method is invalid
134 */
135 static public Hashtable parsePostData(int len, ServletInputStream in) {
136
137
138
139 if (len <= 0) {
140 return new Hashtable();
141 }
142
143 if (in == null) {
144 throw new IllegalArgumentException();
145 }
146
147
148
149
150 byte[] postedBytes = new byte[len];
151 try {
152 int offset = 0;
153
154 do {
155 int inputLen = in.read(postedBytes, offset, len - offset);
156 if (inputLen <= 0) {
157 String msg = lStrings.getString("err.io.short_read");
158 throw new IllegalArgumentException(msg);
159 }
160 offset += inputLen;
161 } while ((len - offset) > 0);
162
163 } catch (IOException e) {
164 throw new IllegalArgumentException(e.getMessage());
165 }
166
167
168
169
170
171
172 try {
173 String postedBody = new String(postedBytes, 0, len, "8859_1");
174 return parseQueryString(postedBody);
175 } catch (java.io.UnsupportedEncodingException e) {
176
177
178 throw new IllegalArgumentException(e.getMessage());
179 }
180 }
181
182 /**
183 * Parse a name in the query string.
184 */
185 static private String parseName(String s, StringBuffer sb) {
186 sb.setLength(0);
187 for (int i = 0; i < s.length(); i++) {
188 char c = s.charAt(i);
189 switch (c) {
190 case '+':
191 sb.append(' ');
192 break;
193 case '%':
194 try {
195 sb.append((char) Integer.parseInt(s.substring(i + 1, i + 3),
196 16));
197 i += 2;
198 } catch (NumberFormatException e) {
199
200
201 throw new IllegalArgumentException();
202 } catch (StringIndexOutOfBoundsException e) {
203 String rest = s.substring(i);
204 sb.append(rest);
205 if (rest.length() == 2)
206 i++;
207 }
208
209 break;
210 default:
211 sb.append(c);
212 break;
213 }
214 }
215 return sb.toString();
216 }
217
218 /**
219 * Reconstructs the URL the client used to make the request, using
220 * information in the <code>HttpServletRequest</code> object. The returned
221 * URL contains a protocol, server name, port number, and server path, but
222 * it does not include query string parameters.
223 *
224 * <p>Because this method returns a <code>StringBuffer</code>, not a
225 * string, you can modify the URL easily, for example, to append query
226 * parameters.
227 *
228 * <p>This method is useful for creating redirect messages and for
229 * reporting errors.
230 *
231 * @param req a <code>HttpServletRequest</code> object containing the
232 * client's request
233 *
234 * @return a <code>StringBuffer</code> object containing the reconstructed
235 * URL
236 */
237 public static StringBuffer getRequestURL(HttpServletRequest req) {
238 StringBuffer url = new StringBuffer();
239 String scheme = req.getScheme();
240 int port = req.getServerPort();
241 String urlPath = req.getRequestURI();
242
243
244
245
246 url.append(scheme);
247 url.append("://");
248 url.append(req.getServerName());
249 if ((scheme.equals("http") && port != 80)
250 || (scheme.equals("https") && port != 443)) {
251 url.append(':');
252 url.append(req.getServerPort());
253 }
254
255
256
257
258 url.append(urlPath);
259 return url;
260 }
261 }
262
263
264