001: /*
002: * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/httpcore/tags/4.0-beta1/module-main/src/main/java/org/apache/http/impl/io/AbstractMessageParser.java $
003: * $Revision: 576077 $
004: * $Date: 2007-09-16 13:50:22 +0200 (Sun, 16 Sep 2007) $
005: *
006: * ====================================================================
007: * Licensed to the Apache Software Foundation (ASF) under one
008: * or more contributor license agreements. See the NOTICE file
009: * distributed with this work for additional information
010: * regarding copyright ownership. The ASF licenses this file
011: * to you under the Apache License, Version 2.0 (the
012: * "License"); you may not use this file except in compliance
013: * with the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing,
018: * software distributed under the License is distributed on an
019: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020: * KIND, either express or implied. See the License for the
021: * specific language governing permissions and limitations
022: * under the License.
023: * ====================================================================
024: *
025: * This software consists of voluntary contributions made by many
026: * individuals on behalf of the Apache Software Foundation. For more
027: * information on the Apache Software Foundation, please see
028: * <http://www.apache.org/>.
029: *
030: */
031:
032: package org.apache.http.impl.io;
033:
034: import java.io.IOException;
035: import java.util.ArrayList;
036:
037: import org.apache.http.Header;
038: import org.apache.http.HttpException;
039: import org.apache.http.HttpMessage;
040: import org.apache.http.ParseException;
041: import org.apache.http.ProtocolException;
042: import org.apache.http.io.HttpMessageParser;
043: import org.apache.http.io.SessionInputBuffer;
044: import org.apache.http.message.LineParser;
045: import org.apache.http.message.BasicLineParser;
046: import org.apache.http.params.CoreConnectionPNames;
047: import org.apache.http.params.HttpParams;
048: import org.apache.http.util.CharArrayBuffer;
049:
050: /**
051: * Message parser base class.
052: *
053: * @author Michael Becke
054: * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
055: */
056: public abstract class AbstractMessageParser implements
057: HttpMessageParser {
058:
059: private final SessionInputBuffer sessionBuffer;
060: private final int maxHeaderCount;
061: private final int maxLineLen;
062: protected final LineParser lineParser;
063:
064: public AbstractMessageParser(final SessionInputBuffer buffer,
065: final LineParser parser, final HttpParams params) {
066: super ();
067: if (buffer == null) {
068: throw new IllegalArgumentException(
069: "Session input buffer may not be null");
070: }
071: if (params == null) {
072: throw new IllegalArgumentException(
073: "HTTP parameters may not be null");
074: }
075: this .sessionBuffer = buffer;
076: this .maxHeaderCount = params.getIntParameter(
077: CoreConnectionPNames.MAX_HEADER_COUNT, -1);
078: this .maxLineLen = params.getIntParameter(
079: CoreConnectionPNames.MAX_LINE_LENGTH, -1);
080: this .lineParser = (parser != null) ? parser
081: : BasicLineParser.DEFAULT;
082: }
083:
084: /**
085: * Parses HTTP headers from the data receiver stream according to the generic
086: * format as given in Section 3.1 of RFC 822, RFC-2616 Section 4 and 19.3.
087: *
088: * @param inbuffer Session input buffer
089: * @param maxHeaderCount maximum number of headers allowed. If the number
090: * of headers received from the data stream exceeds maxCount value, an
091: * IOException will be thrown. Setting this parameter to a negative value
092: * or zero will disable the check.
093: * @param maxLineLen maximum number of characters for a header line,
094: * including the continuation lines
095: * @return array of HTTP headers
096: *
097: * @throws HttpException
098: * @throws IOException
099: */
100: public static Header[] parseHeaders(
101: final SessionInputBuffer inbuffer, int maxHeaderCount,
102: int maxLineLen, LineParser parser) throws HttpException,
103: IOException {
104:
105: if (inbuffer == null) {
106: throw new IllegalArgumentException(
107: "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')
131: && previous != null) {
132: // we have continuation folded header
133: // so append value
134: int i = 0;
135: while (i < current.length()) {
136: char ch = current.charAt(i);
137: if (ch != ' ' && ch != '\t') {
138: break;
139: }
140: i++;
141: }
142: if (maxLineLen > 0
143: && previous.length() + 1 + current.length() - i > maxLineLen) {
144: throw new IOException(
145: "Maximum line length limit exceeded");
146: }
147: previous.append(' ');
148: previous.append(current, i, current.length() - i);
149: } else {
150: headerLines.add(current);
151: previous = current;
152: current = null;
153: }
154: if (maxHeaderCount > 0
155: && headerLines.size() >= maxHeaderCount) {
156: throw new IOException("Maximum header count exceeded");
157: }
158: }
159: Header[] headers = new Header[headerLines.size()];
160: for (int i = 0; i < headerLines.size(); i++) {
161: CharArrayBuffer buffer = (CharArrayBuffer) headerLines
162: .get(i);
163: try {
164: headers[i] = parser.parseHeader(buffer);
165: } catch (ParseException ex) {
166: throw new ProtocolException(ex.getMessage());
167: }
168: }
169: return headers;
170: }
171:
172: protected abstract HttpMessage parseHead(
173: SessionInputBuffer sessionBuffer) throws IOException,
174: HttpException, ParseException;
175:
176: public HttpMessage parse() throws IOException, HttpException {
177: HttpMessage message = null;
178: try {
179: message = parseHead(this .sessionBuffer);
180: } catch (ParseException px) {
181: throw new ProtocolException(px.getMessage(), px);
182: }
183: Header[] headers = AbstractMessageParser.parseHeaders(
184: this.sessionBuffer, this.maxHeaderCount,
185: this.maxLineLen, this.lineParser);
186: message.setHeaders(headers);
187: return message;
188: }
189:
190: }
|