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