1 /** @file
2 
3     Unit tests for HTTP2
4 
5     @section license License
6 
7     Licensed to the Apache Software Foundation (ASF) under one
8     or more contributor license agreements.  See the NOTICE file
9     distributed with this work for additional information
10     regarding copyright ownership.  The ASF licenses this file
11     to you under the Apache License, Version 2.0 (the
12     "License"); you may not use this file except in compliance
13     with the License.  You may obtain a copy of the License at
14 
15     http://www.apache.org/licenses/LICENSE-2.0
16 
17     Unless required by applicable law or agreed to in writing, software
18     distributed under the License is distributed on an "AS IS" BASIS,
19     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20     See the License for the specific language governing permissions and
21     limitations under the License.
22 */
23 
24 #include "catch.hpp"
25 
26 #include "HTTP2.h"
27 
28 #include "tscpp/util/PostScript.h"
29 
30 TEST_CASE("Convert HTTPHdr", "[HTTP2]")
31 {
32   url_init();
33   mime_init();
34   http_init();
35   http2_init();
36 
37   HTTPParser parser;
__anon6d3b2ca40102() 38   ts::PostScript parser_defer([&]() -> void { http_parser_clear(&parser); });
39   http_parser_init(&parser);
40 
41   SECTION("request")
42   {
43     const char request[] = "GET /index.html HTTP/1.1\r\n"
44                            "Host: trafficserver.apache.org\r\n"
45                            "User-Agent: foobar\r\n"
46                            "\r\n";
47 
48     HTTPHdr hdr_1;
__anon6d3b2ca40202() 49     ts::PostScript hdr_1_defer([&]() -> void { hdr_1.destroy(); });
50     hdr_1.create(HTTP_TYPE_REQUEST);
51     http2_init_pseudo_headers(hdr_1);
52 
53     // parse
54     const char *start = request;
55     const char *end   = request + sizeof(request) - 1;
56     hdr_1.parse_req(&parser, &start, end, true);
57 
58     // convert to HTTP/2
59     http2_convert_header_from_1_1_to_2(&hdr_1);
60 
61     // check pseudo headers
62     // :method
63     {
64       MIMEField *f = hdr_1.field_find(HTTP2_VALUE_METHOD, HTTP2_LEN_METHOD);
65       REQUIRE(f != nullptr);
66       std::string_view v = f->value_get();
67       CHECK(v == "GET");
68     }
69 
70     // :scheme
71     {
72       MIMEField *f = hdr_1.field_find(HTTP2_VALUE_SCHEME, HTTP2_LEN_SCHEME);
73       REQUIRE(f != nullptr);
74       std::string_view v = f->value_get();
75       CHECK(v == "https");
76     }
77 
78     // :authority
79     {
80       MIMEField *f = hdr_1.field_find(HTTP2_VALUE_AUTHORITY, HTTP2_LEN_AUTHORITY);
81       REQUIRE(f != nullptr);
82       std::string_view v = f->value_get();
83       CHECK(v == "trafficserver.apache.org");
84     }
85 
86     // :path
87     {
88       MIMEField *f = hdr_1.field_find(HTTP2_VALUE_PATH, HTTP2_LEN_PATH);
89       REQUIRE(f != nullptr);
90       std::string_view v = f->value_get();
91       CHECK(v == "/index.html");
92     }
93 
94     // convert to HTTP/1.1
95     HTTPHdr hdr_2;
__anon6d3b2ca40302() 96     ts::PostScript hdr_2_defer([&]() -> void { hdr_2.destroy(); });
97     hdr_2.create(HTTP_TYPE_REQUEST);
98     hdr_2.copy(&hdr_1);
99 
100     http2_convert_header_from_2_to_1_1(&hdr_2);
101 
102     // dump
103     char buf[128]  = {0};
104     int bufindex   = 0;
105     int dumpoffset = 0;
106 
107     hdr_2.print(buf, sizeof(buf), &bufindex, &dumpoffset);
108 
109     // check
110     CHECK_THAT(buf, Catch::StartsWith("GET https://trafficserver.apache.org/index.html HTTP/1.1\r\n"
111                                       "Host: trafficserver.apache.org\r\n"
112                                       "User-Agent: foobar\r\n"
113                                       "\r\n"));
114   }
115 
116   SECTION("response")
117   {
118     const char response[] = "HTTP/1.1 200 OK\r\n"
119                             "Connection: close\r\n"
120                             "\r\n";
121 
122     HTTPHdr hdr_1;
__anon6d3b2ca40402() 123     ts::PostScript hdr_1_defer([&]() -> void { hdr_1.destroy(); });
124     hdr_1.create(HTTP_TYPE_RESPONSE);
125     http2_init_pseudo_headers(hdr_1);
126 
127     // parse
128     const char *start = response;
129     const char *end   = response + sizeof(response) - 1;
130     hdr_1.parse_resp(&parser, &start, end, true);
131 
132     // convert to HTTP/2
133     http2_convert_header_from_1_1_to_2(&hdr_1);
134 
135     // check pseudo headers
136     // :status
137     {
138       MIMEField *f = hdr_1.field_find(HTTP2_VALUE_STATUS, HTTP2_LEN_STATUS);
139       REQUIRE(f != nullptr);
140       std::string_view v = f->value_get();
141       CHECK(v == "200");
142     }
143 
144     // no connection header
145     {
146       MIMEField *f = hdr_1.field_find(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION);
147       CHECK(f == nullptr);
148     }
149 
150     // convert to HTTP/1.1
151     HTTPHdr hdr_2;
__anon6d3b2ca40502() 152     ts::PostScript hdr_2_defer([&]() -> void { hdr_2.destroy(); });
153     hdr_2.create(HTTP_TYPE_REQUEST);
154     hdr_2.copy(&hdr_1);
155 
156     http2_convert_header_from_2_to_1_1(&hdr_2);
157 
158     // dump
159     char buf[128]  = {0};
160     int bufindex   = 0;
161     int dumpoffset = 0;
162 
163     hdr_2.print(buf, sizeof(buf), &bufindex, &dumpoffset);
164 
165     // check
166     REQUIRE(bufindex > 0);
167     CHECK_THAT(buf, Catch::StartsWith("HTTP/1.1 200 OK\r\n\r\n"));
168   }
169 }
170