src/java.net.http/share/classes/java/net/http/internal/HeaderParser.java
branchhttp-client-branch
changeset 56089 42208b2f224e
parent 56079 d23b02f37fce
equal deleted inserted replaced
56088:38fac6d0521d 56089:42208b2f224e
       
     1 /*
       
     2  * Copyright (c) 2015, 2018, 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 java.net.http.internal;
       
    27 
       
    28 import java.util.Iterator;
       
    29 import java.util.Locale;
       
    30 import java.util.NoSuchElementException;
       
    31 
       
    32 /* This is useful for the nightmare of parsing multi-part HTTP/RFC822 headers
       
    33  * sensibly:
       
    34  * From a String like: 'timeout=15, max=5'
       
    35  * create an array of Strings:
       
    36  * { {"timeout", "15"},
       
    37  *   {"max", "5"}
       
    38  * }
       
    39  * From one like: 'Basic Realm="FuzzFace" Foo="Biz Bar Baz"'
       
    40  * create one like (no quotes in literal):
       
    41  * { {"basic", null},
       
    42  *   {"realm", "FuzzFace"}
       
    43  *   {"foo", "Biz Bar Baz"}
       
    44  * }
       
    45  * keys are converted to lower case, vals are left as is....
       
    46  */
       
    47 class HeaderParser {
       
    48 
       
    49     /* table of key/val pairs */
       
    50     String raw;
       
    51     String[][] tab;
       
    52     int nkeys;
       
    53     int asize = 10; // initial size of array is 10
       
    54 
       
    55     public HeaderParser(String raw) {
       
    56         this.raw = raw;
       
    57         tab = new String[asize][2];
       
    58         parse();
       
    59     }
       
    60 
       
    61 //    private HeaderParser () { }
       
    62 
       
    63 //    /**
       
    64 //     * Creates a new HeaderParser from this, whose keys (and corresponding
       
    65 //     * values) range from "start" to "end-1"
       
    66 //     */
       
    67 //    public HeaderParser subsequence(int start, int end) {
       
    68 //        if (start == 0 && end == nkeys) {
       
    69 //            return this;
       
    70 //        }
       
    71 //        if (start < 0 || start >= end || end > nkeys) {
       
    72 //            throw new IllegalArgumentException("invalid start or end");
       
    73 //        }
       
    74 //        HeaderParser n = new HeaderParser();
       
    75 //        n.tab = new String [asize][2];
       
    76 //        n.asize = asize;
       
    77 //        System.arraycopy (tab, start, n.tab, 0, (end-start));
       
    78 //        n.nkeys= (end-start);
       
    79 //        return n;
       
    80 //    }
       
    81 
       
    82     private void parse() {
       
    83 
       
    84         if (raw != null) {
       
    85             raw = raw.trim();
       
    86             char[] ca = raw.toCharArray();
       
    87             int beg = 0, end = 0, i = 0;
       
    88             boolean inKey = true;
       
    89             boolean inQuote = false;
       
    90             int len = ca.length;
       
    91             while (end < len) {
       
    92                 char c = ca[end];
       
    93                 if ((c == '=') && !inQuote) { // end of a key
       
    94                     tab[i][0] = new String(ca, beg, end-beg).toLowerCase(Locale.US);
       
    95                     inKey = false;
       
    96                     end++;
       
    97                     beg = end;
       
    98                 } else if (c == '\"') {
       
    99                     if (inQuote) {
       
   100                         tab[i++][1]= new String(ca, beg, end-beg);
       
   101                         inQuote=false;
       
   102                         do {
       
   103                             end++;
       
   104                         } while (end < len && (ca[end] == ' ' || ca[end] == ','));
       
   105                         inKey=true;
       
   106                         beg=end;
       
   107                     } else {
       
   108                         inQuote=true;
       
   109                         end++;
       
   110                         beg=end;
       
   111                     }
       
   112                 } else if (c == ' ' || c == ',') { // end key/val, of whatever we're in
       
   113                     if (inQuote) {
       
   114                         end++;
       
   115                         continue;
       
   116                     } else if (inKey) {
       
   117                         tab[i++][0] = (new String(ca, beg, end-beg)).toLowerCase(Locale.US);
       
   118                     } else {
       
   119                         tab[i++][1] = (new String(ca, beg, end-beg));
       
   120                     }
       
   121                     while (end < len && (ca[end] == ' ' || ca[end] == ',')) {
       
   122                         end++;
       
   123                     }
       
   124                     inKey = true;
       
   125                     beg = end;
       
   126                 } else {
       
   127                     end++;
       
   128                 }
       
   129                 if (i == asize) {
       
   130                     asize = asize * 2;
       
   131                     String[][] ntab = new String[asize][2];
       
   132                     System.arraycopy (tab, 0, ntab, 0, tab.length);
       
   133                     tab = ntab;
       
   134                 }
       
   135             }
       
   136             // get last key/val, if any
       
   137             if (--end > beg) {
       
   138                 if (!inKey) {
       
   139                     if (ca[end] == '\"') {
       
   140                         tab[i++][1] = (new String(ca, beg, end-beg));
       
   141                     } else {
       
   142                         tab[i++][1] = (new String(ca, beg, end-beg+1));
       
   143                     }
       
   144                 } else {
       
   145                     tab[i++][0] = (new String(ca, beg, end-beg+1)).toLowerCase();
       
   146                 }
       
   147             } else if (end == beg) {
       
   148                 if (!inKey) {
       
   149                     if (ca[end] == '\"') {
       
   150                         tab[i++][1] = String.valueOf(ca[end-1]);
       
   151                     } else {
       
   152                         tab[i++][1] = String.valueOf(ca[end]);
       
   153                     }
       
   154                 } else {
       
   155                     tab[i++][0] = String.valueOf(ca[end]).toLowerCase();
       
   156                 }
       
   157             }
       
   158             nkeys=i;
       
   159         }
       
   160     }
       
   161 
       
   162     public String findKey(int i) {
       
   163         if (i < 0 || i > asize) {
       
   164             return null;
       
   165         }
       
   166         return tab[i][0];
       
   167     }
       
   168 
       
   169     public String findValue(int i) {
       
   170         if (i < 0 || i > asize) {
       
   171             return null;
       
   172         }
       
   173         return tab[i][1];
       
   174     }
       
   175 
       
   176     public String findValue(String key) {
       
   177         return findValue(key, null);
       
   178     }
       
   179 
       
   180     public String findValue(String k, String Default) {
       
   181         if (k == null) {
       
   182             return Default;
       
   183         }
       
   184         k = k.toLowerCase(Locale.US);
       
   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<String> {
       
   196         int index;
       
   197         boolean returnsValue; // or key
       
   198 
       
   199         ParserIterator (boolean returnValue) {
       
   200             returnsValue = returnValue;
       
   201         }
       
   202         @Override
       
   203         public boolean hasNext () {
       
   204             return index<nkeys;
       
   205         }
       
   206         @Override
       
   207         public String next () {
       
   208             if (index >= nkeys) {
       
   209                 throw new NoSuchElementException();
       
   210             }
       
   211             return tab[index++][returnsValue?1:0];
       
   212         }
       
   213     }
       
   214 
       
   215     public Iterator<String> keys () {
       
   216         return new ParserIterator (false);
       
   217     }
       
   218 
       
   219 //    public Iterator<String> values () {
       
   220 //        return new ParserIterator (true);
       
   221 //    }
       
   222 
       
   223     @Override
       
   224     public String toString () {
       
   225         Iterator<String> k = keys();
       
   226         StringBuilder sb = new StringBuilder();
       
   227         sb.append("{size=").append(asize).append(" nkeys=").append(nkeys)
       
   228                 .append(' ');
       
   229         for (int i=0; k.hasNext(); i++) {
       
   230             String key = k.next();
       
   231             String val = findValue (i);
       
   232             if (val != null && "".equals (val)) {
       
   233                 val = null;
       
   234             }
       
   235             sb.append(" {").append(key).append(val == null ? "" : "," + val)
       
   236                     .append('}');
       
   237             if (k.hasNext()) {
       
   238                 sb.append (',');
       
   239             }
       
   240         }
       
   241         sb.append (" }");
       
   242         return sb.toString();
       
   243     }
       
   244 
       
   245 //    public int findInt(String k, int Default) {
       
   246 //        try {
       
   247 //            return Integer.parseInt(findValue(k, String.valueOf(Default)));
       
   248 //        } catch (Throwable t) {
       
   249 //            return Default;
       
   250 //        }
       
   251 //    }
       
   252 }