mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractMessageParser.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /*
     2  * ====================================================================
     3  * Licensed to the Apache Software Foundation (ASF) under one
     4  * or more contributor license agreements.  See the NOTICE file
     5  * distributed with this work for additional information
     6  * regarding copyright ownership.  The ASF licenses this file
     7  * to you under the Apache License, Version 2.0 (the
     8  * "License"); you may not use this file except in compliance
     9  * with the License.  You may obtain a copy of the License at
    10  *
    11  *   http://www.apache.org/licenses/LICENSE-2.0
    12  *
    13  * Unless required by applicable law or agreed to in writing,
    14  * software distributed under the License is distributed on an
    15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    16  * KIND, either express or implied.  See the License for the
    17  * specific language governing permissions and limitations
    18  * under the License.
    19  * ====================================================================
    20  *
    21  * This software consists of voluntary contributions made by many
    22  * individuals on behalf of the Apache Software Foundation.  For more
    23  * information on the Apache Software Foundation, please see
    24  * <http://www.apache.org/>.
    25  *
    26  */
    28 package ch.boye.httpclientandroidlib.impl.io;
    30 import java.io.IOException;
    31 import java.util.ArrayList;
    32 import java.util.List;
    34 import ch.boye.httpclientandroidlib.Header;
    35 import ch.boye.httpclientandroidlib.HttpException;
    36 import ch.boye.httpclientandroidlib.HttpMessage;
    37 import ch.boye.httpclientandroidlib.ParseException;
    38 import ch.boye.httpclientandroidlib.ProtocolException;
    39 import ch.boye.httpclientandroidlib.io.HttpMessageParser;
    40 import ch.boye.httpclientandroidlib.io.SessionInputBuffer;
    41 import ch.boye.httpclientandroidlib.message.LineParser;
    42 import ch.boye.httpclientandroidlib.message.BasicLineParser;
    43 import ch.boye.httpclientandroidlib.params.CoreConnectionPNames;
    44 import ch.boye.httpclientandroidlib.params.HttpParams;
    45 import ch.boye.httpclientandroidlib.util.CharArrayBuffer;
    47 /**
    48  * Abstract base class for HTTP message parsers that obtain input from
    49  * an instance of {@link SessionInputBuffer}.
    50  * <p>
    51  * The following parameters can be used to customize the behavior of this
    52  * class:
    53  * <ul>
    54  *  <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_HEADER_COUNT}</li>
    55  *  <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_LINE_LENGTH}</li>
    56  * </ul>
    57  *
    58  * @since 4.0
    59  */
    60 public abstract class AbstractMessageParser implements HttpMessageParser {
    62     private static final int HEAD_LINE    = 0;
    63     private static final int HEADERS      = 1;
    65     private final SessionInputBuffer sessionBuffer;
    66     private final int maxHeaderCount;
    67     private final int maxLineLen;
    68     private final List headerLines;
    69     protected final LineParser lineParser;
    71     private int state;
    72     private HttpMessage message;
    74     /**
    75      * Creates an instance of this class.
    76      *
    77      * @param buffer the session input buffer.
    78      * @param parser the line parser.
    79      * @param params HTTP parameters.
    80      */
    81     public AbstractMessageParser(
    82             final SessionInputBuffer buffer,
    83             final LineParser parser,
    84             final HttpParams params) {
    85         super();
    86         if (buffer == null) {
    87             throw new IllegalArgumentException("Session input buffer may not be null");
    88         }
    89         if (params == null) {
    90             throw new IllegalArgumentException("HTTP parameters may not be null");
    91         }
    92         this.sessionBuffer = buffer;
    93         this.maxHeaderCount = params.getIntParameter(
    94                 CoreConnectionPNames.MAX_HEADER_COUNT, -1);
    95         this.maxLineLen = params.getIntParameter(
    96                 CoreConnectionPNames.MAX_LINE_LENGTH, -1);
    97         this.lineParser = (parser != null) ? parser : BasicLineParser.DEFAULT;
    98         this.headerLines = new ArrayList();
    99         this.state = HEAD_LINE;
   100     }
   102     /**
   103      * Parses HTTP headers from the data receiver stream according to the generic
   104      * format as given in Section 3.1 of RFC 822, RFC-2616 Section 4 and 19.3.
   105      *
   106      * @param inbuffer Session input buffer
   107      * @param maxHeaderCount maximum number of headers allowed. If the number
   108      *  of headers received from the data stream exceeds maxCount value, an
   109      *  IOException will be thrown. Setting this parameter to a negative value
   110      *  or zero will disable the check.
   111      * @param maxLineLen maximum number of characters for a header line,
   112      *  including the continuation lines. Setting this parameter to a negative
   113      *  value or zero will disable the check.
   114      * @return array of HTTP headers
   115      * @param parser line parser to use. Can be <code>null</code>, in which case
   116      *  the default implementation of this interface will be used.
   117      *
   118      * @throws IOException in case of an I/O error
   119      * @throws HttpException in case of HTTP protocol violation
   120      */
   121     public static Header[] parseHeaders(
   122             final SessionInputBuffer inbuffer,
   123             int maxHeaderCount,
   124             int maxLineLen,
   125             LineParser parser)
   126         throws HttpException, IOException {
   127         if (parser == null) {
   128             parser = BasicLineParser.DEFAULT;
   129         }
   130         List headerLines = new ArrayList();
   131         return parseHeaders(inbuffer, maxHeaderCount, maxLineLen, parser, headerLines);
   132     }
   134     /**
   135      * Parses HTTP headers from the data receiver stream according to the generic
   136      * format as given in Section 3.1 of RFC 822, RFC-2616 Section 4 and 19.3.
   137      *
   138      * @param inbuffer Session input buffer
   139      * @param maxHeaderCount maximum number of headers allowed. If the number
   140      *  of headers received from the data stream exceeds maxCount value, an
   141      *  IOException will be thrown. Setting this parameter to a negative value
   142      *  or zero will disable the check.
   143      * @param maxLineLen maximum number of characters for a header line,
   144      *  including the continuation lines. Setting this parameter to a negative
   145      *  value or zero will disable the check.
   146      * @param parser line parser to use.
   147      * @param headerLines List of header lines. This list will be used to store
   148      *   intermediate results. This makes it possible to resume parsing of
   149      *   headers in case of a {@link java.io.InterruptedIOException}.
   150      *
   151      * @return array of HTTP headers
   152      *
   153      * @throws IOException in case of an I/O error
   154      * @throws HttpException in case of HTTP protocol violation
   155      *
   156      * @since 4.1
   157      */
   158     public static Header[] parseHeaders(
   159             final SessionInputBuffer inbuffer,
   160             int maxHeaderCount,
   161             int maxLineLen,
   162             final LineParser parser,
   163             final List headerLines)
   164         throws HttpException, IOException {
   166         if (inbuffer == null) {
   167             throw new IllegalArgumentException("Session input buffer may not be null");
   168         }
   169         if (parser == null) {
   170             throw new IllegalArgumentException("Line parser may not be null");
   171         }
   172         if (headerLines == null) {
   173             throw new IllegalArgumentException("Header line list may not be null");
   174         }
   176         CharArrayBuffer current = null;
   177         CharArrayBuffer previous = null;
   178         for (;;) {
   179             if (current == null) {
   180                 current = new CharArrayBuffer(64);
   181             } else {
   182                 current.clear();
   183             }
   184             int l = inbuffer.readLine(current);
   185             if (l == -1 || current.length() < 1) {
   186                 break;
   187             }
   188             // Parse the header name and value
   189             // Check for folded headers first
   190             // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2
   191             // discussion on folded headers
   192             if ((current.charAt(0) == ' ' || current.charAt(0) == '\t') && previous != null) {
   193                 // we have continuation folded header
   194                 // so append value
   195                 int i = 0;
   196                 while (i < current.length()) {
   197                     char ch = current.charAt(i);
   198                     if (ch != ' ' && ch != '\t') {
   199                         break;
   200                     }
   201                     i++;
   202                 }
   203                 if (maxLineLen > 0
   204                         && previous.length() + 1 + current.length() - i > maxLineLen) {
   205                     throw new IOException("Maximum line length limit exceeded");
   206                 }
   207                 previous.append(' ');
   208                 previous.append(current, i, current.length() - i);
   209             } else {
   210                 headerLines.add(current);
   211                 previous = current;
   212                 current = null;
   213             }
   214             if (maxHeaderCount > 0 && headerLines.size() >= maxHeaderCount) {
   215                 throw new IOException("Maximum header count exceeded");
   216             }
   217         }
   218         Header[] headers = new Header[headerLines.size()];
   219         for (int i = 0; i < headerLines.size(); i++) {
   220             CharArrayBuffer buffer = (CharArrayBuffer) headerLines.get(i);
   221             try {
   222                 headers[i] = parser.parseHeader(buffer);
   223             } catch (ParseException ex) {
   224                 throw new ProtocolException(ex.getMessage());
   225             }
   226         }
   227         return headers;
   228     }
   230     /**
   231      * Subclasses must override this method to generate an instance of
   232      * {@link HttpMessage} based on the initial input from the session buffer.
   233      * <p>
   234      * Usually this method is expected to read just the very first line or
   235      * the very first valid from the data stream and based on the input generate
   236      * an appropriate instance of {@link HttpMessage}.
   237      *
   238      * @param sessionBuffer the session input buffer.
   239      * @return HTTP message based on the input from the session buffer.
   240      * @throws IOException in case of an I/O error.
   241      * @throws HttpException in case of HTTP protocol violation.
   242      * @throws ParseException in case of a parse error.
   243      */
   244     protected abstract HttpMessage parseHead(SessionInputBuffer sessionBuffer)
   245         throws IOException, HttpException, ParseException;
   247     public HttpMessage parse() throws IOException, HttpException {
   248         int st = this.state;
   249         switch (st) {
   250         case HEAD_LINE:
   251             try {
   252                 this.message = parseHead(this.sessionBuffer);
   253             } catch (ParseException px) {
   254                 throw new ProtocolException(px.getMessage(), px);
   255             }
   256             this.state = HEADERS;
   257             //$FALL-THROUGH$
   258         case HEADERS:
   259             Header[] headers = AbstractMessageParser.parseHeaders(
   260                     this.sessionBuffer,
   261                     this.maxHeaderCount,
   262                     this.maxLineLen,
   263                     this.lineParser,
   264                     this.headerLines);
   265             this.message.setHeaders(headers);
   266             HttpMessage result = this.message;
   267             this.message = null;
   268             this.headerLines.clear();
   269             this.state = HEAD_LINE;
   270             return result;
   271         default:
   272             throw new IllegalStateException("Inconsistent parser state");
   273         }
   274     }
   276 }

mercurial