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