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-24 21:01:51 -0700 (Tue, 24 Oct 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