View Javadoc

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