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     }
190 
191     @Test
192     public void testHttpVersionParsing() throws Exception {
193         final CharArrayBuffer buffer = new CharArrayBuffer(16);
194         buffer.append("HTTP/1.1");
195         ParserCursor cursor = new ParserCursor(0, buffer.length());
196 
197         HttpVersion version = (HttpVersion) parser.parseProtocolVersion(buffer, cursor);
198         Assertions.assertEquals("HTTP", version.getProtocol(), "HTTP protocol name");
199         Assertions.assertEquals(1, version.getMajor(), "HTTP major version number");
200         Assertions.assertEquals(1, version.getMinor(), "HTTP minor version number");
201         Assertions.assertEquals("HTTP/1.1", version.toString(), "HTTP version number");
202         Assertions.assertEquals(buffer.length(), cursor.getPos());
203         Assertions.assertTrue(cursor.atEnd());
204 
205         buffer.clear();
206         buffer.append("HTTP/1.123 123");
207         cursor = new ParserCursor(0, buffer.length());
208 
209         version = (HttpVersion) parser.parseProtocolVersion(buffer, cursor);
210         Assertions.assertEquals( "HTTP", version.getProtocol(), "HTTP protocol name");
211         Assertions.assertEquals( 1, version.getMajor(), "HTTP major version number");
212         Assertions.assertEquals(123, version.getMinor(), "HTTP minor version number");
213         Assertions.assertEquals("HTTP/1.123", version.toString(), "HTTP version number");
214         Assertions.assertEquals(' ', buffer.charAt(cursor.getPos()));
215         Assertions.assertEquals(buffer.length() - 4, cursor.getPos());
216         Assertions.assertFalse(cursor.atEnd());
217     }
218 
219     @Test
220     public void testInvalidHttpVersionParsing() throws Exception {
221         final CharArrayBuffer buffer = new CharArrayBuffer(16);
222         buffer.clear();
223         buffer.append("    ");
224         final ParserCursor cursor1 = new ParserCursor(0, buffer.length());
225         Assertions.assertThrows(ParseException.class, () ->
226                 parser.parseProtocolVersion(buffer, cursor1));
227         buffer.clear();
228         buffer.append("HTT");
229         final ParserCursor cursor2 = new ParserCursor(0, buffer.length());
230         Assertions.assertThrows(ParseException.class, () ->
231                 parser.parseProtocolVersion(buffer, cursor2));
232         buffer.clear();
233         buffer.append("crap");
234         final ParserCursor cursor3 = new ParserCursor(0, buffer.length());
235         Assertions.assertThrows(ParseException.class, () ->
236                 parser.parseProtocolVersion(buffer, cursor3));
237         buffer.clear();
238         buffer.append("HTTP/crap");
239         final ParserCursor cursor4 = new ParserCursor(0, buffer.length());
240         Assertions.assertThrows(ParseException.class, () ->
241                 parser.parseProtocolVersion(buffer, cursor4));
242         buffer.clear();
243         buffer.append("HTTP/1");
244         final ParserCursor cursor5 = new ParserCursor(0, buffer.length());
245         Assertions.assertThrows(ParseException.class, () ->
246                 parser.parseProtocolVersion(buffer, cursor5));
247         buffer.clear();
248         buffer.append("HTTP/1234");
249         final ParserCursor cursor6 = new ParserCursor(0, buffer.length());
250         Assertions.assertThrows(ParseException.class, () ->
251                 parser.parseProtocolVersion(buffer, cursor6));
252         buffer.clear();
253         buffer.append("HTTP/1.");
254         final ParserCursor cursor7 = new ParserCursor(0, buffer.length());
255         Assertions.assertThrows(ParseException.class, () ->
256                 parser.parseProtocolVersion(buffer, cursor7));
257         buffer.clear();
258         buffer.append("HTTP/whatever.whatever whatever");
259         final ParserCursor cursor8 = new ParserCursor(0, buffer.length());
260         Assertions.assertThrows(ParseException.class, () ->
261                 parser.parseProtocolVersion(buffer, cursor8));
262         buffer.clear();
263         buffer.append("HTTP/1.whatever whatever");
264         final ParserCursor cursor9 = new ParserCursor(0, buffer.length());
265         Assertions.assertThrows(ParseException.class, () ->
266                 parser.parseProtocolVersion(buffer, cursor9));
267     }
268 
269     @Test
270     public void testHeaderParse() throws Exception {
271         final CharArrayBuffer buf = new CharArrayBuffer(64);
272         //typical request line
273         buf.clear();
274         buf.append("header: blah");
275         Header header = this.parser.parseHeader(buf);
276         Assertions.assertEquals("header", header.getName());
277         Assertions.assertEquals("blah", header.getValue());
278 
279         //Lots of blanks
280         buf.clear();
281         buf.append("    header:    blah    ");
282         header = this.parser.parseHeader(buf);
283         Assertions.assertEquals("header", header.getName());
284         Assertions.assertEquals("blah", header.getValue());
285     }
286 
287     @Test
288     public void testInvalidHeaderParsing() throws Exception {
289         final CharArrayBuffer buffer = new CharArrayBuffer(16);
290         buffer.clear();
291         buffer.append("");
292         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
293         buffer.clear();
294         buffer.append("blah");
295         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
296         buffer.clear();
297         buffer.append(":");
298         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
299         buffer.clear();
300         buffer.append("   :");
301         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
302         buffer.clear();
303         buffer.append(": blah");
304         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
305         buffer.clear();
306         buffer.append(" : blah");
307         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
308         buffer.clear();
309         buffer.append("header : blah");
310         Assertions.assertThrows(ParseException.class, () -> parser.parseHeader(buffer));
311     }
312 
313 }