KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > HTTPClient > Util


1 /*
2  * @(#)Util.java 0.3-2 18/06/1999
3  *
4  * This file is part of the HTTPClient package
5  * Copyright (C) 1996-1999 Ronald Tschalär
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307, USA
21  *
22  * For questions, suggestions, bug-reports, enhancement-requests etc.
23  * I may be contacted at:
24  *
25  * ronald@innovation.ch
26  *
27  */

28
29 package HTTPClient;
30
31 import java.net.URL JavaDoc;
32 import java.util.Date JavaDoc;
33 import java.util.BitSet JavaDoc;
34 import java.util.Vector JavaDoc;
35 import java.util.Hashtable JavaDoc;
36 import java.util.SimpleTimeZone JavaDoc;
37 import java.util.StringTokenizer JavaDoc;
38 import java.text.SimpleDateFormat JavaDoc;
39 import java.util.Locale JavaDoc;
40
41
42 /**
43  * This class holds various utility methods.
44  *
45  * @version 0.3-2 18/06/1999
46  * @author Ronald Tschalär
47  */

48
49 public class Util
50 {
51     private static final BitSet JavaDoc Separators = new BitSet JavaDoc(128);
52     private static final BitSet JavaDoc TokenChar = new BitSet JavaDoc(128);
53     private static final BitSet JavaDoc UnsafeChar = new BitSet JavaDoc(128);
54     private static SimpleDateFormat JavaDoc http_format;
55
56     static
57     {
58     // rfc-2068 tspecial
59
Separators.set('(');
60     Separators.set(')');
61     Separators.set('<');
62     Separators.set('>');
63     Separators.set('@');
64     Separators.set(',');
65     Separators.set(';');
66     Separators.set(':');
67     Separators.set('\\');
68     Separators.set('"');
69     Separators.set('/');
70     Separators.set('[');
71     Separators.set(']');
72     Separators.set('?');
73     Separators.set('=');
74     Separators.set('{');
75     Separators.set('}');
76     Separators.set(' ');
77     Separators.set('\t');
78
79     // rfc-2068 token
80
for (int ch=32; ch<127; ch++) TokenChar.set(ch);
81     TokenChar.xor(Separators);
82
83     // rfc-1738 unsafe characters, including CTL and SP, and excluding
84
// "#" and "%"
85
for (int ch=0; ch<32; ch++) UnsafeChar.set(ch);
86     UnsafeChar.set(' ');
87     UnsafeChar.set('<');
88     UnsafeChar.set('>');
89     UnsafeChar.set('"');
90     UnsafeChar.set('{');
91     UnsafeChar.set('}');
92     UnsafeChar.set('|');
93     UnsafeChar.set('\\');
94     UnsafeChar.set('^');
95     UnsafeChar.set('~');
96     UnsafeChar.set('[');
97     UnsafeChar.set(']');
98     UnsafeChar.set('`');
99     UnsafeChar.set(127);
100
101     // rfc-1123 date format (restricted to GMT, as per rfc-2068)
102
/* This initialization has been moved to httpDate() because it
103      * takes an awfully long time and is often not needed
104      *
105     http_format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'",
106                        Locale.US);
107     http_format.setTimeZone(new SimpleTimeZone(0, "GMT"));
108     */

109     }
110
111
112     // Constructors
113

114     /**
115      * This class isn't meant to be instantiated.
116      */

117     private Util() {}
118
119
120     // Methods
121

122     // this doesn't work!!! Aaaaarrgghhh!
123
final static Object JavaDoc[] resizeArray(Object JavaDoc[] src, int new_size)
124     {
125     Object JavaDoc tmp[] = new Object JavaDoc[new_size];
126     System.arraycopy(src, 0, tmp, 0,
127             (src.length < new_size ? src.length : new_size));
128     return tmp;
129     }
130
131     final static NVPair[] resizeArray(NVPair[] src, int new_size)
132     {
133     NVPair tmp[] = new NVPair[new_size];
134     System.arraycopy(src, 0, tmp, 0,
135             (src.length < new_size ? src.length : new_size));
136     return tmp;
137     }
138
139     final static AuthorizationInfo[] resizeArray(AuthorizationInfo[] src,
140                          int new_size)
141     {
142     AuthorizationInfo tmp[] = new AuthorizationInfo[new_size];
143     System.arraycopy(src, 0, tmp, 0,
144             (src.length < new_size ? src.length : new_size));
145     return tmp;
146     }
147
148     final static Cookie[] resizeArray(Cookie[] src, int new_size)
149     {
150     Cookie tmp[] = new Cookie[new_size];
151     System.arraycopy(src, 0, tmp, 0,
152             (src.length < new_size ? src.length : new_size));
153     return tmp;
154     }
155
156     final static String JavaDoc[] resizeArray(String JavaDoc[] src, int new_size)
157     {
158     String JavaDoc tmp[] = new String JavaDoc[new_size];
159     System.arraycopy(src, 0, tmp, 0,
160             (src.length < new_size ? src.length : new_size));
161     return tmp;
162     }
163
164     final static boolean[] resizeArray(boolean[] src, int new_size)
165     {
166     boolean tmp[] = new boolean[new_size];
167     System.arraycopy(src, 0, tmp, 0,
168             (src.length < new_size ? src.length : new_size));
169     return tmp;
170     }
171
172     final static byte[] resizeArray(byte[] src, int new_size)
173     {
174     byte tmp[] = new byte[new_size];
175     System.arraycopy(src, 0, tmp, 0,
176             (src.length < new_size ? src.length : new_size));
177     return tmp;
178     }
179
180     final static char[] resizeArray(char[] src, int new_size)
181     {
182     char tmp[] = new char[new_size];
183     System.arraycopy(src, 0, tmp, 0,
184             (src.length < new_size ? src.length : new_size));
185     return tmp;
186     }
187
188     final static int[] resizeArray(int[] src, int new_size)
189     {
190     int tmp[] = new int[new_size];
191     System.arraycopy(src, 0, tmp, 0,
192             (src.length < new_size ? src.length : new_size));
193     return tmp;
194     }
195
196
197     /**
198      * Split a property into an array of Strings, using "|" as the
199      * separator.
200      */

201     static String JavaDoc[] splitProperty(String JavaDoc prop)
202     {
203     if (prop == null) return new String JavaDoc[0];
204
205     StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(prop, "|");
206     String JavaDoc[] list = new String JavaDoc[tok.countTokens()];
207     for (int idx=0; idx<list.length; idx++)
208         list[idx] = tok.nextToken().trim();
209
210     return list;
211     }
212
213
214     /**
215      * Helper method for context lists used by modules. Returns the
216      * list associated with the context if it exists; otherwise it creates
217      * a new list and adds it to the context list.
218      *
219      * @param cntxt_list the list of lists indexed by context
220      * @param cntxt the context
221      */

222     final static Hashtable JavaDoc getList(Hashtable JavaDoc cntxt_list, Object JavaDoc cntxt)
223     {
224     Hashtable JavaDoc list = (Hashtable JavaDoc) cntxt_list.get(cntxt);
225     if (list == null)
226     {
227         synchronized(cntxt_list) // only synch if necessary
228
{
229         list = (Hashtable JavaDoc) cntxt_list.get(cntxt);
230         if (list == null) // verify nobody else beat us to it
231
{
232             list = new Hashtable JavaDoc();
233             cntxt_list.put(cntxt, list);
234         }
235         }
236     }
237
238     return list;
239     }
240
241
242     /**
243      * Creates an array of distances to speed up the search in findStr().
244      * The returned array should be passed as the second argument to
245      * findStr().
246      *
247      * @param search the search string (same as the first argument to
248      * findStr()).
249      * @return an array of distances (to be passed as the second argument to
250      * findStr()).
251      */

252     final static int[] compile_search(byte[] search)
253     {
254     int[] cmp = {0, 1, 0, 1, 0, 1};
255     int end;
256
257     for (int idx=0; idx<search.length; idx++)
258     {
259         for (end=idx+1; end<search.length; end++)
260         {
261         if (search[idx] == search[end]) break;
262         }
263         if (end < search.length)
264         {
265         if ((end-idx) > cmp[1])
266         {
267             cmp[4] = cmp[2];
268             cmp[5] = cmp[3];
269             cmp[2] = cmp[0];
270             cmp[3] = cmp[1];
271             cmp[0] = idx;
272             cmp[1] = end - idx;
273         }
274         else if ((end-idx) > cmp[3])
275         {
276             cmp[4] = cmp[2];
277             cmp[5] = cmp[3];
278             cmp[2] = idx;
279             cmp[3] = end - idx;
280         }
281         else if ((end-idx) > cmp[3])
282         {
283             cmp[4] = idx;
284             cmp[5] = end - idx;
285         }
286         }
287     }
288
289     cmp[1] += cmp[0];
290     cmp[3] += cmp[2];
291     cmp[5] += cmp[4];
292     return cmp;
293     }
294
295     /**
296      * Search for a string. Use compile_search() to first generate the second
297      * argument. This uses a Knuth-Morris-Pratt like algorithm.
298      *
299      * @param search the string to search for.
300      * @param cmp the the array returned by compile_search.
301      * @param str the string in which to look for <var>search</var>.
302      * @param beg the position at which to start the search in
303      * <var>str</var>.
304      * @param end the position at which to end the search in <var>str</var>,
305      * noninclusive.
306      * @return the position in <var>str</var> where <var>search</var> was
307      * found, or -1 if not found.
308      */

309     final static int findStr(byte[] search, int[] cmp, byte[] str,
310                      int beg, int end)
311     {
312     int c1f = cmp[0],
313         c1l = cmp[1],
314         d1 = c1l - c1f,
315         c2f = cmp[2],
316         c2l = cmp[3],
317         d2 = c2l - c2f,
318         c3f = cmp[4],
319         c3l = cmp[5],
320         d3 = c3l - c3f;
321
322     Find: while (beg+search.length <= end)
323     {
324         if (search[c1l] == str[beg+c1l])
325         {
326         /* This is correct, but Visual J++ can't cope with it...
327         Comp: if (search[c1f] == str[beg+c1f])
328         {
329             for (int idx=0; idx<search.length; idx++)
330             if (search[idx] != str[beg+idx]) break Comp;
331
332             break Find; // we found it
333         }
334         * so here is the replacement: */

335         if (search[c1f] == str[beg+c1f])
336         {
337             boolean same = true;
338
339             for (int idx=0; idx<search.length; idx++)
340             if (search[idx] != str[beg+idx])
341             {
342                 same = false;
343                 break;
344             }
345
346             if (same)
347             break Find; // we found it
348
}
349
350         beg += d1;
351         }
352         else if (search[c2l] == str[beg+c2l])
353         beg += d2;
354         else if (search[c3l] == str[beg+c3l])
355         beg += d3;
356         else
357         beg++;
358     }
359
360     if (beg+search.length > end)
361         return -1;
362     else
363         return beg;
364     }
365
366
367     /**
368      * Replace quoted characters by their unquoted version. Quoted characters
369      * are characters preceded by a slash. E.g. "\c" would be replaced by "c".
370      * This is used in parsing http headers where quoted-characters are
371      * allowed in quoted-strings and often used to quote the quote character
372      * &lt;"&gt;.
373      *
374      * @param str the string do dequote
375      * @return the string do with all quoted characters replaced by their
376      * true value.
377      */

378     public final static String JavaDoc dequoteString(String JavaDoc str)
379     {
380     if (str.indexOf('\\') == -1) return str;
381
382     char[] buf = str.toCharArray();
383     int pos = 0, num_deq = 0;
384     while (pos < buf.length)
385     {
386         if (buf[pos] == '\\' && pos+1 < buf.length)
387         {
388         System.arraycopy(buf, pos+1, buf, pos, buf.length-pos-1);
389         num_deq++;
390         }
391         pos++;
392     }
393
394     return new String JavaDoc(buf, 0, buf.length-num_deq);
395     }
396
397
398     /**
399      * Replace given characters by their quoted version. Quoted characters
400      * are characters preceded by a slash. E.g. "c" would be replaced by "\c".
401      * This is used in generating http headers where certain characters need
402      * to be quoted, such as the quote character &lt;"&gt;.
403      *
404      * @param str the string do quote
405      * @param qlist the list of characters to quote
406      * @return the string do with all characters replaced by their
407      * quoted version.
408      */

409     public final static String JavaDoc quoteString(String JavaDoc str, String JavaDoc qlist)
410     {
411     char[] list = qlist.toCharArray();
412     int idx;
413     for (idx=0; idx<list.length; idx++)
414         if (str.indexOf(list[idx]) != -1) break;
415     if (idx == list.length) return str;
416
417     int len = str.length();
418     char[] buf = new char[len*2];
419     str.getChars(0, len, buf, 0);
420     int pos = 0;
421     while (pos < len)
422     {
423         if (qlist.indexOf(buf[pos], 0) != -1)
424         {
425         if (len == buf.length)
426             buf = Util.resizeArray(buf, len+str.length());
427
428         System.arraycopy(buf, pos, buf, pos+1, len-pos);
429         len++;
430         buf[pos++] = '\\';
431         }
432         pos++;
433     }
434
435     return new String JavaDoc(buf, 0, len);
436     }
437
438
439     /**
440      * This parses the value part of a header. All quoted strings are
441      * dequoted.
442      *
443      * @see #parseHeader(java.lang.String, boolean)
444      * @param header the value part of the header.
445      * @return a Vector containing all the elements; each entry is an
446      * instance of <var>HttpHeaderElement</var>.
447      * @exception ParseException if the syntax rules are violated.
448      */

449     public final static Vector JavaDoc parseHeader(String JavaDoc header) throws ParseException
450     {
451     return parseHeader(header, true);
452     }
453
454
455     /**
456      * This parses the value part of a header. The result is a Vector of
457      * HttpHeaderElement's. The syntax the header must conform to is:
458      *
459      * <PRE>
460      * header = [ element ] *( "," [ element ] )
461      * element = name [ "=" [ value ] ] *( ";" [ param ] )
462      * param = name [ "=" [ value ] ]
463      *
464      * name = token
465      * value = ( token | quoted-string )
466      *
467      * token = 1*&lt;any char except "=", ",", ";", &lt;"&gt; and
468      * white space&gt;
469      * quoted-string = &lt;"&gt; *( text | quoted-char ) &lt;"&gt;
470      * text = any char except &lt;"&gt;
471      * quoted-char = "\" char
472      * </PRE>
473      *
474      * Any amount of white space is allowed between any part of the header,
475      * element or param and is ignored. A missing value in any element or
476      * param will be stored as the empty string; if the "=" is also missing
477      * <var>null</var> will be stored instead.
478      *
479      * @param header the value part of the header.
480      * @param dequote if true all quoted strings are dequoted.
481      * @return a Vector containing all the elements; each entry is an
482      * instance of <var>HttpHeaderElement</var>.
483      * @exception ParseException if the above syntax rules are violated.
484      * @see HTTPClient.HttpHeaderElement
485      */

486     public final static Vector JavaDoc parseHeader(String JavaDoc header, boolean dequote)
487         throws ParseException
488     {
489     if (header == null) return null;
490     char[] buf = header.toCharArray();
491     Vector JavaDoc elems = new Vector JavaDoc();
492     boolean first = true;
493     int beg = -1, end = 0, len = buf.length, abeg[] = new int[1];
494     String JavaDoc elem_name, elem_value;
495
496
497     elements: while (true)
498     {
499         if (!first) // find required ","
500
{
501         beg = skipSpace(buf, end);
502         if (beg == len) break;
503         if (buf[beg] != ',')
504             throw new ParseException("Bad header format: '" + header +
505                          "'\nExpected \",\" at position " +
506                          beg);
507         }
508         first = false;
509
510         beg = skipSpace(buf, beg+1);
511         if (beg == len) break elements;
512         if (buf[beg] == ',') // skip empty elements
513
{
514         end = beg;
515         continue elements;
516         }
517
518         if (buf[beg] == '=' || buf[beg] == ';' || buf[beg] == '"')
519         throw new ParseException("Bad header format: '" + header +
520                      "'\nEmpty element name at position " +
521                      beg);
522
523         end = beg+1; // extract element name
524
while (end < len && !Character.isSpace(buf[end]) &&
525            buf[end] != '=' && buf[end] != ',' && buf[end] != ';')
526         end++;
527         elem_name = new String JavaDoc(buf, beg, end-beg);
528
529         beg = skipSpace(buf, end);
530         if (beg < len && buf[beg] == '=') // element value
531
{
532         abeg[0] = beg+1;
533         elem_value = parseValue(buf, abeg, header, dequote);
534         end = abeg[0];
535         }
536         else
537         {
538         elem_value = null;
539         end = beg;
540         }
541
542         NVPair[] params = new NVPair[0];
543         params: while (true)
544         {
545         String JavaDoc param_name, param_value;
546
547         beg = skipSpace(buf, end); // expect ";"
548
if (beg == len || buf[beg] != ';')
549             break params;
550
551         beg = skipSpace(buf, beg+1);
552         if (beg == len || buf[beg] == ',')
553         {
554             end = beg;
555             break params;
556         }
557         if (buf[beg] == ';') // skip empty parameters
558
{
559             end = beg;
560             continue params;
561         }
562
563         if (buf[beg] == '=' || buf[beg] == '"')
564             throw new ParseException("Bad header format: '" + header +
565                      "'\nEmpty parameter name at position "+
566                      beg);
567
568         end = beg+1; // extract param name
569
while (end < len && !Character.isSpace(buf[end]) &&
570                buf[end] != '=' && buf[end] != ',' && buf[end] != ';')
571             end++;
572         param_name = new String JavaDoc(buf, beg, end-beg);
573
574         beg = skipSpace(buf, end);
575         if (beg < len && buf[beg] == '=') // element value
576
{
577             abeg[0] = beg+1;
578             param_value = parseValue(buf, abeg, header, dequote);
579             end = abeg[0];
580         }
581         else
582         {
583             param_value = null;
584             end = beg;
585         }
586
587         params = Util.resizeArray(params, params.length+1);
588         params[params.length-1] = new NVPair(param_name, param_value);
589         }
590
591         elems.addElement(
592               new HttpHeaderElement(elem_name, elem_value, params));
593     }
594
595     return elems;
596     }
597
598
599     /**
600      * Parse the value part. Accepts either token or quoted string.
601      */

602     private static String JavaDoc parseValue(char[] buf, int[] abeg, String JavaDoc header,
603                      boolean dequote)
604         throws ParseException
605     {
606     int beg = abeg[0], end = beg, len = buf.length;
607     String JavaDoc value;
608
609
610     beg = skipSpace(buf, beg);
611
612     if (beg < len && buf[beg] == '"') // it's a quoted-string
613
{
614         beg++;
615         end = beg;
616         char[] deq_buf = null;
617         int deq_pos = 0, lst_pos = beg;
618
619         while (end < len && buf[end] != '"')
620         {
621         if (buf[end] == '\\')
622         {
623             if (dequote) // dequote char
624
{
625             if (deq_buf == null)
626                 deq_buf = new char[buf.length];
627             System.arraycopy(buf, lst_pos, deq_buf, deq_pos,
628                      end-lst_pos);
629             deq_pos += end-lst_pos;
630             lst_pos = ++end;
631             }
632             else
633             end++; // skip quoted char
634
}
635
636         end++;
637         }
638         if (end == len)
639         throw new ParseException("Bad header format: '" + header +
640                      "'\nClosing <\"> for quoted-string"+
641                      " starting at position " +
642                      (beg-1) + " not found");
643         if (deq_buf != null)
644         {
645         System.arraycopy(buf, lst_pos, deq_buf, deq_pos, end-lst_pos);
646         deq_pos += end-lst_pos;
647         value = new String JavaDoc(deq_buf, 0, deq_pos);
648         }
649         else
650         value = new String JavaDoc(buf, beg, end-beg);
651         end++;
652     }
653     else // it's a simple token value
654
{
655         end = beg;
656         while (end < len && !Character.isSpace(buf[end]) &&
657            buf[end] != ',' && buf[end] != ';')
658         end++;
659
660         value = new String JavaDoc(buf, beg, end-beg);
661     }
662
663     abeg[0] = end;
664     return value;
665     }
666
667
668     /**
669      * Determines if the given header contains a certain token. The header
670      * must conform to the rules outlined in parseHeader().
671      *
672      * @see #parseHeader(java.lang.String)
673      * @param header the header value.
674      * @param token the token to find; the match is case-insensitive.
675      * @return true if the token is present, false otherwise.
676      * @exception ParseException if this is thrown parseHeader().
677      */

678     public final static boolean hasToken(String JavaDoc header, String JavaDoc token)
679         throws ParseException
680     {
681     if (header == null)
682         return false;
683     else
684         return parseHeader(header).contains(new HttpHeaderElement(token));
685     }
686
687
688     /**
689      * Get the HttpHeaderElement with the name <var>name</var>.
690      *
691      * @param header a vector of HttpHeaderElement's, such as is returned
692      * from <code>parseHeader()</code>
693      * @param name the name of element to retrieve; matching is
694      * case-insensitive
695      * @return the request element, or null if none found.
696      * @see #parseHeader(java.lang.String)
697      */

698     public final static HttpHeaderElement getElement(Vector JavaDoc header, String JavaDoc name)
699     {
700     int idx = header.indexOf(new HttpHeaderElement(name));
701     if (idx == -1)
702         return null;
703     else
704         return (HttpHeaderElement) header.elementAt(idx);
705     }
706
707
708     /**
709      * retrieves the value associated with the parameter <var>param</var> in
710      * a given header string. It parses the header using
711      * <code>parseHeader()</code> and then searches the first element for the
712      * given parameter. This is used especially in headers like
713      * 'Content-type' and 'Content-Disposition'.
714      *
715      * <P>quoted characters ("\x") in a quoted string are dequoted.
716      *
717      * @see #parseHeader(java.lang.String)
718      * @param param the parameter name
719      * @param hdr the header value
720      * @return the value for this parameter, or null if not found.
721      * @exception ParseException if the above syntax rules are violated.
722      */

723     public final static String JavaDoc getParameter(String JavaDoc param, String JavaDoc hdr)
724         throws ParseException
725     {
726     NVPair[] params = ((HttpHeaderElement) parseHeader(hdr).firstElement()).
727                 getParams();
728
729     for (int idx=0; idx<params.length; idx++)
730     {
731         if (params[idx].getName().equalsIgnoreCase(param))
732         return params[idx].getValue();
733     }
734
735     return null;
736     }
737
738
739     /**
740      * Assembles a Vector of HttpHeaderElements into a full header string.
741      * The individual header elements are seperated by a ", ".
742      *
743      * @param the parsed header
744      * @return a string containing the assembled header
745      */

746     public final static String JavaDoc assembleHeader(Vector JavaDoc pheader)
747     {
748     StringBuffer JavaDoc hdr = new StringBuffer JavaDoc(200);
749     int len = pheader.size();
750
751     for (int idx=0; idx<len; idx++)
752     {
753         ((HttpHeaderElement) pheader.elementAt(idx)).appendTo(hdr);
754         hdr.append(", ");
755     }
756     hdr.setLength(hdr.length()-2);
757
758     return hdr.toString();
759     }
760
761
762     /**
763      * returns the position of the first non-space character in a char array
764      * starting a position pos.
765      *
766      * @param str the char array
767      * @param pos the position to start looking
768      * @return the position of the first non-space character
769      */

770     final static int skipSpace(char[] str, int pos)
771     {
772     int len = str.length;
773     while (pos < len && Character.isSpace(str[pos])) pos++;
774     return pos;
775     }
776
777     /**
778      * returns the position of the first space character in a char array
779      * starting a position pos.
780      *
781      * @param str the char array
782      * @param pos the position to start looking
783      * @return the position of the first space character, or the length of
784      * the string if not found
785      */

786     final static int findSpace(char[] str, int pos)
787     {
788     int len = str.length;
789     while (pos < len && !Character.isSpace(str[pos])) pos++;
790     return pos;
791     }
792
793     /**
794      * returns the position of the first non-token character in a char array
795      * starting a position pos.
796      *
797      * @param str the char array
798      * @param pos the position to start looking
799      * @return the position of the first non-token character, or the length
800      * of the string if not found
801      */

802     final static int skipToken(char[] str, int pos)
803     {
804     int len = str.length;
805     while (pos < len && TokenChar.get(str[pos])) pos++;
806     return pos;
807     }
808
809
810     /**
811      * Does the string need to be quoted when sent in a header? I.e. does
812      * it contain non-token characters?
813      *
814      * @param str the string
815      * @return true if it needs quoting (i.e. it contains non-token chars)
816      */

817     final static boolean needsQuoting(String JavaDoc str)
818     {
819     int len = str.length(), pos = 0;
820
821     while (pos < len && TokenChar.get(str.charAt(pos))) pos++;
822     return (pos < len);
823     }
824
825
826     /**
827      * Compares two http urls for equality. This exists because the method
828      * <code>java.net.URL.sameFile()</code> is broken (an explicit port 80
829      * doesn't compare equal to an implicit port, and it doesn't take
830      * escapes into account).
831      *
832      * <P>Two http urls are considered equal if they have the same protocol
833      * (case-insensitive match), the same host (case-insensitive), the
834      * same port and the same file (after decoding escaped characters).
835      *
836      * @param url1 the first url
837      * @param url1 the second url
838      * @return true if <var>url1</var> and <var>url2</var> compare equal
839      */

840     public final static boolean sameHttpURL(URL JavaDoc url1, URL JavaDoc url2)
841     {
842     if (!url1.getProtocol().equalsIgnoreCase(url2.getProtocol()))
843         return false;
844
845     if (!url1.getHost().equalsIgnoreCase(url2.getHost()))
846         return false;
847
848     int port1 = url1.getPort(), port2 = url2.getPort();
849     if (port1 == -1) port1 = URI.defaultPort(url1.getProtocol());
850     if (port2 == -1) port2 = URI.defaultPort(url1.getProtocol());
851     if (port1 != port2)
852         return false;
853
854     try
855         { return URI.unescape(url1.getFile()).equals(URI.unescape(url2.getFile())); }
856     catch (ParseException pe)
857         { return url1.getFile().equals(url2.getFile());}
858     }
859
860
861     /**
862      * Return the default port used by a given protocol.
863      *
864      * @param protocol the protocol
865      * @return the port number, or 0 if unknown
866      * @deprecated use URI.defaultPort() instead
867      * @see HTTPClient.URI#defaultPort(java.lang.String)
868      */

869     public final static int defaultPort(String JavaDoc protocol)
870     {
871     return URI.defaultPort(protocol);
872     }
873
874
875     /**
876      * This returns a string containing the date and time in <var>date</var>
877      * formatted according to a subset of RFC-1123. The format is defined in
878      * the HTTP/1.0 spec (RFC-1945), section 3.3, and the HTTP/1.1 spec
879      * (RFC-2068), section 3.3.1. Note that Date.toGMTString() is close, but
880      * is missing the weekday and supresses the leading zero if the day is
881      * less than the 10th. Instead we use the SimpleDateFormat class.
882      *
883      * <P>Some versions of JDK 1.1.x are bugged in that their GMT uses
884      * daylight savings time... Therefore we use our own timezone
885      * definitions.
886      *
887      * @param date the date and time to be converted
888      * @return a string containg the date and time as used in http
889      */

890     public final static String JavaDoc httpDate(Date JavaDoc date)
891     {
892     if (http_format == null)
893     {
894         synchronized(HTTPClient.Util.class)
895         {
896         if (http_format == null)
897         {
898             http_format =
899             new SimpleDateFormat JavaDoc("EEE, dd MMM yyyy HH:mm:ss 'GMT'",
900                          Locale.US);
901             http_format.setTimeZone(new SimpleTimeZone JavaDoc(0, "GMT"));
902         }
903         }
904     }
905
906     return http_format.format(date);
907     }
908
909
910     /**
911      * Escape unsafe characters in a path.
912      *
913      * @param path the original path
914      * @return the path with all unsafe characters escaped
915      */

916     final static String JavaDoc escapeUnsafeChars(String JavaDoc path)
917     {
918     int len = path.length();
919     char[] buf = new char[3*len];
920
921     int dst = 0;
922     for (int SRC=0; src<len; src++)
923     {
924         char ch = path.charAt(src);
925         if (ch >= 128 || UnsafeChar.get(ch))
926         {
927         buf[dst++] = '%';
928         buf[dst++] = hex_map[(ch & 0xf0) >>> 4];
929         buf[dst++] = hex_map[ch & 0x0f];
930         }
931         else
932         buf[dst++] = ch;
933     }
934
935     if (dst > len)
936         return new String JavaDoc(buf, 0, dst);
937     else
938         return path;
939     }
940
941     static final char[] hex_map =
942         {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
943
944
945     /**
946      * Extract the path from an http resource.
947      *
948      * <P>The "resource" part of an HTTP URI can contain a number of parts,
949      * some of which are not always of interest. These methods here will
950      * extract the various parts, assuming the following syntanx (taken from
951      * RFC-2068):
952      *
953      * <PRE>
954      * resource = [ "/" ] [ path ] [ ";" params ] [ "?" query ] [ "#" fragment ]
955      * </PRE>
956      *
957      * @param the resource to split
958      * @return the path, including any leading "/"
959      * @see #getParams
960      * @see #getQuery
961      * @see #getFragment
962      */

963     public final static String JavaDoc getPath(String JavaDoc resource)
964     {
965     int p, end = resource.length();
966     if ((p = resource.indexOf('#')) != -1) // find fragment
967
end = p;
968     if ((p = resource.indexOf('?')) != -1 && p < end) // find query
969
end = p;
970     if ((p = resource.indexOf(';')) != -1 && p < end) // find params
971
end = p;
972     return resource.substring(0, end);
973     }
974
975
976     /**
977      * Extract the params part from an http resource.
978      *
979      * @param the resource to split
980      * @return the params, or null if there are none
981      * @see #getPath
982      */

983     public final static String JavaDoc getParams(String JavaDoc resource)
984     {
985     int beg, f, q;
986     if ((beg = resource.indexOf(';')) == -1) // find params
987
return null;
988     if ((f = resource.indexOf('#')) != -1 && f < beg) // find fragment
989
return null;
990     if ((q = resource.indexOf('?')) != -1 && q < beg) // find query
991
return null;
992     if (q == -1 && f == -1)
993         return resource.substring(beg+1);
994     if (f == -1 || (q != -1 && q < f))
995         return resource.substring(beg+1, q);
996     else
997         return resource.substring(beg+1, f);
998     }
999
1000
1001    /**
1002     * Extract the query string from an http resource.
1003     *
1004     * @param the resource to split
1005     * @return the query, or null if there was none
1006     * @see #getPath
1007     */

1008    public final static String JavaDoc getQuery(String JavaDoc resource)
1009    {
1010    int beg, f;
1011    if ((beg = resource.indexOf('?')) == -1) // find query
1012
return null;
1013    if ((f = resource.indexOf('#')) != -1 && f < beg) // find fragment
1014
return null; // '?' is in fragment
1015
if (f == -1)
1016        return resource.substring(beg+1); // no fragment
1017
else
1018        return resource.substring(beg+1, f); // strip fragment
1019
}
1020
1021
1022    /**
1023     * Extract the fragment part from an http resource.
1024     *
1025     * @param the resource to split
1026     * @return the fragment, or null if there was none
1027     * @see #getPath
1028     */

1029    public final static String JavaDoc getFragment(String JavaDoc resource)
1030    {
1031    int beg;
1032    if ((beg = resource.indexOf('#')) == -1) // find fragment
1033
return null;
1034    else
1035        return resource.substring(beg+1);
1036    }
1037}
1038
1039
Popular Tags