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