e.g. Calendar Search Help
You must enter a value before pressing Search
tomcat

Class: org.apache.catalina.util.RequestUtil   ©

 OK to copy?
001 /*
002  * Copyright 1999,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 
018 package org.apache.catalina.util;
019 
020 import java.io.UnsupportedEncodingException;
021 import java.text.SimpleDateFormat;
022 import java.util.ArrayList;
023 import java.util.Map;
024 import java.util.TimeZone;
025 
026 import javax.servlet.http.Cookie;
027 
028 
029 /**
030  * General purpose request parsing and encoding utility methods.
031  *
032  * @author Craig R. McClanahan
033  * @author Tim Tye
034  * @version $Revision: 1.8 $ $Date: 2004/05/26 16:26:10 $
035  */
036 
037 public final class RequestUtil {
038 
039 
040     /**
041      * The DateFormat to use for generating readable dates in cookies.
042      */
043     private static SimpleDateFormat format =
044         new SimpleDateFormat(" EEEE, dd-MMM-yy kk:mm:ss zz");
045 
046     static {
047         format.setTimeZone(TimeZone.getTimeZone("GMT"));
048     }
049 
050 
051     /**
052      * Encode a cookie as per RFC 2109.  The resulting string can be used
053      * as the value for a <code>Set-Cookie</code> header.
054      *
055      * @param cookie The cookie to encode.
056      * @return A string following RFC 2109.
057      */
058     public static String encodeCookie(Cookie cookie) {
059 
060         StringBuffer buf = new StringBuffer( cookie.getName() );
061         buf.append("=");
062         buf.append(cookie.getValue());
063 
064         if (cookie.getComment() != null) {
065             buf.append("; Comment=\"");
066             buf.append(cookie.getComment());
067             buf.append("\"");
068         }
069 
070         if (cookie.getDomain() != null) {
071             buf.append("; Domain=\"");
072             buf.append(cookie.getDomain());
073             buf.append("\"");
074         }
075 
076         long age = cookie.getMaxAge();
077         if (cookie.getMaxAge() >= 0) {
078             buf.append("; Max-Age=\"");
079             buf.append(cookie.getMaxAge());
080             buf.append("\"");
081         }
082 
083         if (cookie.getPath() != null) {
084             buf.append("; Path=\"");
085             buf.append(cookie.getPath());
086             buf.append("\"");
087         }
088 
089         if (cookie.getSecure()) {
090             buf.append("; Secure");
091         }
092 
093         if (cookie.getVersion() > 0) {
094             buf.append("; Version=\"");
095             buf.append(cookie.getVersion());
096             buf.append("\"");
097         }
098 
099         return (buf.toString());
100     }
101 
102 
103     /**
104      * Filter the specified message string for characters that are sensitive
105      * in HTML.  This avoids potential attacks caused by including JavaScript
106      * codes in the request URL that is often reported in error messages.
107      *
108      * @param message The message string to be filtered
109      */
110     public static String filter(String message) {
111 
112         if (message == null)
113             return (null);
114 
115         char content[] = new char[message.length()];
116         message.getChars(0, message.length(), content, 0);
117         StringBuffer result = new StringBuffer(content.length + 50);
118         for (int i = 0; i < content.length; i++) {
119             switch (content[i]) {
120             case '<':
121                 result.append("&lt;");
122                 break;
123             case '>':
124                 result.append("&gt;");
125                 break;
126             case '&':
127                 result.append("&amp;");
128                 break;
129             case '"':
130                 result.append("&quot;");
131                 break;
132             default:
133                 result.append(content[i]);
134             }
135         }
136         return (result.toString());
137 
138     }
139 
140 
141     /**
142      * Normalize a relative URI path that may have relative values ("/./",
143      * "/../", and so on ) it it.  <strong>WARNING</strong> - This method is
144      * useful only for normalizing application-generated paths.  It does not
145      * try to perform security checks for malicious input.
146      *
147      * @param path Relative path to be normalized
148      */
149     public static String normalize(String path) {
150 
151         if (path == null)
152             return null;
153 
154         // Create a place for the normalized path
155         String normalized = path;
156 
157         if (normalized.equals("/."))
158             return "/";
159 
160         // Add a leading "/" if necessary
161         if (!normalized.startsWith("/"))
162             normalized = "/" + normalized;
163 
164         // Resolve occurrences of "//" in the normalized path
165         while (true) {
166             int index = normalized.indexOf("//");
167             if (index < 0)
168                 break;
169             normalized = normalized.substring(0, index) +
170                 normalized.substring(index + 1);
171         }
172 
173         // Resolve occurrences of "/./" in the normalized path
174         while (true) {
175             int index = normalized.indexOf("/./");
176             if (index < 0)
177                 break;
178             normalized = normalized.substring(0, index) +
179                 normalized.substring(index + 2);
180         }
181 
182         // Resolve occurrences of "/../" in the normalized path
183         while (true) {
184             int index = normalized.indexOf("/../");
185             if (index < 0)
186                 break;
187             if (index == 0)
188                 return (null);  // Trying to go outside our context
189             int index2 = normalized.lastIndexOf('/', index - 1);
190             normalized = normalized.substring(0, index2) +
191                 normalized.substring(index + 3);
192         }
193 
194         // Return the normalized path that we have completed
195         return (normalized);
196 
197     }
198 
199 
200     /**
201      * Parse the character encoding from the specified content type header.
202      * If the content type is null, or there is no explicit character encoding,
203      * <code>null</code> is returned.
204      *
205      * @param contentType a content type header
206      */
207     public static String parseCharacterEncoding(String contentType) {
208 
209         if (contentType == null)
210             return (null);
211         int start = contentType.indexOf("charset=");
212         if (start < 0)
213             return (null);
214         String encoding = contentType.substring(start + 8);
215         int end = encoding.indexOf(';');
216         if (end >= 0)
217             encoding = encoding.substring(0, end);
218         encoding = encoding.trim();
219         if ((encoding.length() > 2) && (encoding.startsWith("\""))
220             && (encoding.endsWith("\"")))
221             encoding = encoding.substring(1, encoding.length() - 1);
222         return (encoding.trim());
223 
224     }
225 
226 
227     /**
228      * Parse a cookie header into an array of cookies according to RFC 2109.
229      *
230      * @param header Value of an HTTP "Cookie" header
231      */
232     public static Cookie[] parseCookieHeader(String header) {
233 
234         if ((header == null) || (header.length() < 1))
235             return (new Cookie[0]);
236 
237         ArrayList cookies = new ArrayList();
238         while (header.length() > 0) {
239             int semicolon = header.indexOf(';');
240             if (semicolon < 0)
241                 semicolon = header.length();
242             if (semicolon == 0)
243                 break;
244             String token = header.substring(0, semicolon);
245             if (semicolon < header.length())
246                 header = header.substring(semicolon + 1);
247             else
248                 header = "";
249             try {
250                 int equals = token.indexOf('=');
251                 if (equals > 0) {
252                     String name = token.substring(0, equals).trim();
253                     String value = token.substring(equals+1).trim();
254                     cookies.add(new Cookie(name, value));
255                 }
256             } catch (Throwable e) {
257                 ;
258             }
259         }
260 
261         return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));
262 
263     }
264 
265 
266     /**
267      * Append request parameters from the specified String to the specified
268      * Map.  It is presumed that the specified Map is not accessed from any
269      * other thread, so no synchronization is performed.
270      * <p>
271      * <strong>IMPLEMENTATION NOTE</strong>:  URL decoding is performed
272      * individually on the parsed name and value elements, rather than on
273      * the entire query string ahead of time, to properly deal with the case
274      * where the name or value includes an encoded "=" or "&" character
275      * that would otherwise be interpreted as a delimiter.
276      *
277      * @param map Map that accumulates the resulting parameters
278      * @param data Input string containing request parameters
279      *
280      * @exception IllegalArgumentException if the data is malformed
281      */
282     public static void parseParameters(Map map, String data, String encoding)
283         throws UnsupportedEncodingException {
284 
285         if ((data != null) && (data.length() > 0)) {
286 
287             // use the specified encoding to extract bytes out of the
288             // given string so that the encoding is not lost. If an
289             // encoding is not specified, let it use platform default
290             byte[] bytes = null;
291             try {
292                 if (encoding == null) {
293                     bytes = data.getBytes();
294                 } else {
295                     bytes = data.getBytes(encoding);
296                 }
297             } catch (UnsupportedEncodingException uee) {
298             }
299 
300             parseParameters(map, bytes, encoding);
301         }
302 
303     }
304 
305 
306     /**
307      * Decode and return the specified URL-encoded String.
308      * When the byte array is converted to a string, the system default
309      * character encoding is used...  This may be different than some other
310      * servers.
311      *
312      * @param str The url-encoded string
313      *
314      * @exception IllegalArgumentException if a '%' character is not followed
315      * by a valid 2-digit hexadecimal number
316      */
317     public static String URLDecode(String str) {
318 
319         return URLDecode(str, null);
320 
321     }
322 
323 
324     /**
325      * Decode and return the specified URL-encoded String.
326      *
327      * @param str The url-encoded string
328      * @param enc The encoding to use; if null, the default encoding is used
329      * @exception IllegalArgumentException if a '%' character is not followed
330      * by a valid 2-digit hexadecimal number
331      */
332     public static String URLDecode(String str, String enc) {
333 
334         if (str == null)
335             return (null);
336 
337         // use the specified encoding to extract bytes out of the
338         // given string so that the encoding is not lost. If an
339         // encoding is not specified, let it use platform default
340         byte[] bytes = null;
341         try {
342             if (enc == null) {
343                 bytes = str.getBytes();
344             } else {
345                 bytes = str.getBytes(enc);
346             }
347         } catch (UnsupportedEncodingException uee) {}
348 
349         return URLDecode(bytes, enc);
350 
351     }
352 
353 
354     /**
355      * Decode and return the specified URL-encoded byte array.
356      *
357      * @param bytes The url-encoded byte array
358      * @exception IllegalArgumentException if a '%' character is not followed
359      * by a valid 2-digit hexadecimal number
360      */
361     public static String URLDecode(byte[] bytes) {
362         return URLDecode(bytes, null);
363     }
364 
365 
366     /**
367      * Decode and return the specified URL-encoded byte array.
368      *
369      * @param bytes The url-encoded byte array
370      * @param enc The encoding to use; if null, the default encoding is used
371      * @exception IllegalArgumentException if a '%' character is not followed
372      * by a valid 2-digit hexadecimal number
373      */
374     public static String URLDecode(byte[] bytes, String enc) {
375 
376         if (bytes == null)
377             return (null);
378 
379         int len = bytes.length;
380         int ix = 0;
381         int ox = 0;
382         while (ix < len) {
383             byte b = bytes[ix++];     // Get byte to test
384             if (b == '+') {
385                 b = (byte)' ';
386             } else if (b == '%') {
387                 b = (byte) ((convertHexDigit(bytes[ix++]) << 4)
388                             + convertHexDigit(bytes[ix++]));
389             }
390             bytes[ox++] = b;
391         }
392         if (enc != null) {
393             try {
394                 return new String(bytes, 0, ox, enc);
395             } catch (Exception e) {
Rate396                 e.printStackTrace();
397             }
398         }
399         return new String(bytes, 0, ox);
400 
401     }
402 
403 
404     /**
405      * Convert a byte character value to hexidecimal digit value.
406      *
407      * @param b the character value byte
408      */
409     private static byte convertHexDigit( byte b ) {
410         if ((b >= '0') && (b <= '9')) return (byte)(b - '0');
411         if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10);
412         if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10);
413         return 0;
414     }
415 
416 
417     /**
418      * Put name and value pair in map.  When name already exist, add value
419      * to array of values.
420      *
421      * @param map The map to populate
422      * @param name The parameter name
423      * @param value The parameter value
424      */
425     private static void putMapEntry( Map map, String name, String value) {
426         String[] newValues = null;
427         String[] oldValues = (String[]) map.get(name);
428         if (oldValues == null) {
429             newValues = new String[1];
430             newValues[0] = value;
431         } else {
432             newValues = new String[oldValues.length + 1];
433             System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
434             newValues[oldValues.length] = value;
435         }
436         map.put(name, newValues);
437     }
438 
439 
440     /**
441      * Append request parameters from the specified String to the specified
442      * Map.  It is presumed that the specified Map is not accessed from any
443      * other thread, so no synchronization is performed.
444      * <p>
445      * <strong>IMPLEMENTATION NOTE</strong>:  URL decoding is performed
446      * individually on the parsed name and value elements, rather than on
447      * the entire query string ahead of time, to properly deal with the case
448      * where the name or value includes an encoded "=" or "&" character
449      * that would otherwise be interpreted as a delimiter.
450      *
451      * NOTE: byte array data is modified by this method.  Caller beware.
452      *
453      * @param map Map that accumulates the resulting parameters
454      * @param data Input string containing request parameters
455      * @param encoding Encoding to use for converting hex
456      *
457      * @exception UnsupportedEncodingException if the data is malformed
458      */
459     public static void parseParameters(Map map, byte[] data, String encoding)
460         throws UnsupportedEncodingException {
461 
462         if (data != null && data.length > 0) {
463             int    pos = 0;
464             int    ix = 0;
465             int    ox = 0;
466             String key = null;
467             String value = null;
468             while (ix < data.length) {
469                 byte c = data[ix++];
470                 switch ((char) c) {
471                 case '&':
472                     value = new String(data, 0, ox, encoding);
473                     if (key != null) {
474                         putMapEntry(map, key, value);
475                         key = null;
476                     }
477                     ox = 0;
478                     break;
479                 case '=':
480                     if (key == null) {
481                         key = new String(data, 0, ox, encoding);
482                         ox = 0;
483                     } else {
484                         data[ox++] = c;
485                     }                   
486                     break;  
487                 case '+':
488                     data[ox++] = (byte)' ';
489                     break;
490                 case '%':
491                     data[ox++] = (byte)((convertHexDigit(data[ix++]) << 4)
492                                     + convertHexDigit(data[ix++]));
493                     break;
494                 default:
495                     data[ox++] = c;
496                 }
497             }
498             //The last value does not end in '&'.  So save it now.
499             if (key != null) {
500                 value = new String(data, 0, ox, encoding);
501                 putMapEntry(map, key, value);
502             }
503         }
504 
505     }
506 
507 
508 
509 }

            
All Examples in File:
Example
Line
Rating (found
useful by...)
396 0% of 0