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