OLD | NEW |
1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 13 matching lines...) Expand all Loading... |
24 #include <vector> | 24 #include <vector> |
25 | 25 |
26 #include "base/files/file_path.h" | 26 #include "base/files/file_path.h" |
27 #include "base/format_macros.h" | 27 #include "base/format_macros.h" |
28 #include "base/logging.h" | 28 #include "base/logging.h" |
29 #include "base/strings/stringprintf.h" | 29 #include "base/strings/stringprintf.h" |
30 #include "base/strings/utf_string_conversions.h" | 30 #include "base/strings/utf_string_conversions.h" |
31 #include "build/build_config.h" | 31 #include "build/build_config.h" |
32 #include "gtest/gtest.h" | 32 #include "gtest/gtest.h" |
33 #include "test/multiprocess_exec.h" | 33 #include "test/multiprocess_exec.h" |
34 #include "test/paths.h" | 34 #include "test/test_paths.h" |
35 #include "util/file/file_io.h" | 35 #include "util/file/file_io.h" |
36 #include "util/misc/random_string.h" | 36 #include "util/misc/random_string.h" |
37 #include "util/net/http_body.h" | 37 #include "util/net/http_body.h" |
38 #include "util/net/http_headers.h" | 38 #include "util/net/http_headers.h" |
39 #include "util/net/http_multipart_builder.h" | 39 #include "util/net/http_multipart_builder.h" |
40 | 40 |
41 namespace crashpad { | 41 namespace crashpad { |
42 namespace test { | 42 namespace test { |
43 namespace { | 43 namespace { |
44 | 44 |
45 class HTTPTransportTestFixture : public MultiprocessExec { | 45 class HTTPTransportTestFixture : public MultiprocessExec { |
46 public: | 46 public: |
47 using RequestValidator = | 47 using RequestValidator = |
48 void(*)(HTTPTransportTestFixture*, const std::string&); | 48 void(*)(HTTPTransportTestFixture*, const std::string&); |
49 | 49 |
50 HTTPTransportTestFixture(const HTTPHeaders& headers, | 50 HTTPTransportTestFixture(const HTTPHeaders& headers, |
51 std::unique_ptr<HTTPBodyStream> body_stream, | 51 std::unique_ptr<HTTPBodyStream> body_stream, |
52 uint16_t http_response_code, | 52 uint16_t http_response_code, |
53 RequestValidator request_validator) | 53 RequestValidator request_validator) |
54 : MultiprocessExec(), | 54 : MultiprocessExec(), |
55 headers_(headers), | 55 headers_(headers), |
56 body_stream_(std::move(body_stream)), | 56 body_stream_(std::move(body_stream)), |
57 response_code_(http_response_code), | 57 response_code_(http_response_code), |
58 request_validator_(request_validator) { | 58 request_validator_(request_validator) { |
59 base::FilePath server_path = Paths::TestDataRoot().Append( | 59 base::FilePath server_path = TestPaths::TestDataRoot().Append( |
60 FILE_PATH_LITERAL("util/net/http_transport_test_server.py")); | 60 FILE_PATH_LITERAL("util/net/http_transport_test_server.py")); |
61 #if defined(OS_POSIX) | 61 #if defined(OS_POSIX) |
62 SetChildCommand(server_path.value(), nullptr); | 62 SetChildCommand(server_path.value(), nullptr); |
63 #elif defined(OS_WIN) | 63 #elif defined(OS_WIN) |
64 // Explicitly invoke a shell and python so that python can be found in the | 64 // Explicitly invoke a shell and python so that python can be found in the |
65 // path, and run the test script. | 65 // path, and run the test script. |
66 std::vector<std::string> args; | 66 std::vector<std::string> args; |
67 args.push_back("/c"); | 67 args.push_back("/c"); |
68 args.push_back("python"); | 68 args.push_back("python"); |
69 args.push_back(base::UTF16ToUTF8(server_path.value())); | 69 args.push_back(base::UTF16ToUTF8(server_path.value())); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 for (const auto& pair : headers_) { | 104 for (const auto& pair : headers_) { |
105 transport->SetHeader(pair.first, pair.second); | 105 transport->SetHeader(pair.first, pair.second); |
106 } | 106 } |
107 transport->SetBodyStream(std::move(body_stream_)); | 107 transport->SetBodyStream(std::move(body_stream_)); |
108 | 108 |
109 std::string response_body; | 109 std::string response_body; |
110 bool success = transport->ExecuteSynchronously(&response_body); | 110 bool success = transport->ExecuteSynchronously(&response_body); |
111 if (response_code_ == 200) { | 111 if (response_code_ == 200) { |
112 EXPECT_TRUE(success); | 112 EXPECT_TRUE(success); |
113 std::string expect_response_body = random_string + "\r\n"; | 113 std::string expect_response_body = random_string + "\r\n"; |
114 EXPECT_EQ(expect_response_body, response_body); | 114 EXPECT_EQ(response_body, expect_response_body); |
115 } else { | 115 } else { |
116 EXPECT_FALSE(success); | 116 EXPECT_FALSE(success); |
117 EXPECT_TRUE(response_body.empty()); | 117 EXPECT_TRUE(response_body.empty()); |
118 } | 118 } |
119 | 119 |
120 // Read until the child's stdout closes. | 120 // Read until the child's stdout closes. |
121 std::string request; | 121 std::string request; |
122 char buf[32]; | 122 char buf[32]; |
123 FileOperationResult bytes_read; | 123 FileOperationResult bytes_read; |
124 while ((bytes_read = ReadFile(ReadPipeHandle(), buf, sizeof(buf))) != 0) { | 124 while ((bytes_read = ReadFile(ReadPipeHandle(), buf, sizeof(buf))) != 0) { |
(...skipping 10 matching lines...) Expand all Loading... |
135 uint16_t response_code_; | 135 uint16_t response_code_; |
136 RequestValidator request_validator_; | 136 RequestValidator request_validator_; |
137 }; | 137 }; |
138 | 138 |
139 const char kMultipartFormData[] = "multipart/form-data"; | 139 const char kMultipartFormData[] = "multipart/form-data"; |
140 | 140 |
141 void GetHeaderField(const std::string& request, | 141 void GetHeaderField(const std::string& request, |
142 const std::string& header, | 142 const std::string& header, |
143 std::string* value) { | 143 std::string* value) { |
144 size_t index = request.find(header); | 144 size_t index = request.find(header); |
145 ASSERT_NE(std::string::npos, index); | 145 ASSERT_NE(index, std::string::npos); |
146 // Since the header is never the first line of the request, it should always | 146 // Since the header is never the first line of the request, it should always |
147 // be preceded by a CRLF. | 147 // be preceded by a CRLF. |
148 EXPECT_EQ('\n', request[index - 1]); | 148 EXPECT_EQ(request[index - 1], '\n'); |
149 EXPECT_EQ('\r', request[index - 2]); | 149 EXPECT_EQ(request[index - 2], '\r'); |
150 | 150 |
151 index += header.length(); | 151 index += header.length(); |
152 EXPECT_EQ(':', request[index++]); | 152 EXPECT_EQ(request[index++], ':'); |
153 // Per RFC 7230 §3.2, there can be one or more spaces or horizontal tabs. | 153 // Per RFC 7230 §3.2, there can be one or more spaces or horizontal tabs. |
154 // For testing purposes, just assume one space. | 154 // For testing purposes, just assume one space. |
155 EXPECT_EQ(' ', request[index++]); | 155 EXPECT_EQ(request[index++], ' '); |
156 | 156 |
157 size_t header_end = request.find('\r', index); | 157 size_t header_end = request.find('\r', index); |
158 ASSERT_NE(std::string::npos, header_end); | 158 ASSERT_NE(header_end, std::string::npos); |
159 | 159 |
160 *value = request.substr(index, header_end - index); | 160 *value = request.substr(index, header_end - index); |
161 } | 161 } |
162 | 162 |
163 void GetMultipartBoundary(const std::string& request, | 163 void GetMultipartBoundary(const std::string& request, |
164 std::string* multipart_boundary) { | 164 std::string* multipart_boundary) { |
165 std::string content_type; | 165 std::string content_type; |
166 GetHeaderField(request, kContentType, &content_type); | 166 GetHeaderField(request, kContentType, &content_type); |
167 | 167 |
168 ASSERT_GE(content_type.length(), strlen(kMultipartFormData)); | 168 ASSERT_GE(content_type.length(), strlen(kMultipartFormData)); |
169 size_t index = strlen(kMultipartFormData); | 169 size_t index = strlen(kMultipartFormData); |
170 EXPECT_EQ(kMultipartFormData, content_type.substr(0, index)); | 170 EXPECT_EQ(content_type.substr(0, index), kMultipartFormData); |
171 | 171 |
172 EXPECT_EQ(';', content_type[index++]); | 172 EXPECT_EQ(content_type[index++], ';'); |
173 | 173 |
174 size_t boundary_begin = content_type.find('=', index); | 174 size_t boundary_begin = content_type.find('=', index); |
175 ASSERT_NE(std::string::npos, boundary_begin); | 175 ASSERT_NE(boundary_begin, std::string::npos); |
176 EXPECT_EQ('=', content_type[boundary_begin++]); | 176 EXPECT_EQ(content_type[boundary_begin++], '='); |
177 if (multipart_boundary) { | 177 if (multipart_boundary) { |
178 *multipart_boundary = content_type.substr(boundary_begin); | 178 *multipart_boundary = content_type.substr(boundary_begin); |
179 } | 179 } |
180 } | 180 } |
181 | 181 |
182 const char kBoundaryEq[] = "boundary="; | 182 const char kBoundaryEq[] = "boundary="; |
183 | 183 |
184 void ValidFormData(HTTPTransportTestFixture* fixture, | 184 void ValidFormData(HTTPTransportTestFixture* fixture, |
185 const std::string& request) { | 185 const std::string& request) { |
186 std::string actual_boundary; | 186 std::string actual_boundary; |
187 GetMultipartBoundary(request, &actual_boundary); | 187 GetMultipartBoundary(request, &actual_boundary); |
188 | 188 |
189 const auto& content_type = fixture->headers().find(kContentType); | 189 const auto& content_type = fixture->headers().find(kContentType); |
190 ASSERT_NE(fixture->headers().end(), content_type); | 190 ASSERT_NE(content_type, fixture->headers().end()); |
191 | 191 |
192 size_t boundary = content_type->second.find(kBoundaryEq); | 192 size_t boundary = content_type->second.find(kBoundaryEq); |
193 ASSERT_NE(std::string::npos, boundary); | 193 ASSERT_NE(boundary, std::string::npos); |
194 std::string expected_boundary = | 194 std::string expected_boundary = |
195 content_type->second.substr(boundary + strlen(kBoundaryEq)); | 195 content_type->second.substr(boundary + strlen(kBoundaryEq)); |
196 EXPECT_EQ(expected_boundary, actual_boundary); | 196 EXPECT_EQ(actual_boundary, expected_boundary); |
197 | 197 |
198 size_t body_start = request.find("\r\n\r\n"); | 198 size_t body_start = request.find("\r\n\r\n"); |
199 ASSERT_NE(std::string::npos, body_start); | 199 ASSERT_NE(body_start, std::string::npos); |
200 body_start += 4; | 200 body_start += 4; |
201 | 201 |
202 std::string expected = "--" + expected_boundary + "\r\n"; | 202 std::string expected = "--" + expected_boundary + "\r\n"; |
203 expected += "Content-Disposition: form-data; name=\"key1\"\r\n\r\n"; | 203 expected += "Content-Disposition: form-data; name=\"key1\"\r\n\r\n"; |
204 expected += "test\r\n"; | 204 expected += "test\r\n"; |
205 ASSERT_LT(body_start + expected.length(), request.length()); | 205 ASSERT_LT(body_start + expected.length(), request.length()); |
206 EXPECT_EQ(expected, request.substr(body_start, expected.length())); | 206 EXPECT_EQ(request.substr(body_start, expected.length()), expected); |
207 | 207 |
208 body_start += expected.length(); | 208 body_start += expected.length(); |
209 | 209 |
210 expected = "--" + expected_boundary + "\r\n"; | 210 expected = "--" + expected_boundary + "\r\n"; |
211 expected += "Content-Disposition: form-data; name=\"key2\"\r\n\r\n"; | 211 expected += "Content-Disposition: form-data; name=\"key2\"\r\n\r\n"; |
212 expected += "--abcdefg123\r\n"; | 212 expected += "--abcdefg123\r\n"; |
213 expected += "--" + expected_boundary + "--\r\n"; | 213 expected += "--" + expected_boundary + "--\r\n"; |
214 ASSERT_EQ(body_start + expected.length(), request.length()); | 214 ASSERT_EQ(request.length(), body_start + expected.length()); |
215 EXPECT_EQ(expected, request.substr(body_start)); | 215 EXPECT_EQ(request.substr(body_start), expected); |
216 } | 216 } |
217 | 217 |
218 TEST(HTTPTransport, ValidFormData) { | 218 TEST(HTTPTransport, ValidFormData) { |
219 HTTPMultipartBuilder builder; | 219 HTTPMultipartBuilder builder; |
220 builder.SetFormData("key1", "test"); | 220 builder.SetFormData("key1", "test"); |
221 builder.SetFormData("key2", "--abcdefg123"); | 221 builder.SetFormData("key2", "--abcdefg123"); |
222 | 222 |
223 HTTPHeaders headers; | 223 HTTPHeaders headers; |
224 builder.PopulateContentHeaders(&headers); | 224 builder.PopulateContentHeaders(&headers); |
225 | 225 |
(...skipping 15 matching lines...) Expand all Loading... |
241 &ValidFormData); | 241 &ValidFormData); |
242 test.Run(); | 242 test.Run(); |
243 } | 243 } |
244 | 244 |
245 const char kTextPlain[] = "text/plain"; | 245 const char kTextPlain[] = "text/plain"; |
246 | 246 |
247 void ErrorResponse(HTTPTransportTestFixture* fixture, | 247 void ErrorResponse(HTTPTransportTestFixture* fixture, |
248 const std::string& request) { | 248 const std::string& request) { |
249 std::string content_type; | 249 std::string content_type; |
250 GetHeaderField(request, kContentType, &content_type); | 250 GetHeaderField(request, kContentType, &content_type); |
251 EXPECT_EQ(kTextPlain, content_type); | 251 EXPECT_EQ(content_type, kTextPlain); |
252 } | 252 } |
253 | 253 |
254 TEST(HTTPTransport, ErrorResponse) { | 254 TEST(HTTPTransport, ErrorResponse) { |
255 HTTPMultipartBuilder builder; | 255 HTTPMultipartBuilder builder; |
256 HTTPHeaders headers; | 256 HTTPHeaders headers; |
257 headers[kContentType] = kTextPlain; | 257 headers[kContentType] = kTextPlain; |
258 HTTPTransportTestFixture test(headers, builder.GetBodyStream(), | 258 HTTPTransportTestFixture test(headers, builder.GetBodyStream(), |
259 404, &ErrorResponse); | 259 404, &ErrorResponse); |
260 test.Run(); | 260 test.Run(); |
261 } | 261 } |
262 | 262 |
263 const char kTextBody[] = "hello world"; | 263 const char kTextBody[] = "hello world"; |
264 | 264 |
265 void UnchunkedPlainText(HTTPTransportTestFixture* fixture, | 265 void UnchunkedPlainText(HTTPTransportTestFixture* fixture, |
266 const std::string& request) { | 266 const std::string& request) { |
267 std::string header_value; | 267 std::string header_value; |
268 GetHeaderField(request, kContentType, &header_value); | 268 GetHeaderField(request, kContentType, &header_value); |
269 EXPECT_EQ(kTextPlain, header_value); | 269 EXPECT_EQ(header_value, kTextPlain); |
270 | 270 |
271 GetHeaderField(request, kContentLength, &header_value); | 271 GetHeaderField(request, kContentLength, &header_value); |
272 const auto& content_length = fixture->headers().find(kContentLength); | 272 const auto& content_length = fixture->headers().find(kContentLength); |
273 ASSERT_NE(fixture->headers().end(), content_length); | 273 ASSERT_NE(content_length, fixture->headers().end()); |
274 EXPECT_EQ(content_length->second, header_value); | 274 EXPECT_EQ(header_value, content_length->second); |
275 | 275 |
276 size_t body_start = request.rfind("\r\n"); | 276 size_t body_start = request.rfind("\r\n"); |
277 ASSERT_NE(std::string::npos, body_start); | 277 ASSERT_NE(body_start, std::string::npos); |
278 | 278 |
279 EXPECT_EQ(kTextBody, request.substr(body_start + 2)); | 279 EXPECT_EQ(request.substr(body_start + 2), kTextBody); |
280 } | 280 } |
281 | 281 |
282 TEST(HTTPTransport, UnchunkedPlainText) { | 282 TEST(HTTPTransport, UnchunkedPlainText) { |
283 std::unique_ptr<HTTPBodyStream> body_stream( | 283 std::unique_ptr<HTTPBodyStream> body_stream( |
284 new StringHTTPBodyStream(kTextBody)); | 284 new StringHTTPBodyStream(kTextBody)); |
285 | 285 |
286 HTTPHeaders headers; | 286 HTTPHeaders headers; |
287 headers[kContentType] = kTextPlain; | 287 headers[kContentType] = kTextPlain; |
288 headers[kContentLength] = base::StringPrintf("%" PRIuS, strlen(kTextBody)); | 288 headers[kContentLength] = base::StringPrintf("%" PRIuS, strlen(kTextBody)); |
289 | 289 |
(...skipping 17 matching lines...) Expand all Loading... |
307 if (has_content_length) { | 307 if (has_content_length) { |
308 headers[kContentLength] = | 308 headers[kContentLength] = |
309 base::StringPrintf("%" PRIuS, request_string.size()); | 309 base::StringPrintf("%" PRIuS, request_string.size()); |
310 } | 310 } |
311 HTTPTransportTestFixture test( | 311 HTTPTransportTestFixture test( |
312 headers, | 312 headers, |
313 std::move(body_stream), | 313 std::move(body_stream), |
314 200, | 314 200, |
315 [](HTTPTransportTestFixture* fixture, const std::string& request) { | 315 [](HTTPTransportTestFixture* fixture, const std::string& request) { |
316 size_t body_start = request.rfind("\r\n"); | 316 size_t body_start = request.rfind("\r\n"); |
317 EXPECT_EQ(33 * 1024u + 2, request.size() - body_start); | 317 EXPECT_EQ(request.size() - body_start, 33 * 1024u + 2); |
318 }); | 318 }); |
319 test.Run(); | 319 test.Run(); |
320 } | 320 } |
321 | 321 |
322 TEST(HTTPTransport, Upload33k) { | 322 TEST(HTTPTransport, Upload33k) { |
323 RunUpload33k(true); | 323 RunUpload33k(true); |
324 } | 324 } |
325 | 325 |
326 TEST(HTTPTransport, Upload33k_LengthUnknown) { | 326 TEST(HTTPTransport, Upload33k_LengthUnknown) { |
327 // The same as Upload33k, but without declaring Content-Length ahead of time. | 327 // The same as Upload33k, but without declaring Content-Length ahead of time. |
328 RunUpload33k(false); | 328 RunUpload33k(false); |
329 } | 329 } |
330 | 330 |
331 } // namespace | 331 } // namespace |
332 } // namespace test | 332 } // namespace test |
333 } // namespace crashpad | 333 } // namespace crashpad |
OLD | NEW |