1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/url_request/redirect_util.h"
6
7 #include <string>
8
9 #include "net/http/http_request_headers.h"
10 #include "net/url_request/redirect_info.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "url/gurl.h"
13
14 namespace net {
15 namespace {
16
TEST(RedirectUtilTest,UpdateHttpRequest)17 TEST(RedirectUtilTest, UpdateHttpRequest) {
18 const GURL original_url("https://www.example.com/test.php");
19 const char kContentLengthValue[] = "100";
20 const char kContentTypeValue[] = "text/plain; charset=utf-8";
21 const char kContentEncoding[] = "Content-Encoding";
22 const char kContentEncodingValue[] = "gzip";
23 const char kContentLanguage[] = "Content-Language";
24 const char kContentLanguageValue[] = "tlh";
25 const char kContentLocation[] = "Content-Location";
26 const char kContentLocationValue[] = "https://somewhere.test/";
27 const char kCustomHeader[] = "Custom-Header-For-Test";
28 const char kCustomHeaderValue[] = "custom header value";
29
30 struct TestCase {
31 const char* original_method;
32 const char* new_method;
33 const char* new_url;
34 const struct {
35 const char* name;
36 const char* value;
37 } modified_headers[2];
38 bool expected_should_clear_upload;
39 // nullptr if the origin header should not exist
40 const char* expected_origin_header;
41 };
42 const TestCase kTests[] = {
43 {
44 "POST" /* original_method */,
45 "POST" /* new_method */,
46 "https://www.example.com/redirected.php" /* new_url */,
47 {{"Header1", "Value1"}, {"Header2", "Value2"}} /* modified_headers */,
48 false /* expected_should_clear_upload */,
49 "https://origin.example.com" /* expected_origin_header */
50 },
51 {
52 "POST" /* original_method */,
53 "GET" /* new_method */,
54 "https://www.example.com/redirected.php" /* new_url */,
55 {{"Header1", "Value1"}, {"Header2", "Value2"}} /* modified_headers */,
56 true /* expected_should_clear_upload */,
57 nullptr /* expected_origin_header */
58 },
59 {
60 "POST" /* original_method */,
61 "POST" /* new_method */,
62 "https://other.example.com/redirected.php" /* new_url */,
63 {{"Header1", "Value1"}, {"Header2", "Value2"}} /* modified_headers */,
64 false /* expected_should_clear_upload */,
65 "null" /* expected_origin_header */
66 },
67 {
68 "POST" /* original_method */,
69 "GET" /* new_method */,
70 "https://other.example.com/redirected.php" /* new_url */,
71 {{"Header1", "Value1"}, {"Header2", "Value2"}} /* modified_headers */,
72 true /* expected_should_clear_upload */,
73 nullptr /* expected_origin_header */
74 },
75 {
76 "PUT" /* original_method */,
77 "GET" /* new_method */,
78 "https://www.example.com/redirected.php" /* new_url */,
79 {{"Header1", "Value1"}, {"Header2", "Value2"}} /* modified_headers */,
80 true /* expected_should_clear_upload */,
81 nullptr /* expected_origin_header */
82 },
83 {
84 "FOOT" /* original_method */,
85 "GET" /* new_method */,
86 "https://www.example.com/redirected.php" /* new_url */,
87 {{"Header1", "Value1"}, {"Header2", "Value2"}} /* modified_headers */,
88 true /* expected_should_clear_upload */,
89 nullptr /* expected_origin_header */
90 },
91 };
92
93 for (const auto& test : kTests) {
94 SCOPED_TRACE(::testing::Message()
95 << "original_method: " << test.original_method
96 << " new_method: " << test.new_method
97 << " new_url: " << test.new_url);
98 RedirectInfo redirect_info;
99 redirect_info.new_method = test.new_method;
100 redirect_info.new_url = GURL(test.new_url);
101
102 net::HttpRequestHeaders modified_headers;
103 for (const auto& headers : test.modified_headers) {
104 ASSERT_TRUE(!!headers.name); // Currently all test case has this.
105 modified_headers.SetHeader(headers.name, headers.value);
106 }
107 std::string expected_modified_header1, expected_modified_header2;
108 modified_headers.GetHeader("Header1", &expected_modified_header1);
109 modified_headers.GetHeader("Header2", &expected_modified_header2);
110
111 HttpRequestHeaders request_headers;
112 request_headers.SetHeader(HttpRequestHeaders::kOrigin,
113 "https://origin.example.com");
114 request_headers.SetHeader(HttpRequestHeaders::kContentLength,
115 kContentLengthValue);
116 request_headers.SetHeader(HttpRequestHeaders::kContentType,
117 kContentTypeValue);
118 request_headers.SetHeader(kContentEncoding, kContentEncodingValue);
119 request_headers.SetHeader(kContentLanguage, kContentLanguageValue);
120 request_headers.SetHeader(kContentLocation, kContentLocationValue);
121 request_headers.SetHeader(kCustomHeader, kCustomHeaderValue);
122 request_headers.SetHeader("Header1", "Initial-Value1");
123
124 bool should_clear_upload = !test.expected_should_clear_upload;
125
126 RedirectUtil::UpdateHttpRequest(
127 original_url, test.original_method, redirect_info,
128 std::nullopt /* removed_headers */, modified_headers, &request_headers,
129 &should_clear_upload);
130 EXPECT_EQ(test.expected_should_clear_upload, should_clear_upload);
131
132 std::string content_length;
133 EXPECT_EQ(!test.expected_should_clear_upload,
134 request_headers.GetHeader(HttpRequestHeaders::kContentLength,
135 &content_length));
136 std::string content_type;
137 EXPECT_EQ(!test.expected_should_clear_upload,
138 request_headers.GetHeader(HttpRequestHeaders::kContentType,
139 &content_type));
140 std::string content_encoding;
141 EXPECT_EQ(!test.expected_should_clear_upload,
142 request_headers.GetHeader(kContentEncoding, &content_encoding));
143 std::string content_language;
144 EXPECT_EQ(!test.expected_should_clear_upload,
145 request_headers.GetHeader(kContentLanguage, &content_language));
146 std::string content_location;
147 EXPECT_EQ(!test.expected_should_clear_upload,
148 request_headers.GetHeader(kContentLocation, &content_location));
149 if (!test.expected_should_clear_upload) {
150 EXPECT_EQ(kContentLengthValue, content_length);
151 EXPECT_EQ(kContentTypeValue, content_type);
152 EXPECT_EQ(kContentEncodingValue, content_encoding);
153 EXPECT_EQ(kContentLanguageValue, content_language);
154 EXPECT_EQ(kContentLocationValue, content_location);
155 }
156
157 std::string custom_header;
158 EXPECT_TRUE(request_headers.GetHeader(kCustomHeader, &custom_header));
159 EXPECT_EQ(kCustomHeaderValue, custom_header);
160
161 std::string origin_header_value;
162 EXPECT_EQ(test.expected_origin_header != nullptr,
163 request_headers.GetHeader(HttpRequestHeaders::kOrigin,
164 &origin_header_value));
165 if (test.expected_origin_header) {
166 EXPECT_EQ(test.expected_origin_header, origin_header_value);
167 }
168
169 std::string modified_header1, modified_header2;
170 EXPECT_TRUE(request_headers.GetHeader("Header1", &modified_header1));
171 EXPECT_EQ(expected_modified_header1, modified_header1);
172 EXPECT_TRUE(request_headers.GetHeader("Header2", &modified_header2));
173 EXPECT_EQ(expected_modified_header2, modified_header2);
174 }
175 }
176
TEST(RedirectUtilTest,RemovedHeaders)177 TEST(RedirectUtilTest, RemovedHeaders) {
178 struct TestCase {
179 std::vector<const char*> initial_headers;
180 std::vector<const char*> modified_headers;
181 std::vector<const char*> removed_headers;
182 std::vector<const char*> final_headers;
183 };
184 const TestCase kTests[] = {
185 // Remove no headers (empty vector).
186 {
187 {}, // Initial headers
188 {}, // Modified headers
189 {}, // Removed headers
190 {}, // Final headers
191 },
192 // Remove an existing header.
193 {
194 {"A:0"}, // Initial headers
195 {}, // Modified headers
196 {"A"}, // Removed headers
197 {}, // Final headers
198 },
199 // Remove a missing header.
200 {
201 {}, // Initial headers
202 {}, // Modified headers
203 {"A"}, // Removed headers
204 {}, // Final headers
205 },
206 // Remove two different headers.
207 {
208 {"A:0", "B:0"}, // Initial headers
209 {}, // Modified headers
210 {"A", "B"}, // Removed headers
211 {}, // Final headers
212 },
213 // Remove two times the same headers.
214 {
215 {"A:0"}, // Initial headers
216 {}, // Modified headers
217 {"A", "A"}, // Removed headers
218 {}, // Final headers
219 },
220 // Remove an existing header that is also modified.
221 {
222 {"A:0"}, // Initial headers
223 {"A:1"}, // Modified headers
224 {"A"}, // Removed headers
225 {"A:1"}, // Final headers
226 },
227 // Some headers are removed, some aren't.
228 {
229 {"A:0", "B:0"}, // Initial headers
230 {}, // Modified headers
231 {"A"}, // Removed headers
232 {"B:0"}, // Final headers
233 },
234 };
235
236 for (const auto& test : kTests) {
237 HttpRequestHeaders initial_headers, modified_headers, final_headers;
238 std::vector<std::string> removed_headers;
239 for (const char* header : test.initial_headers)
240 initial_headers.AddHeaderFromString(header);
241 for (const char* header : test.modified_headers)
242 modified_headers.AddHeaderFromString(header);
243 for (const char* header : test.removed_headers)
244 removed_headers.push_back(header);
245 for (const char* header : test.final_headers)
246 final_headers.AddHeaderFromString(header);
247 bool should_clear_upload(false); // unused.
248
249 RedirectUtil::UpdateHttpRequest(GURL(), // original_url
250 std::string(), // original_method
251 RedirectInfo(), removed_headers,
252 modified_headers, &initial_headers,
253 &should_clear_upload);
254
255 // The initial_headers have been updated and should match the expected final
256 // headers.
257 EXPECT_EQ(initial_headers.ToString(), final_headers.ToString());
258 }
259 }
260
261 // Test with removed_headers = std::nullopt.
TEST(RedirectUtilTest,RemovedHeadersNullOpt)262 TEST(RedirectUtilTest, RemovedHeadersNullOpt) {
263 HttpRequestHeaders initial_headers, final_headers;
264 initial_headers.SetHeader("A", "0");
265 final_headers.SetHeader("A", "0");
266 std::optional<std::vector<std::string>> removed_headers(std::nullopt);
267 std::optional<HttpRequestHeaders> modified_headers(std::in_place);
268 bool should_clear_upload(false); // unused.
269
270 RedirectUtil::UpdateHttpRequest(GURL(), // original_url
271 std::string(), // original_method
272 RedirectInfo(), removed_headers,
273 modified_headers, &initial_headers,
274 &should_clear_upload);
275
276 // The initial_headers have been updated and should match the expected final
277 // headers.
278 EXPECT_EQ(initial_headers.ToString(), final_headers.ToString());
279 }
280
281 // Test with modified_headers = std::nullopt.
TEST(RedirectUtilTest,ModifyHeadersNullopt)282 TEST(RedirectUtilTest, ModifyHeadersNullopt) {
283 HttpRequestHeaders initial_headers, final_headers;
284 initial_headers.SetHeader("A", "0");
285 final_headers.SetHeader("A", "0");
286 std::optional<std::vector<std::string>> removed_headers(std::in_place);
287 std::optional<HttpRequestHeaders> modified_headers(std::nullopt);
288 bool should_clear_upload(false); // unused.
289
290 RedirectUtil::UpdateHttpRequest(GURL(), // original_url
291 std::string(), // original_method
292 RedirectInfo(), removed_headers,
293 modified_headers, &initial_headers,
294 &should_clear_upload);
295
296 // The initial_headers have been updated and should match the expected final
297 // headers.
298 EXPECT_EQ(initial_headers.ToString(), final_headers.ToString());
299 }
300
301 } // namespace
302 } // namespace net
303