View Javadoc
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   */
27  
28  package org.apache.hc.core5.http.message;
29  
30  import org.apache.hc.core5.http.Header;
31  import org.apache.hc.core5.http.HttpVersion;
32  import org.apache.hc.core5.http.Method;
33  import org.apache.hc.core5.http.ParseException;
34  import org.apache.hc.core5.http.ProtocolVersion;
35  import org.apache.hc.core5.util.CharArrayBuffer;
36  import org.junit.jupiter.api.Assertions;
37  import org.junit.jupiter.api.BeforeEach;
38  import org.junit.jupiter.api.Test;
39  
40  /**
41   * Tests for {@link BasicLineParser}.
42   *
43   */
44  public class TestBasicLineParser {
45  
46      private BasicLineParser parser;
47  
48      @BeforeEach
49      public void setup() {
50          this.parser = BasicLineParser.INSTANCE;
51      }
52  
53      @Test
54      public void testRLParse() throws Exception {
55          final CharArrayBuffer buf = new CharArrayBuffer(64);
56          //typical request line
57          buf.clear();
58          buf.append("GET /stuff HTTP/1.1");
59          RequestLine requestline = this.parser.parseRequestLine(buf);
60          Assertions.assertEquals("GET /stuff HTTP/1.1", requestline.toString());
61          Assertions.assertEquals(Method.GET.name(), requestline.getMethod());
62          Assertions.assertEquals("/stuff", requestline.getUri());
63          Assertions.assertEquals(HttpVersion.HTTP_1_1, requestline.getProtocolVersion());
64  
65          //Lots of blanks
66          buf.clear();
67          buf.append("  GET    /stuff   HTTP/1.1   ");
68          requestline = this.parser.parseRequestLine(buf);
69          Assertions.assertEquals("GET /stuff HTTP/1.1", requestline.toString());
70          Assertions.assertEquals(Method.GET.name(), requestline.getMethod());
71          Assertions.assertEquals("/stuff", requestline.getUri());
72          Assertions.assertEquals(HttpVersion.HTTP_1_1, requestline.getProtocolVersion());
73  
74          //this is not strictly valid, but is lenient
75          buf.clear();
76          buf.append("\rGET /stuff HTTP/1.1");
77          requestline = this.parser.parseRequestLine(buf);
78          Assertions.assertEquals(Method.GET.name(), requestline.getMethod());
79          Assertions.assertEquals("/stuff", requestline.getUri());
80          Assertions.assertEquals(HttpVersion.HTTP_1_1, requestline.getProtocolVersion());
81      }
82  
83      @Test
84      public void testRLParseFailure() throws Exception {
85          final CharArrayBuffer buf = new CharArrayBuffer(64);
86          buf.clear();
87          buf.append("    ");
88          Assertions.assertThrows(ParseException.class, () -> parser.parseRequestLine(buf));
89          buf.clear();
90          buf.append("  GET");
91          Assertions.assertThrows(ParseException.class, () -> parser.parseRequestLine(buf));
92          buf.clear();
93          buf.append("GET /stuff");
94          Assertions.assertThrows(ParseException.class, () -> parser.parseRequestLine(buf));
95          buf.clear();
96          buf.append("GET/stuff HTTP/1.1");
97          Assertions.assertThrows(ParseException.class, () -> parser.parseRequestLine(buf));
98          buf.clear();
99          buf.append("GET /stuff HTTP/1.1 Oooooooooooppsie");
100         Assertions.assertThrows(ParseException.class, () -> parser.parseRequestLine(buf));
101     }
102 
103     @Test
104     public void testSLParse() throws Exception {
105         final CharArrayBuffer buf = new CharArrayBuffer(64);
106         //typical status line
107         buf.clear();
108         buf.append("HTTP/1.1 200 OK");
109         StatusLine statusLine = this.parser.parseStatusLine(buf);
110         Assertions.assertEquals("HTTP/1.1 200 OK", statusLine.toString());
111         Assertions.assertEquals(HttpVersion.HTTP_1_1, statusLine.getProtocolVersion());
112         Assertions.assertEquals(200, statusLine.getStatusCode());
113         Assertions.assertEquals("OK", statusLine.getReasonPhrase());
114 
115         //status line with multi word reason phrase
116         buf.clear();
117         buf.append("HTTP/1.1 404 Not Found");
118         statusLine = this.parser.parseStatusLine(buf);
119         Assertions.assertEquals(404, statusLine.getStatusCode());
120         Assertions.assertEquals("Not Found", statusLine.getReasonPhrase());
121 
122         //reason phrase can be anyting
123         buf.clear();
124         buf.append("HTTP/1.1 404 Non Trouve");
125         statusLine = this.parser.parseStatusLine(buf);
126         Assertions.assertEquals("Non Trouve", statusLine.getReasonPhrase());
127 
128         //its ok to end with a \n\r
129         buf.clear();
130         buf.append("HTTP/1.1 404 Not Found\r\n");
131         statusLine = this.parser.parseStatusLine(buf);
132         Assertions.assertEquals("Not Found", statusLine.getReasonPhrase());
133 
134         //this is valid according to the Status-Line BNF
135         buf.clear();
136         buf.append("HTTP/1.1 200 ");
137         statusLine = this.parser.parseStatusLine(buf);
138         Assertions.assertEquals(200, statusLine.getStatusCode());
139         Assertions.assertEquals("", statusLine.getReasonPhrase());
140 
141         //this is not strictly valid, but is lenient
142         buf.clear();
143         buf.append("HTTP/1.1 200");
144         statusLine = this.parser.parseStatusLine(buf);
145         Assertions.assertEquals(200, statusLine.getStatusCode());
146         Assertions.assertEquals("", statusLine.getReasonPhrase());
147 
148         //this is not strictly valid, but is lenient
149         buf.clear();
150         buf.append("HTTP/1.1     200 OK");
151         statusLine = this.parser.parseStatusLine(buf);
152         Assertions.assertEquals(200, statusLine.getStatusCode());
153         Assertions.assertEquals("OK", statusLine.getReasonPhrase());
154 
155         //this is not strictly valid, but is lenient
156         buf.clear();
157         buf.append("\nHTTP/1.1 200 OK");
158         statusLine = this.parser.parseStatusLine(buf);
159         Assertions.assertEquals(200, statusLine.getStatusCode());
160         Assertions.assertEquals("OK", statusLine.getReasonPhrase());
161         Assertions.assertEquals(HttpVersion.HTTP_1_1, statusLine.getProtocolVersion());
162 
163         //this is not strictly valid, but is lenient
164         buf.clear();
165         buf.append("  HTTP/1.1 200 OK");
166         statusLine = this.parser.parseStatusLine(buf);
167         Assertions.assertEquals(200, statusLine.getStatusCode());
168         Assertions.assertEquals("OK", statusLine.getReasonPhrase());
169         Assertions.assertEquals(HttpVersion.HTTP_1_1, statusLine.getProtocolVersion());
170     }
171 
172     @Test
173     public void testSLParseFailure() throws Exception {
174         final CharArrayBuffer buf = new CharArrayBuffer(64);
175         buf.clear();
176         buf.append("xxx 200 OK");
177         Assertions.assertThrows(ParseException.class, () -> parser.parseStatusLine(buf));
178         buf.clear();
179         buf.append("HTTP/1.1 xxx OK");
180         Assertions.assertThrows(ParseException.class, () -> parser.parseStatusLine(buf));
181         buf.clear();
182         buf.append("HTTP/1.1    ");
183         Assertions.assertThrows(ParseException.class, () -> parser.parseStatusLine(buf));
184         buf.clear();
185         buf.append("HTTP/1.1");
186         Assertions.assertThrows(ParseException.class, () -> parser.parseStatusLine(buf));
187         buf.clear();
188         buf.append("HTTP/1.1 -200 OK");
189         Assertions.assertThrows(ParseException.class, () -> parser.parseStatusLine(buf));
190         buf.clear();
191         buf.append("HTTP/1.1 0200 OK");
192         Assertions.assertThrows(ParseException.class, () -> parser.parseStatusLine(buf));
193         buf.clear();
194         buf.append("HTTP/1.1 2000 OK");
195         Assertions.assertThrows(ParseException.class, () -> parser.parseStatusLine(buf));
196     }
197 
198     @Test
199     public void testHttpVersionParsing() throws Exception {
200         final CharArrayBuffer buffer = new CharArrayBuffer(16);
201         buffer.append("HTTP/1.1");
202         final ParserCursor cursor = new ParserCursor(0, buffer.length());
203 
204         final ProtocolVersion version = parser.parseProtocolVersion(buffer, cursor);
205         Assertions.assertEquals("HTTP", version.getProtocol(), "HTTP protocol name");
206         Assertions.assertEquals(1, version.getMajor(), "HTTP major version number");
207         Assertions.assertEquals(1, version.getMinor(), "HTTP minor version number");
208         Assertions.assertEquals("HTTP/1.1", version.toString(), "HTTP version number");
209         Assertions.assertEquals(buffer.length(), cursor.getPos());
210         Assertions.assertTrue(cursor.atEnd());
211 
212         buffer.clear();
213         buffer.append("HTTP/1.123 123");
214         final ParserCursor cursor2 = new ParserCursor(0, buffer.length());
215 
216         final ProtocolVersion version2 = parser.parseProtocolVersion(buffer, cursor2);
217         Assertions.assertEquals( "HTTP", version2.getProtocol(), "HTTP protocol name");
218         Assertions.assertEquals( 1, version2.getMajor(), "HTTP major version number");
219         Assertions.assertEquals(123, version2.getMinor(), "HTTP minor version number");
220         Assertions.assertEquals("HTTP/1.123", version2.toString(), "HTTP version number");
221         Assertions.assertEquals(' ', buffer.charAt(cursor2.getPos()));
222         Assertions.assertEquals(buffer.length() - 4, cursor2.getPos());
223         Assertions.assertFalse(cursor2.atEnd());
224     }
225 
226     @Test
227     public void testInvalidHttpVersionParsing() throws Exception {
228         final CharArrayBuffer buffer = new CharArrayBuffer(16);
229         buffer.clear();
230         buffer.append("    ");
231         final ParserCursor cursor1 = new ParserCursor(0, buffer.length());
232         Assertions.assertThrows(ParseException.class, () ->
233                 parser.parseProtocolVersion(buffer, cursor1));
234         buffer.clear();
235         buffer.append("HTT");
236         final ParserCursor cursor2 = new ParserCursor(0, buffer.length());
237         Assertions.assertThrows(ParseException.class, () ->
238                 parser.parseProtocolVersion(buffer, cursor2));
239         buffer.clear();
240         buffer.append("crap");
241         final ParserCursor cursor3 = new ParserCursor(0, buffer.length());
242         Assertions.assertThrows(ParseException.class, () ->
243                 parser.parseProtocolVersion(buffer, cursor3));
244         buffer.clear();
245         buffer.append("HTTP/crap");
246         final ParserCursor cursor4 = new ParserCursor(0, buffer.length());
247         Assertions.assertThrows(ParseException.class, () ->
248                 parser.parseProtocolVersion(buffer, cursor4));
249         buffer.clear();
250         buffer.append("HTTP/1");
251         final ParserCursor cursor5 = new ParserCursor(0, buffer.length());
252         Assertions.assertThrows(ParseException.class, () ->
253                 parser.parseProtocolVersion(buffer, cursor5));
254         buffer.clear();
255         buffer.append("HTTP/1.");
256         final ParserCursor cursor7 = new ParserCursor(0, buffer.length());
257         Assertions.assertThrows(ParseException.class, () ->
258                 parser.parseProtocolVersion(buffer, cursor7));
259         buffer.clear();
260         buffer.append("HTTP/whatever.whatever whatever");
261         final ParserCursor cursor8 = new ParserCursor(0, buffer.length());
262         Assertions.assertThrows(ParseException.class, () ->
263                 parser.parseProtocolVersion(buffer, cursor8));
264         buffer.clear();
265         buffer.append("HTTP/1.whatever whatever");
266         final ParserCursor cursor9 = new ParserCursor(0, buffer.length());
267         Assertions.assertThrows(ParseException.class, () ->
268                 parser.parseProtocolVersion(buffer, cursor9));
269     }
270 
271     @Test
272     public void testHeaderParse() throws Exception {
273         final CharArrayBuffer buf = new CharArrayBuffer(64);
274         //typical request line
275         buf.clear();
276         buf.append("header: blah");
277         Header header = this.parser.parseHeader(buf);
278         Assertions.assertEquals("header", header.getName());
279         Assertions.assertEquals("blah", header.getValue());
280 
281         //Lots of blanks
282         buf.clear();
283         buf.append("    header:    blah    ");
284         header = this.parser.parseHeader(buf);
285         Assertions.assertEquals("header", header.getName());
286         Assertions.assertEquals("blah", header.getValue());
287     }
288 
289     @Test
290     public void testInvalidHeaderParsing() throws Exception {
291         final CharArrayBuffer buffer = new CharArrayBuffer(16);
292         buffer.clear();
293         buffer.append("");
294         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
295         buffer.clear();
296         buffer.append("blah");
297         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
298         buffer.clear();
299         buffer.append(":");
300         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
301         buffer.clear();
302         buffer.append("   :");
303         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
304         buffer.clear();
305         buffer.append(": blah");
306         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
307         buffer.clear();
308         buffer.append(" : blah");
309         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
310         buffer.clear();
311         buffer.append("header : blah");
312         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
313     }
314 
315 }