• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2013 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "shrpx_downstream_test.h"
26 
27 #include <iostream>
28 
29 #include "munitxx.h"
30 
31 #include "shrpx_downstream.h"
32 
33 using namespace std::literals;
34 
35 namespace shrpx {
36 
37 namespace {
38 const MunitTest tests[]{
39     munit_void_test(test_downstream_field_store_append_last_header),
40     munit_void_test(test_downstream_field_store_header),
41     munit_void_test(test_downstream_crumble_request_cookie),
42     munit_void_test(test_downstream_assemble_request_cookie),
43     munit_void_test(test_downstream_rewrite_location_response_header),
44     munit_void_test(test_downstream_supports_non_final_response),
45     munit_void_test(test_downstream_find_affinity_cookie),
46     munit_test_end(),
47 };
48 } // namespace
49 
50 const MunitSuite downstream_suite{
51     "/downstream", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE,
52 };
53 
test_downstream_field_store_append_last_header(void)54 void test_downstream_field_store_append_last_header(void) {
55   BlockAllocator balloc(16, 16);
56   FieldStore fs(balloc, 0);
57   fs.alloc_add_header_name("alpha"_sr);
58   auto bravo = "BRAVO"_sr;
59   fs.append_last_header_key(bravo.data(), bravo.size());
60   // Add more characters so that relloc occurs
61   auto golf = "golF0123456789"_sr;
62   fs.append_last_header_key(golf.data(), golf.size());
63 
64   auto charlie = "Charlie"_sr;
65   fs.append_last_header_value(charlie.data(), charlie.size());
66   auto delta = "deltA"_sr;
67   fs.append_last_header_value(delta.data(), delta.size());
68   // Add more characters so that relloc occurs
69   auto echo = "echo0123456789"_sr;
70   fs.append_last_header_value(echo.data(), echo.size());
71 
72   fs.add_header_token("echo"_sr, "foxtrot"_sr, false, -1);
73 
74   auto ans = HeaderRefs{
75       {"alphabravogolf0123456789"_sr, "CharliedeltAecho0123456789"_sr},
76       {"echo"_sr, "foxtrot"_sr}};
77   assert_true(ans == fs.headers());
78 }
79 
test_downstream_field_store_header(void)80 void test_downstream_field_store_header(void) {
81   BlockAllocator balloc(16, 16);
82   FieldStore fs(balloc, 0);
83   fs.add_header_token("alpha"_sr, "0"_sr, false, -1);
84   fs.add_header_token(":authority"_sr, "1"_sr, false, http2::HD__AUTHORITY);
85   fs.add_header_token("content-length"_sr, "2"_sr, false,
86                       http2::HD_CONTENT_LENGTH);
87 
88   // By token
89   assert_true(HeaderRef(StringRef{":authority"}, StringRef{"1"}) ==
90               *fs.header(http2::HD__AUTHORITY));
91   assert_null(fs.header(http2::HD__METHOD));
92 
93   // By name
94   assert_true(HeaderRef(StringRef{"alpha"}, StringRef{"0"}) ==
95               *fs.header("alpha"_sr));
96   assert_null(fs.header("bravo"_sr));
97 }
98 
test_downstream_crumble_request_cookie(void)99 void test_downstream_crumble_request_cookie(void) {
100   Downstream d(nullptr, nullptr, 0);
101   auto &req = d.request();
102   req.fs.add_header_token(":method"_sr, "get"_sr, false, -1);
103   req.fs.add_header_token(":path"_sr, "/"_sr, false, -1);
104   req.fs.add_header_token("cookie"_sr, "alpha; bravo; ; ;; charlie;;"_sr, true,
105                           http2::HD_COOKIE);
106   req.fs.add_header_token("cookie"_sr, ";delta"_sr, false, http2::HD_COOKIE);
107   req.fs.add_header_token("cookie"_sr, "echo"_sr, false, http2::HD_COOKIE);
108 
109   std::vector<nghttp2_nv> nva;
110   d.crumble_request_cookie(nva);
111 
112   auto num_cookies = d.count_crumble_request_cookie();
113 
114   assert_size(5, ==, nva.size());
115   assert_size(5, ==, num_cookies);
116 
117   HeaderRefs cookies;
118   std::transform(std::begin(nva), std::end(nva), std::back_inserter(cookies),
119                  [](const nghttp2_nv &nv) {
120                    return HeaderRef(StringRef{nv.name, nv.namelen},
121                                     StringRef{nv.value, nv.valuelen},
122                                     nv.flags & NGHTTP2_NV_FLAG_NO_INDEX);
123                  });
124 
125   HeaderRefs ans = {{"cookie"_sr, "alpha"_sr},
126                     {"cookie"_sr, "bravo"_sr},
127                     {"cookie"_sr, "charlie"_sr},
128                     {"cookie"_sr, "delta"_sr},
129                     {"cookie"_sr, "echo"_sr}};
130 
131   assert_true(ans == cookies);
132   assert_true(cookies[0].no_index);
133   assert_true(cookies[1].no_index);
134   assert_true(cookies[2].no_index);
135 }
136 
test_downstream_assemble_request_cookie(void)137 void test_downstream_assemble_request_cookie(void) {
138   Downstream d(nullptr, nullptr, 0);
139   auto &req = d.request();
140 
141   req.fs.add_header_token(":method"_sr, "get"_sr, false, -1);
142   req.fs.add_header_token(":path"_sr, "/"_sr, false, -1);
143   req.fs.add_header_token("cookie"_sr, "alpha"_sr, false, http2::HD_COOKIE);
144   req.fs.add_header_token("cookie"_sr, "bravo;"_sr, false, http2::HD_COOKIE);
145   req.fs.add_header_token("cookie"_sr, "charlie; "_sr, false, http2::HD_COOKIE);
146   req.fs.add_header_token("cookie"_sr, "delta;;"_sr, false, http2::HD_COOKIE);
147   assert_stdsv_equal("alpha; bravo; charlie; delta"sv,
148                      d.assemble_request_cookie());
149 }
150 
test_downstream_rewrite_location_response_header(void)151 void test_downstream_rewrite_location_response_header(void) {
152   Downstream d(nullptr, nullptr, 0);
153   auto &req = d.request();
154   auto &resp = d.response();
155   d.set_request_downstream_host("localhost2"_sr);
156   req.authority = "localhost:8443"_sr;
157   resp.fs.add_header_token("location"_sr, "http://localhost2:3000/"_sr, false,
158                            http2::HD_LOCATION);
159   d.rewrite_location_response_header("https"_sr);
160   auto location = resp.fs.header(http2::HD_LOCATION);
161   assert_stdsv_equal("https://localhost:8443/"sv, (*location).value);
162 }
163 
test_downstream_supports_non_final_response(void)164 void test_downstream_supports_non_final_response(void) {
165   Downstream d(nullptr, nullptr, 0);
166   auto &req = d.request();
167 
168   req.http_major = 3;
169   req.http_minor = 0;
170 
171   assert_true(d.supports_non_final_response());
172 
173   req.http_major = 2;
174   req.http_minor = 0;
175 
176   assert_true(d.supports_non_final_response());
177 
178   req.http_major = 1;
179   req.http_minor = 1;
180 
181   assert_true(d.supports_non_final_response());
182 
183   req.http_major = 1;
184   req.http_minor = 0;
185 
186   assert_false(d.supports_non_final_response());
187 
188   req.http_major = 0;
189   req.http_minor = 9;
190 
191   assert_false(d.supports_non_final_response());
192 }
193 
test_downstream_find_affinity_cookie(void)194 void test_downstream_find_affinity_cookie(void) {
195   Downstream d(nullptr, nullptr, 0);
196 
197   auto &req = d.request();
198   req.fs.add_header_token("cookie"_sr, StringRef{}, false, http2::HD_COOKIE);
199   req.fs.add_header_token("cookie"_sr, "a=b;;c=d"_sr, false, http2::HD_COOKIE);
200   req.fs.add_header_token("content-length"_sr, "599"_sr, false,
201                           http2::HD_CONTENT_LENGTH);
202   req.fs.add_header_token("cookie"_sr, "lb=deadbeef;LB=f1f2f3f4"_sr, false,
203                           http2::HD_COOKIE);
204   req.fs.add_header_token("cookie"_sr, "short=e1e2e3e"_sr, false,
205                           http2::HD_COOKIE);
206 
207   uint32_t aff;
208 
209   aff = d.find_affinity_cookie("lb"_sr);
210 
211   assert_uint32(0xdeadbeef, ==, aff);
212 
213   aff = d.find_affinity_cookie("LB"_sr);
214 
215   assert_uint32(0xf1f2f3f4, ==, aff);
216 
217   aff = d.find_affinity_cookie("short"_sr);
218 
219   assert_uint32(0, ==, aff);
220 }
221 
222 } // namespace shrpx
223