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.http2.impl;
29  
30  import java.util.Arrays;
31  import java.util.List;
32  
33  import org.apache.hc.core5.http.Header;
34  import org.apache.hc.core5.http.HttpException;
35  import org.apache.hc.core5.http.HttpHost;
36  import org.apache.hc.core5.http.HttpRequest;
37  import org.apache.hc.core5.http.message.BasicHeader;
38  import org.apache.hc.core5.http.message.BasicHttpRequest;
39  import org.apache.hc.core5.net.URIAuthority;
40  import org.junit.Assert;
41  import org.junit.Rule;
42  import org.junit.Test;
43  import org.junit.rules.ExpectedException;
44  
45  public class TestDefaultH2RequestConverter {
46  
47      @Rule
48      public ExpectedException thrown = ExpectedException.none();
49  
50      @Test
51      public void testConvertFromFieldsBasic() throws Exception {
52  
53          final List<Header> headers = Arrays.<Header>asList(
54                  new BasicHeader(":method", "GET"),
55                  new BasicHeader(":scheme", "http"),
56                  new BasicHeader(":authority", "www.example.com"),
57                  new BasicHeader(":path", "/"),
58                  new BasicHeader("custom123", "value"));
59  
60          final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
61          final HttpRequest request = converter.convert(headers);
62          Assert.assertNotNull(request);
63          Assert.assertEquals("GET", request.getMethod());
64          Assert.assertEquals("http", request.getScheme());
65          Assert.assertEquals(new URIAuthority("www.example.com"), request.getAuthority());
66          Assert.assertEquals("/", request.getPath());
67          final Header[] allHeaders = request.getHeaders();
68          Assert.assertEquals(1, allHeaders.length);
69          Assert.assertEquals("custom123", allHeaders[0].getName());
70          Assert.assertEquals("value", allHeaders[0].getValue());
71      }
72  
73      @Test
74      public void testConvertFromFieldsUpperCaseHeaderName() throws Exception {
75  
76          thrown.expect(HttpException.class);
77          thrown.expectMessage("Header name ':Path' is invalid (header name contains uppercase characters)");
78  
79          final List<Header> headers = Arrays.<Header>asList(
80                  new BasicHeader(":method", "GET"),
81                  new BasicHeader(":scheme", "http"),
82                  new BasicHeader(":authority", "www.example.com"),
83                  new BasicHeader(":Path", "/"),
84                  new BasicHeader("custom", "value"));
85  
86          final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
87          converter.convert(headers);
88      }
89  
90      @Test
91      public void testConvertFromFieldsConnectionHeader() throws Exception {
92  
93          thrown.expect(HttpException.class);
94          thrown.expectMessage("Header 'connection: keep-alive' is illegal for HTTP/2 messages");
95  
96          final List<Header> headers = Arrays.<Header>asList(
97                  new BasicHeader(":method", "GET"),
98                  new BasicHeader(":scheme", "http"),
99                  new BasicHeader(":authority", "www.example.com"),
100                 new BasicHeader(":path", "/"),
101                 new BasicHeader("connection", "keep-alive"));
102 
103         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
104         converter.convert(headers);
105     }
106 
107     @Test
108     public void testConvertFromFieldsPseudoHeaderSequence() throws Exception {
109 
110         thrown.expect(HttpException.class);
111         thrown.expectMessage("Invalid sequence of headers (pseudo-headers must precede message headers)");
112 
113         final List<Header> headers = Arrays.<Header>asList(
114                 new BasicHeader(":method", "GET"),
115                 new BasicHeader(":scheme", "http"),
116                 new BasicHeader("custom", "value"),
117                 new BasicHeader(":authority", "www.example.com"),
118                 new BasicHeader(":path", "/"));
119 
120         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
121         converter.convert(headers);
122     }
123 
124     @Test
125     public void testConvertFromFieldsMissingMethod() throws Exception {
126 
127         thrown.expect(HttpException.class);
128         thrown.expectMessage("Mandatory request header ':method' not found");
129 
130         final List<Header> headers = Arrays.<Header>asList(
131                 new BasicHeader(":scheme", "http"),
132                 new BasicHeader(":authority", "www.example.com"),
133                 new BasicHeader(":path", "/"),
134                 new BasicHeader("custom", "value"));
135 
136         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
137         converter.convert(headers);
138     }
139 
140     @Test
141     public void testConvertFromFieldsMissingScheme() throws Exception {
142 
143         thrown.expect(HttpException.class);
144         thrown.expectMessage("Mandatory request header ':scheme' not found");
145 
146         final List<Header> headers = Arrays.<Header>asList(
147                 new BasicHeader(":method", "GET"),
148                 new BasicHeader(":authority", "www.example.com"),
149                 new BasicHeader(":path", "/"),
150                 new BasicHeader("custom", "value"));
151 
152         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
153         converter.convert(headers);
154     }
155 
156     @Test
157     public void testConvertFromFieldsMissingPath() throws Exception {
158 
159         thrown.expect(HttpException.class);
160         thrown.expectMessage("Mandatory request header ':path' not found");
161 
162         final List<Header> headers = Arrays.<Header>asList(
163                 new BasicHeader(":method", "GET"),
164                 new BasicHeader(":scheme", "http"),
165                 new BasicHeader(":authority", "www.example.com"),
166                 new BasicHeader("custom", "value"));
167 
168         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
169         converter.convert(headers);
170     }
171 
172     @Test
173     public void testConvertFromFieldsUnknownPseudoHeader() throws Exception {
174 
175         thrown.expect(HttpException.class);
176         thrown.expectMessage("Unsupported request header ':custom'");
177 
178         final List<Header> headers = Arrays.<Header>asList(
179                 new BasicHeader(":method", "GET"),
180                 new BasicHeader(":scheme", "http"),
181                 new BasicHeader(":authority", "www.example.com"),
182                 new BasicHeader(":path", "/"),
183                 new BasicHeader(":custom", "value"));
184 
185         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
186         converter.convert(headers);
187     }
188 
189     @Test
190     public void testConvertFromFieldsMultipleMethod() throws Exception {
191 
192         thrown.expect(HttpException.class);
193         thrown.expectMessage("Multiple ':method' request headers are illegal");
194 
195         final List<Header> headers = Arrays.<Header>asList(
196                 new BasicHeader(":method", "GET"),
197                 new BasicHeader(":method", "GET"),
198                 new BasicHeader(":scheme", "http"),
199                 new BasicHeader(":authority", "www.example.com"),
200                 new BasicHeader(":path", "/"),
201                 new BasicHeader("custom", "value"));
202 
203         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
204         converter.convert(headers);
205     }
206 
207     @Test
208     public void testConvertFromFieldsMultipleScheme() throws Exception {
209 
210         thrown.expect(HttpException.class);
211         thrown.expectMessage("Multiple ':scheme' request headers are illegal");
212 
213         final List<Header> headers = Arrays.<Header>asList(
214                 new BasicHeader(":method", "GET"),
215                 new BasicHeader(":scheme", "http"),
216                 new BasicHeader(":scheme", "https"),
217                 new BasicHeader(":authority", "www.example.com"),
218                 new BasicHeader(":path", "/"),
219                 new BasicHeader("custom", "value"));
220 
221         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
222         converter.convert(headers);
223     }
224 
225     @Test
226     public void testConvertFromFieldsMultiplePath() throws Exception {
227 
228         thrown.expect(HttpException.class);
229         thrown.expectMessage("Multiple ':path' request headers are illegal");
230 
231         final List<Header> headers = Arrays.<Header>asList(
232                 new BasicHeader(":method", "GET"),
233                 new BasicHeader(":scheme", "https"),
234                 new BasicHeader(":authority", "www.example.com"),
235                 new BasicHeader(":path", "/"),
236                 new BasicHeader(":path", "/"),
237                 new BasicHeader("custom", "value"));
238 
239         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
240         converter.convert(headers);
241     }
242 
243     @Test
244     public void testConvertFromFieldsConnect() throws Exception {
245 
246         final List<Header> headers = Arrays.<Header>asList(
247                 new BasicHeader(":method", "CONNECT"),
248                 new BasicHeader(":authority", "www.example.com"),
249                 new BasicHeader("custom", "value"));
250 
251         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
252         converter.convert(headers);
253     }
254 
255     @Test
256     public void testConvertFromFieldsConnectMissingAuthority() throws Exception {
257 
258         thrown.expect(HttpException.class);
259         thrown.expectMessage("Header ':authority' is mandatory for CONNECT request");
260 
261         final List<Header> headers = Arrays.<Header>asList(
262                 new BasicHeader(":method", "CONNECT"),
263                 new BasicHeader("custom", "value"));
264 
265         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
266         converter.convert(headers);
267     }
268 
269     @Test
270     public void testConvertFromFieldsConnectPresentScheme() throws Exception {
271 
272         thrown.expect(HttpException.class);
273         thrown.expectMessage("Header ':scheme' must not be set for CONNECT request");
274 
275         final List<Header> headers = Arrays.<Header>asList(
276                 new BasicHeader(":method", "CONNECT"),
277                 new BasicHeader(":scheme", "http"),
278                 new BasicHeader(":authority", "www.example.com"),
279                 new BasicHeader("custom", "value"));
280 
281         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
282         converter.convert(headers);
283     }
284 
285     @Test
286     public void testConvertFromFieldsConnectPresentPath() throws Exception {
287 
288         thrown.expect(HttpException.class);
289         thrown.expectMessage("Header ':path' must not be set for CONNECT request");
290 
291         final List<Header> headers = Arrays.<Header>asList(
292                 new BasicHeader(":method", "CONNECT"),
293                 new BasicHeader(":authority", "www.example.com"),
294                 new BasicHeader(":path", "/"),
295                 new BasicHeader("custom", "value"));
296 
297         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
298         converter.convert(headers);
299     }
300 
301     @Test
302     public void testConvertFromMessageBasic() throws Exception {
303 
304         final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
305         request.addHeader("custom123", "Value");
306 
307         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
308         final List<Header> headers = converter.convert(request);
309 
310         Assert.assertNotNull(headers);
311         Assert.assertEquals(5, headers.size());
312         final Header header1 = headers.get(0);
313         Assert.assertEquals(":method", header1.getName());
314         Assert.assertEquals("GET", header1.getValue());
315         final Header header2 = headers.get(1);
316         Assert.assertEquals(":scheme", header2.getName());
317         Assert.assertEquals("http", header2.getValue());
318         final Header header3 = headers.get(2);
319         Assert.assertEquals(":authority", header3.getName());
320         Assert.assertEquals("host", header3.getValue());
321         final Header header4 = headers.get(3);
322         Assert.assertEquals(":path", header4.getName());
323         Assert.assertEquals("/", header4.getValue());
324         final Header header5 = headers.get(4);
325         Assert.assertEquals("custom123", header5.getName());
326         Assert.assertEquals("Value", header5.getValue());
327     }
328 
329     @Test
330     public void testConvertFromMessageMissingScheme() throws Exception {
331 
332         thrown.expect(HttpException.class);
333         thrown.expectMessage("Request scheme is not set");
334 
335         final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
336         request.addHeader("Custom123", "Value");
337         request.setScheme(null);
338 
339         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
340         converter.convert(request);
341     }
342 
343     @Test
344     public void testConvertFromMessageMissingPath() throws Exception {
345 
346         thrown.expect(HttpException.class);
347         thrown.expectMessage("Request path is not set");
348 
349         final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
350         request.addHeader("Custom123", "Value");
351         request.setPath(null);
352 
353         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
354         converter.convert(request);
355     }
356 
357     @Test
358     public void testConvertFromMessageConnect() throws Exception {
359 
360         final HttpRequest request = new BasicHttpRequest("CONNECT", new HttpHost("host:80"), null);
361         request.addHeader("custom123", "Value");
362 
363         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
364         final List<Header> headers = converter.convert(request);
365 
366         Assert.assertNotNull(headers);
367         Assert.assertEquals(3, headers.size());
368         final Header header1 = headers.get(0);
369         Assert.assertEquals(":method", header1.getName());
370         Assert.assertEquals("CONNECT", header1.getValue());
371         final Header header2 = headers.get(1);
372         Assert.assertEquals(":authority", header2.getName());
373         Assert.assertEquals("host:80", header2.getValue());
374         final Header header3 = headers.get(2);
375         Assert.assertEquals("custom123", header3.getName());
376         Assert.assertEquals("Value", header3.getValue());
377     }
378 
379     @Test
380     public void testConvertFromMessageConnectMissingAuthority() throws Exception {
381 
382         thrown.expect(HttpException.class);
383         thrown.expectMessage("CONNECT request authority is not set");
384 
385         final HttpRequest request = new BasicHttpRequest("CONNECT", null, null);
386         request.addHeader("Custom123", "Value");
387 
388         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
389         converter.convert(request);
390     }
391 
392     @Test
393     public void testConvertFromMessageConnectWithPath() throws Exception {
394 
395         thrown.expect(HttpException.class);
396         thrown.expectMessage("CONNECT request path must be null");
397 
398         final HttpRequest request = new BasicHttpRequest("CONNECT", "/");
399         request.setAuthority(new URIAuthority("host"));
400         request.addHeader("Custom123", "Value");
401 
402         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
403         converter.convert(request);
404     }
405 
406     @Test
407     public void testConvertFromMessageConnectionHeader() throws Exception {
408 
409         thrown.expect(HttpException.class);
410         thrown.expectMessage("Header 'Connection: Keep-Alive' is illegal for HTTP/2 messages");
411 
412         final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
413         request.addHeader("Connection", "Keep-Alive");
414 
415         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
416         converter.convert(request);
417     }
418 
419     @Test
420     public void testConvertFromMessageInvalidHeader() throws Exception {
421 
422         thrown.expect(HttpException.class);
423         thrown.expectMessage("Header name ':custom' is invalid");
424 
425         final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
426         request.addHeader(":custom", "stuff");
427 
428         final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
429         converter.convert(request);
430     }
431 
432 }
433