1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 1999 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. *
  54. * ====================================================================
  55. *
  56. * This source code implements specifications defined by the Java
  57. * Community Process. In order to remain compliant with the specification
  58. * DO NOT add / change / or delete method signatures!
  59. */
  60. package javax.servlet.http;
  61. import javax.servlet.ServletInputStream;
  62. import java.util.Hashtable;
  63. import java.util.ResourceBundle;
  64. import java.util.StringTokenizer;
  65. import java.io.IOException;
  66. /**
  67. * @deprecated As of Java(tm) Servlet API 2.3.
  68. * These methods were only useful
  69. * with the default encoding and have been moved
  70. * to the request interfaces.
  71. *
  72. */
  73. public class HttpUtils {
  74. private static final String LSTRING_FILE =
  75. "javax.servlet.http.LocalStrings";
  76. private static ResourceBundle lStrings =
  77. ResourceBundle.getBundle(LSTRING_FILE);
  78. static Hashtable nullHashtable = new Hashtable();
  79. /**
  80. * Constructs an empty <code>HttpUtils</code> object.
  81. *
  82. */
  83. public HttpUtils() {}
  84. /**
  85. *
  86. * Parses a query string passed from the client to the
  87. * server and builds a <code>HashTable</code> object
  88. * with key-value pairs.
  89. * The query string should be in the form of a string
  90. * packaged by the GET or POST method, that is, it
  91. * should have key-value pairs in the form <i>key=value</i>,
  92. * with each pair separated from the next by a & character.
  93. *
  94. * <p>A key can appear more than once in the query string
  95. * with different values. However, the key appears only once in
  96. * the hashtable, with its value being
  97. * an array of strings containing the multiple values sent
  98. * by the query string.
  99. *
  100. * <p>The keys and values in the hashtable are stored in their
  101. * decoded form, so
  102. * any + characters are converted to spaces, and characters
  103. * sent in hexadecimal notation (like <i>%xx</i>) are
  104. * converted to ASCII characters.
  105. *
  106. * @param s a string containing the query to be parsed
  107. *
  108. * @return a <code>HashTable</code> object built
  109. * from the parsed key-value pairs
  110. *
  111. * @exception IllegalArgumentException if the query string
  112. * is invalid
  113. *
  114. */
  115. static public Hashtable parseQueryString(String s) {
  116. String valArray[] = null;
  117. if (s == null) {
  118. throw new IllegalArgumentException();
  119. }
  120. Hashtable ht = new Hashtable();
  121. StringBuffer sb = new StringBuffer();
  122. StringTokenizer st = new StringTokenizer(s, "&");
  123. while (st.hasMoreTokens()) {
  124. String pair = (String)st.nextToken();
  125. int pos = pair.indexOf('=');
  126. if (pos == -1) {
  127. // XXX
  128. // should give more detail about the illegal argument
  129. throw new IllegalArgumentException();
  130. }
  131. String key = parseName(pair.substring(0, pos), sb);
  132. String val = parseName(pair.substring(pos+1, pair.length()), sb);
  133. if (ht.containsKey(key)) {
  134. String oldVals[] = (String []) ht.get(key);
  135. valArray = new String[oldVals.length + 1];
  136. for (int i = 0; i < oldVals.length; i++)
  137. valArray[i] = oldVals[i];
  138. valArray[oldVals.length] = val;
  139. } else {
  140. valArray = new String[1];
  141. valArray[0] = val;
  142. }
  143. ht.put(key, valArray);
  144. }
  145. return ht;
  146. }
  147. /**
  148. *
  149. * Parses data from an HTML form that the client sends to
  150. * the server using the HTTP POST method and the
  151. * <i>application/x-www-form-urlencoded</i> MIME type.
  152. *
  153. * <p>The data sent by the POST method contains key-value
  154. * pairs. A key can appear more than once in the POST data
  155. * with different values. However, the key appears only once in
  156. * the hashtable, with its value being
  157. * an array of strings containing the multiple values sent
  158. * by the POST method.
  159. *
  160. * <p>The keys and values in the hashtable are stored in their
  161. * decoded form, so
  162. * any + characters are converted to spaces, and characters
  163. * sent in hexadecimal notation (like <i>%xx</i>) are
  164. * converted to ASCII characters.
  165. *
  166. *
  167. *
  168. * @param len an integer specifying the length,
  169. * in characters, of the
  170. * <code>ServletInputStream</code>
  171. * object that is also passed to this
  172. * method
  173. *
  174. * @param in the <code>ServletInputStream</code>
  175. * object that contains the data sent
  176. * from the client
  177. *
  178. * @return a <code>HashTable</code> object built
  179. * from the parsed key-value pairs
  180. *
  181. *
  182. * @exception IllegalArgumentException if the data
  183. * sent by the POST method is invalid
  184. *
  185. */
  186. static public Hashtable parsePostData(int len,
  187. ServletInputStream in)
  188. {
  189. // XXX
  190. // should a length of 0 be an IllegalArgumentException
  191. if (len <=0)
  192. return new Hashtable(); // cheap hack to return an empty hash
  193. if (in == null) {
  194. throw new IllegalArgumentException();
  195. }
  196. //
  197. // Make sure we read the entire POSTed body.
  198. //
  199. byte[] postedBytes = new byte [len];
  200. try {
  201. int offset = 0;
  202. do {
  203. int inputLen = in.read (postedBytes, offset, len - offset);
  204. if (inputLen <= 0) {
  205. String msg = lStrings.getString("err.io.short_read");
  206. throw new IllegalArgumentException (msg);
  207. }
  208. offset += inputLen;
  209. } while ((len - offset) > 0);
  210. } catch (IOException e) {
  211. throw new IllegalArgumentException(e.getMessage());
  212. }
  213. // XXX we shouldn't assume that the only kind of POST body
  214. // is FORM data encoded using ASCII or ISO Latin/1 ... or
  215. // that the body should always be treated as FORM data.
  216. //
  217. try {
  218. String postedBody = new String(postedBytes, 0, len, "8859_1");
  219. return parseQueryString(postedBody);
  220. } catch (java.io.UnsupportedEncodingException e) {
  221. // XXX function should accept an encoding parameter & throw this
  222. // exception. Otherwise throw something expected.
  223. throw new IllegalArgumentException(e.getMessage());
  224. }
  225. }
  226. /*
  227. * Parse a name in the query string.
  228. */
  229. static private String parseName(String s, StringBuffer sb) {
  230. sb.setLength(0);
  231. for (int i = 0; i < s.length(); i++) {
  232. char c = s.charAt(i);
  233. switch (c) {
  234. case '+':
  235. sb.append(' ');
  236. break;
  237. case '%':
  238. try {
  239. sb.append((char) Integer.parseInt(s.substring(i+1, i+3),
  240. 16));
  241. i += 2;
  242. } catch (NumberFormatException e) {
  243. // XXX
  244. // need to be more specific about illegal arg
  245. throw new IllegalArgumentException();
  246. } catch (StringIndexOutOfBoundsException e) {
  247. String rest = s.substring(i);
  248. sb.append(rest);
  249. if (rest.length()==2)
  250. i++;
  251. }
  252. break;
  253. default:
  254. sb.append(c);
  255. break;
  256. }
  257. }
  258. return sb.toString();
  259. }
  260. /**
  261. *
  262. * Reconstructs the URL the client used to make the request,
  263. * using information in the <code>HttpServletRequest</code> object.
  264. * The returned URL contains a protocol, server name, port
  265. * number, and server path, but it does not include query
  266. * string parameters.
  267. *
  268. * <p>Because this method returns a <code>StringBuffer</code>,
  269. * not a string, you can modify the URL easily, for example,
  270. * to append query parameters.
  271. *
  272. * <p>This method is useful for creating redirect messages
  273. * and for reporting errors.
  274. *
  275. * @param req a <code>HttpServletRequest</code> object
  276. * containing the client's request
  277. *
  278. * @return a <code>StringBuffer</code> object containing
  279. * the reconstructed URL
  280. *
  281. */
  282. public static StringBuffer getRequestURL (HttpServletRequest req) {
  283. StringBuffer url = new StringBuffer ();
  284. String scheme = req.getScheme ();
  285. int port = req.getServerPort ();
  286. String urlPath = req.getRequestURI();
  287. //String servletPath = req.getServletPath ();
  288. //String pathInfo = req.getPathInfo ();
  289. url.append (scheme); // http, https
  290. url.append ("://");
  291. url.append (req.getServerName ());
  292. if ((scheme.equals ("http") && port != 80)
  293. || (scheme.equals ("https") && port != 443)) {
  294. url.append (':');
  295. url.append (req.getServerPort ());
  296. }
  297. //if (servletPath != null)
  298. // url.append (servletPath);
  299. //if (pathInfo != null)
  300. // url.append (pathInfo);
  301. url.append(urlPath);
  302. return url;
  303. }
  304. }