Home | History | Annotate | Download | only in www
      1 /*
      2  * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package sun.net.www;
     27 
     28 import java.util.Iterator;
     29 
     30 /* This is useful for the nightmare of parsing multi-part HTTP/RFC822 headers
     31  * sensibly:
     32  * From a String like: 'timeout=15, max=5'
     33  * create an array of Strings:
     34  * { {"timeout", "15"},
     35  *   {"max", "5"}
     36  * }
     37  * From one like: 'Basic Realm="FuzzFace" Foo="Biz Bar Baz"'
     38  * create one like (no quotes in literal):
     39  * { {"basic", null},
     40  *   {"realm", "FuzzFace"}
     41  *   {"foo", "Biz Bar Baz"}
     42  * }
     43  * keys are converted to lower case, vals are left as is....
     44  *
     45  * @author Dave Brown
     46  */
     47 
     48 
     49 public class HeaderParser {
     50 
     51     /* table of key/val pairs */
     52     String raw;
     53     String[][] tab;
     54     int nkeys;
     55     int asize = 10; // initial size of array is 10
     56 
     57     public HeaderParser(String raw) {
     58         this.raw = raw;
     59         tab = new String[asize][2];
     60         parse();
     61     }
     62 
     63     private HeaderParser () {
     64     }
     65 
     66     /**
     67      * create a new HeaderParser from this, whose keys (and corresponding values)
     68      * range from "start" to "end-1"
     69      */
     70     public HeaderParser subsequence (int start, int end) {
     71         if (start == 0 && end == nkeys) {
     72             return this;
     73         }
     74         if (start < 0 || start >= end || end > nkeys)
     75             throw new IllegalArgumentException ("invalid start or end");
     76         HeaderParser n = new HeaderParser ();
     77         n.tab = new String [asize][2];
     78         n.asize = asize;
     79         System.arraycopy (tab, start, n.tab, 0, (end-start));
     80         n.nkeys= (end-start);
     81         return n;
     82     }
     83 
     84     private void parse() {
     85 
     86         if (raw != null) {
     87             raw = raw.trim();
     88             char[] ca = raw.toCharArray();
     89             int beg = 0, end = 0, i = 0;
     90             boolean inKey = true;
     91             boolean inQuote = false;
     92             int len = ca.length;
     93             while (end < len) {
     94                 char c = ca[end];
     95                 if ((c == '=') && !inQuote) { // end of a key
     96                     tab[i][0] = new String(ca, beg, end-beg).toLowerCase();
     97                     inKey = false;
     98                     end++;
     99                     beg = end;
    100                 } else if (c == '\"') {
    101                     if (inQuote) {
    102                         tab[i++][1]= new String(ca, beg, end-beg);
    103                         inQuote=false;
    104                         do {
    105                             end++;
    106                         } while (end < len && (ca[end] == ' ' || ca[end] == ','));
    107                         inKey=true;
    108                         beg=end;
    109                     } else {
    110                         inQuote=true;
    111                         end++;
    112                         beg=end;
    113                     }
    114                 } else if (c == ' ' || c == ',') { // end key/val, of whatever we're in
    115                     if (inQuote) {
    116                         end++;
    117                         continue;
    118                     } else if (inKey) {
    119                         tab[i++][0] = (new String(ca, beg, end-beg)).toLowerCase();
    120                     } else {
    121                         tab[i++][1] = (new String(ca, beg, end-beg));
    122                     }
    123                     while (end < len && (ca[end] == ' ' || ca[end] == ',')) {
    124                         end++;
    125                     }
    126                     inKey = true;
    127                     beg = end;
    128                 } else {
    129                     end++;
    130                 }
    131                 if (i == asize) {
    132                     asize = asize * 2;
    133                     String[][] ntab = new String[asize][2];
    134                     System.arraycopy (tab, 0, ntab, 0, tab.length);
    135                     tab = ntab;
    136                 }
    137             }
    138             // get last key/val, if any
    139             if (--end > beg) {
    140                 if (!inKey) {
    141                     if (ca[end] == '\"') {
    142                         tab[i++][1] = (new String(ca, beg, end-beg));
    143                     } else {
    144                         tab[i++][1] = (new String(ca, beg, end-beg+1));
    145                     }
    146                 } else {
    147                     tab[i++][0] = (new String(ca, beg, end-beg+1)).toLowerCase();
    148                 }
    149             } else if (end == beg) {
    150                 if (!inKey) {
    151                     if (ca[end] == '\"') {
    152                         tab[i++][1] = String.valueOf(ca[end-1]);
    153                     } else {
    154                         tab[i++][1] = String.valueOf(ca[end]);
    155                     }
    156                 } else {
    157                     tab[i++][0] = String.valueOf(ca[end]).toLowerCase();
    158                 }
    159             }
    160             nkeys=i;
    161         }
    162 
    163     }
    164 
    165     public String findKey(int i) {
    166         if (i < 0 || i > asize)
    167             return null;
    168         return tab[i][0];
    169     }
    170 
    171     public String findValue(int i) {
    172         if (i < 0 || i > asize)
    173             return null;
    174         return tab[i][1];
    175     }
    176 
    177     public String findValue(String key) {
    178         return findValue(key, null);
    179     }
    180 
    181     public String findValue(String k, String Default) {
    182         if (k == null)
    183             return Default;
    184         k = k.toLowerCase();
    185         for (int i = 0; i < asize; ++i) {
    186             if (tab[i][0] == null) {
    187                 return Default;
    188             } else if (k.equals(tab[i][0])) {
    189                 return tab[i][1];
    190             }
    191         }
    192         return Default;
    193     }
    194 
    195     class ParserIterator implements Iterator {
    196         int index;
    197         boolean returnsValue; // or key
    198 
    199         ParserIterator (boolean returnValue) {
    200             returnsValue = returnValue;
    201         }
    202         public boolean hasNext () {
    203             return index<nkeys;
    204         }
    205         public Object next () {
    206             return tab[index++][returnsValue?1:0];
    207         }
    208         public void remove () {
    209             throw new UnsupportedOperationException ("remove not supported");
    210         }
    211     }
    212 
    213     public Iterator keys () {
    214         return new ParserIterator (false);
    215     }
    216 
    217     public Iterator values () {
    218         return new ParserIterator (true);
    219     }
    220 
    221     public String toString () {
    222         Iterator k = keys();
    223         StringBuffer sbuf = new StringBuffer();
    224         sbuf.append ("{size="+asize+" nkeys="+nkeys+" ");
    225         for (int i=0; k.hasNext(); i++) {
    226             String key = (String)k.next();
    227             String val = findValue (i);
    228             if (val != null && "".equals (val)) {
    229                 val = null;
    230             }
    231             sbuf.append (" {"+key+(val==null?"":","+val)+"}");
    232             if (k.hasNext()) {
    233                 sbuf.append (",");
    234             }
    235         }
    236         sbuf.append (" }");
    237         return new String (sbuf);
    238     }
    239 
    240     public int findInt(String k, int Default) {
    241         try {
    242             return Integer.parseInt(findValue(k, String.valueOf(Default)));
    243         } catch (Throwable t) {
    244             return Default;
    245         }
    246     }
    247     /*
    248     public static void main(String[] a) throws Exception {
    249         System.out.print("enter line to parse> ");
    250         System.out.flush();
    251         DataInputStream dis = new DataInputStream(System.in);
    252         String line = dis.readLine();
    253         HeaderParser p = new HeaderParser(line);
    254         for (int i = 0; i < asize; ++i) {
    255             if (p.findKey(i) == null) break;
    256             String v = p.findValue(i);
    257             System.out.println(i + ") " +p.findKey(i) + "="+v);
    258         }
    259         System.out.println("Done!");
    260 
    261     }
    262     */
    263 }
    264