View Javadoc

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