Home | History | Annotate | Download | only in io
      1 /*
      2  * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/AbstractMessageParser.java $
      3  * $Revision: 576077 $
      4  * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
      5  *
      6  * ====================================================================
      7  * Licensed to the Apache Software Foundation (ASF) under one
      8  * or more contributor license agreements.  See the NOTICE file
      9  * distributed with this work for additional information
     10  * regarding copyright ownership.  The ASF licenses this file
     11  * to you under the Apache License, Version 2.0 (the
     12  * "License"); you may not use this file except in compliance
     13  * with the License.  You may obtain a copy of the License at
     14  *
     15  *   http://www.apache.org/licenses/LICENSE-2.0
     16  *
     17  * Unless required by applicable law or agreed to in writing,
     18  * software distributed under the License is distributed on an
     19  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     20  * KIND, either express or implied.  See the License for the
     21  * specific language governing permissions and limitations
     22  * under the License.
     23  * ====================================================================
     24  *
     25  * This software consists of voluntary contributions made by many
     26  * individuals on behalf of the Apache Software Foundation.  For more
     27  * information on the Apache Software Foundation, please see
     28  * <http://www.apache.org/>.
     29  *
     30  */
     31 
     32 package org.apache.http.impl.io;
     33 
     34 import java.io.IOException;
     35 import java.util.ArrayList;
     36 
     37 import org.apache.http.Header;
     38 import org.apache.http.HttpException;
     39 import org.apache.http.HttpMessage;
     40 import org.apache.http.ParseException;
     41 import org.apache.http.ProtocolException;
     42 import org.apache.http.io.HttpMessageParser;
     43 import org.apache.http.io.SessionInputBuffer;
     44 import org.apache.http.message.LineParser;
     45 import org.apache.http.message.BasicLineParser;
     46 import org.apache.http.params.CoreConnectionPNames;
     47 import org.apache.http.params.HttpParams;
     48 import org.apache.http.util.CharArrayBuffer;
     49 
     50 /**
     51  * Message parser base class.
     52  *
     53  * @author Michael Becke
     54  * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
     55  */
     56 public abstract class AbstractMessageParser implements HttpMessageParser {
     57 
     58     private final SessionInputBuffer sessionBuffer;
     59     private final int maxHeaderCount;
     60     private final int maxLineLen;
     61     protected final LineParser lineParser;
     62 
     63 
     64     public AbstractMessageParser(
     65             final SessionInputBuffer buffer,
     66             final LineParser parser,
     67             final HttpParams params) {
     68         super();
     69         if (buffer == null) {
     70             throw new IllegalArgumentException("Session input buffer may not be null");
     71         }
     72         if (params == null) {
     73             throw new IllegalArgumentException("HTTP parameters may not be null");
     74         }
     75         this.sessionBuffer = buffer;
     76         this.maxHeaderCount = params.getIntParameter(
     77                 CoreConnectionPNames.MAX_HEADER_COUNT, -1);
     78         this.maxLineLen = params.getIntParameter(
     79                 CoreConnectionPNames.MAX_LINE_LENGTH, -1);
     80         this.lineParser = (parser != null) ? parser : BasicLineParser.DEFAULT;
     81     }
     82 
     83     /**
     84      * Parses HTTP headers from the data receiver stream according to the generic
     85      * format as given in Section 3.1 of RFC 822, RFC-2616 Section 4 and 19.3.
     86      *
     87      * @param inbuffer Session input buffer
     88      * @param maxHeaderCount maximum number of headers allowed. If the number
     89      *  of headers received from the data stream exceeds maxCount value, an
     90      *  IOException will be thrown. Setting this parameter to a negative value
     91      *  or zero  will disable the check.
     92      * @param maxLineLen maximum number of characters for a header line,
     93      *                   including the continuation lines
     94      * @return array of HTTP headers
     95      *
     96      * @throws HttpException
     97      * @throws IOException
     98      */
     99     public static Header[] parseHeaders(
    100             final SessionInputBuffer inbuffer,
    101             int maxHeaderCount,
    102             int maxLineLen,
    103             LineParser parser)
    104         throws HttpException, IOException {
    105 
    106         if (inbuffer == null) {
    107             throw new IllegalArgumentException("Session input buffer may not be null");
    108         }
    109         if (parser == null)
    110             parser = BasicLineParser.DEFAULT;
    111 
    112         ArrayList headerLines = new ArrayList();
    113 
    114         CharArrayBuffer current = null;
    115         CharArrayBuffer previous = null;
    116         for (;;) {
    117             if (current == null) {
    118                 current = new CharArrayBuffer(64);
    119             } else {
    120                 current.clear();
    121             }
    122             int l = inbuffer.readLine(current);
    123             if (l == -1 || current.length() < 1) {
    124                 break;
    125             }
    126             // Parse the header name and value
    127             // Check for folded headers first
    128             // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2
    129             // discussion on folded headers
    130             if ((current.charAt(0) == ' ' || current.charAt(0) == '\t') && previous != null) {
    131                 // we have continuation folded header
    132                 // so append value
    133                 int i = 0;
    134                 while (i < current.length()) {
    135                     char ch = current.charAt(i);
    136                     if (ch != ' ' && ch != '\t') {
    137                         break;
    138                     }
    139                     i++;
    140                 }
    141                 if (maxLineLen > 0
    142                         && previous.length() + 1 + current.length() - i > maxLineLen) {
    143                     throw new IOException("Maximum line length limit exceeded");
    144                 }
    145                 previous.append(' ');
    146                 previous.append(current, i, current.length() - i);
    147             } else {
    148                 headerLines.add(current);
    149                 previous = current;
    150                 current = null;
    151             }
    152             if (maxHeaderCount > 0 && headerLines.size() >= maxHeaderCount) {
    153                 throw new IOException("Maximum header count exceeded");
    154             }
    155         }
    156         Header[] headers = new Header[headerLines.size()];
    157         for (int i = 0; i < headerLines.size(); i++) {
    158             CharArrayBuffer buffer = (CharArrayBuffer) headerLines.get(i);
    159             try {
    160                 headers[i] = parser.parseHeader(buffer);
    161             } catch (ParseException ex) {
    162                 throw new ProtocolException(ex.getMessage());
    163             }
    164         }
    165         return headers;
    166     }
    167 
    168     protected abstract HttpMessage parseHead(SessionInputBuffer sessionBuffer)
    169         throws IOException, HttpException, ParseException;
    170 
    171     public HttpMessage parse() throws IOException, HttpException {
    172         HttpMessage message = null;
    173         try {
    174             message = parseHead(this.sessionBuffer);
    175         } catch (ParseException px) {
    176             throw new ProtocolException(px.getMessage(), px);
    177         }
    178         Header[] headers = AbstractMessageParser.parseHeaders(
    179                 this.sessionBuffer,
    180                 this.maxHeaderCount,
    181                 this.maxLineLen,
    182                 this.lineParser);
    183         message.setHeaders(headers);
    184         return message;
    185     }
    186 
    187 }
    188