1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.impl.nio.codecs;
29
30 import java.io.IOException;
31 import java.nio.channels.ReadableByteChannel;
32 import java.util.ArrayList;
33 import java.util.List;
34
35 import org.apache.http.HttpException;
36 import org.apache.http.HttpMessage;
37 import org.apache.http.ParseException;
38 import org.apache.http.ProtocolException;
39 import org.apache.http.annotation.NotThreadSafe;
40 import org.apache.http.message.LineParser;
41 import org.apache.http.message.BasicLineParser;
42 import org.apache.http.nio.NHttpMessageParser;
43 import org.apache.http.nio.reactor.SessionInputBuffer;
44 import org.apache.http.params.CoreConnectionPNames;
45 import org.apache.http.params.HttpParams;
46 import org.apache.http.util.CharArrayBuffer;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 @NotThreadSafe
62 public abstract class AbstractMessageParser<T extends HttpMessage> implements NHttpMessageParser<T> {
63
64 private final SessionInputBuffer sessionBuffer;
65
66 private static final int READ_HEAD_LINE = 0;
67 private static final int READ_HEADERS = 1;
68 private static final int COMPLETED = 2;
69
70 private int state;
71 private boolean endOfStream;
72
73 private T message;
74 private CharArrayBuffer lineBuf;
75 private final List<CharArrayBuffer> headerBufs;
76
77 private int maxLineLen = -1;
78 private int maxHeaderCount = -1;
79 protected final LineParser lineParser;
80
81
82
83
84
85
86
87
88 public AbstractMessageParser(final SessionInputBuffer buffer, final LineParser parser, final HttpParams params) {
89 super();
90 if (buffer == null) {
91 throw new IllegalArgumentException("Session input buffer may not be null");
92 }
93 if (params == null) {
94 throw new IllegalArgumentException("HTTP parameters may not be null");
95 }
96 this.sessionBuffer = buffer;
97 this.state = READ_HEAD_LINE;
98 this.endOfStream = false;
99 this.headerBufs = new ArrayList<CharArrayBuffer>();
100 this.maxLineLen = params.getIntParameter(
101 CoreConnectionPNames.MAX_LINE_LENGTH, -1);
102 this.maxHeaderCount = params.getIntParameter(
103 CoreConnectionPNames.MAX_HEADER_COUNT, -1);
104 this.lineParser = (parser != null) ? parser : BasicLineParser.DEFAULT;
105 }
106
107 public void reset() {
108 this.state = READ_HEAD_LINE;
109 this.endOfStream = false;
110 this.headerBufs.clear();
111 this.message = null;
112 }
113
114 public int fillBuffer(final ReadableByteChannel channel) throws IOException {
115 int bytesRead = this.sessionBuffer.fill(channel);
116 if (bytesRead == -1) {
117 this.endOfStream = true;
118 }
119 return bytesRead;
120 }
121
122
123
124
125
126
127
128
129
130
131 protected abstract T createMessage(CharArrayBuffer buffer)
132 throws HttpException, ParseException;
133
134 private void parseHeadLine() throws HttpException, ParseException {
135 this.message = createMessage(this.lineBuf);
136 }
137
138 private void parseHeader() throws IOException {
139 CharArrayBuffer current = this.lineBuf;
140 int count = this.headerBufs.size();
141 if ((this.lineBuf.charAt(0) == ' ' || this.lineBuf.charAt(0) == '\t') && count > 0) {
142
143 CharArrayBuffer previous = this.headerBufs.get(count - 1);
144 int i = 0;
145 while (i < current.length()) {
146 char ch = current.charAt(i);
147 if (ch != ' ' && ch != '\t') {
148 break;
149 }
150 i++;
151 }
152 if (this.maxLineLen > 0
153 && previous.length() + 1 + current.length() - i > this.maxLineLen) {
154 throw new IOException("Maximum line length limit exceeded");
155 }
156 previous.append(' ');
157 previous.append(current, i, current.length() - i);
158 } else {
159 this.headerBufs.add(current);
160 this.lineBuf = null;
161 }
162 }
163
164 public T parse() throws IOException, HttpException {
165 while (this.state != COMPLETED) {
166 if (this.lineBuf == null) {
167 this.lineBuf = new CharArrayBuffer(64);
168 } else {
169 this.lineBuf.clear();
170 }
171 boolean lineComplete = this.sessionBuffer.readLine(this.lineBuf, this.endOfStream);
172 if (this.maxLineLen > 0 &&
173 (this.lineBuf.length() > this.maxLineLen ||
174 (!lineComplete && this.sessionBuffer.length() > this.maxLineLen))) {
175 throw new IOException("Maximum line length limit exceeded");
176 }
177 if (!lineComplete) {
178 break;
179 }
180
181 switch (this.state) {
182 case READ_HEAD_LINE:
183 try {
184 parseHeadLine();
185 } catch (ParseException px) {
186 throw new ProtocolException(px.getMessage(), px);
187 }
188 this.state = READ_HEADERS;
189 break;
190 case READ_HEADERS:
191 if (this.lineBuf.length() > 0) {
192 if (this.maxHeaderCount > 0 && headerBufs.size() >= this.maxHeaderCount) {
193 throw new IOException("Maximum header count exceeded");
194 }
195
196 parseHeader();
197 } else {
198 this.state = COMPLETED;
199 }
200 break;
201 }
202 if (this.endOfStream && !this.sessionBuffer.hasData()) {
203 this.state = COMPLETED;
204 }
205 }
206 if (this.state == COMPLETED) {
207 for (int i = 0; i < this.headerBufs.size(); i++) {
208 CharArrayBuffer buffer = this.headerBufs.get(i);
209 try {
210 this.message.addHeader(lineParser.parseHeader(buffer));
211 } catch (ParseException ex) {
212 throw new ProtocolException(ex.getMessage(), ex);
213 }
214 }
215 return this.message;
216 } else {
217 return null;
218 }
219 }
220
221 }