OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include "base/metrics/field_trial.h" |
5 #include "base/strings/stringprintf.h" | 6 #include "base/strings/stringprintf.h" |
6 #include "base/synchronization/waitable_event.h" | 7 #include "base/synchronization/waitable_event.h" |
| 8 #include "base/test/mock_entropy_provider.h" |
7 #include "base/threading/thread.h" | 9 #include "base/threading/thread.h" |
8 #include "net/http/http_response_headers.h" | 10 #include "net/http/http_response_headers.h" |
9 #include "net/test/spawned_test_server/spawned_test_server.h" | 11 #include "net/test/spawned_test_server/spawned_test_server.h" |
10 #include "net/url_request/test_url_fetcher_factory.h" | 12 #include "net/url_request/test_url_fetcher_factory.h" |
11 #include "net/url_request/url_fetcher_delegate.h" | 13 #include "net/url_request/url_fetcher_delegate.h" |
12 #include "net/url_request/url_request_test_util.h" | 14 #include "net/url_request/url_request_test_util.h" |
13 #include "sync/internal_api/public/base/cancelation_signal.h" | 15 #include "sync/internal_api/public/base/cancelation_signal.h" |
14 #include "sync/internal_api/public/http_bridge.h" | 16 #include "sync/internal_api/public/http_bridge.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 #include "third_party/zlib/zlib.h" |
16 | 19 |
17 namespace syncer { | 20 namespace syncer { |
18 | 21 |
19 namespace { | 22 namespace { |
| 23 |
20 // TODO(timsteele): Should use PathService here. See Chromium Issue 3113. | 24 // TODO(timsteele): Should use PathService here. See Chromium Issue 3113. |
21 const base::FilePath::CharType kDocRoot[] = | 25 const base::FilePath::CharType kDocRoot[] = |
22 FILE_PATH_LITERAL("chrome/test/data"); | 26 FILE_PATH_LITERAL("chrome/test/data"); |
| 27 |
| 28 // ----------------------------------------------------------------------------- |
| 29 // The rest of the code in the anon namespace is copied from |
| 30 // components/metrics/compression_utils.cc |
| 31 // TODO(gangwu): crbug.com/515695. The following codes are copied from |
| 32 // components/metrics/compression_utils.cc, we copied them because if we |
| 33 // reference them, we will get cycle dependency warning. Once the functions |
| 34 // have been moved from //component to //base, we can remove the following |
| 35 // functions. |
| 36 //------------------------------------------------------------------------------ |
| 37 // Pass an integer greater than the following get a gzip header instead of a |
| 38 // zlib header when calling deflateInit2() and inflateInit2(). |
| 39 const int kWindowBitsToGetGzipHeader = 16; |
| 40 |
| 41 // This code is taken almost verbatim from third_party/zlib/uncompr.c. The only |
| 42 // difference is inflateInit2() is called which sets the window bits to be > 16. |
| 43 // That causes a gzip header to be parsed rather than a zlib header. |
| 44 int GzipUncompressHelper(Bytef* dest, |
| 45 uLongf* dest_length, |
| 46 const Bytef* source, |
| 47 uLong source_length) { |
| 48 z_stream stream; |
| 49 |
| 50 stream.next_in = bit_cast<Bytef*>(source); |
| 51 stream.avail_in = static_cast<uInt>(source_length); |
| 52 if (static_cast<uLong>(stream.avail_in) != source_length) |
| 53 return Z_BUF_ERROR; |
| 54 |
| 55 stream.next_out = dest; |
| 56 stream.avail_out = static_cast<uInt>(*dest_length); |
| 57 if (static_cast<uLong>(stream.avail_out) != *dest_length) |
| 58 return Z_BUF_ERROR; |
| 59 |
| 60 stream.zalloc = static_cast<alloc_func>(0); |
| 61 stream.zfree = static_cast<free_func>(0); |
| 62 |
| 63 int err = inflateInit2(&stream, MAX_WBITS + kWindowBitsToGetGzipHeader); |
| 64 if (err != Z_OK) |
| 65 return err; |
| 66 |
| 67 err = inflate(&stream, Z_FINISH); |
| 68 if (err != Z_STREAM_END) { |
| 69 inflateEnd(&stream); |
| 70 if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) |
| 71 return Z_DATA_ERROR; |
| 72 return err; |
| 73 } |
| 74 *dest_length = stream.total_out; |
| 75 |
| 76 err = inflateEnd(&stream); |
| 77 return err; |
23 } | 78 } |
24 | 79 |
| 80 // Returns the uncompressed size from GZIP-compressed |compressed_data|. |
| 81 uint32 GetUncompressedSize(const std::string& compressed_data) { |
| 82 // The uncompressed size is stored in the last 4 bytes of |input| in LE. |
| 83 uint32 size; |
| 84 if (compressed_data.length() < sizeof(size)) |
| 85 return 0; |
| 86 memcpy(&size, &compressed_data[compressed_data.length() - sizeof(size)], |
| 87 sizeof(size)); |
| 88 return base::ByteSwapToLE32(size); |
| 89 } |
| 90 |
| 91 bool GzipUncompress(const std::string& input, std::string* output) { |
| 92 std::string uncompressed_output; |
| 93 uLongf uncompressed_size = static_cast<uLongf>(GetUncompressedSize(input)); |
| 94 uncompressed_output.resize(uncompressed_size); |
| 95 if (GzipUncompressHelper(bit_cast<Bytef*>(uncompressed_output.data()), |
| 96 &uncompressed_size, |
| 97 bit_cast<const Bytef*>(input.data()), |
| 98 static_cast<uLongf>(input.length())) == Z_OK) { |
| 99 output->swap(uncompressed_output); |
| 100 return true; |
| 101 } |
| 102 return false; |
| 103 } |
| 104 |
| 105 } // namespace |
| 106 |
25 const char kUserAgent[] = "user-agent"; | 107 const char kUserAgent[] = "user-agent"; |
26 | 108 |
27 class SyncHttpBridgeTest : public testing::Test { | 109 class SyncHttpBridgeTest : public testing::Test { |
28 public: | 110 public: |
29 SyncHttpBridgeTest() | 111 SyncHttpBridgeTest() |
30 : test_server_(net::SpawnedTestServer::TYPE_HTTP, | 112 : test_server_(net::SpawnedTestServer::TYPE_HTTP, |
31 net::SpawnedTestServer::kLocalhost, | 113 net::SpawnedTestServer::kLocalhost, |
32 base::FilePath(kDocRoot)), | 114 base::FilePath(kDocRoot)), |
33 fake_default_request_context_getter_(NULL), | 115 fake_default_request_context_getter_(NULL), |
34 bridge_for_race_test_(NULL), | 116 bridge_for_race_test_(NULL), |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 private: | 221 private: |
140 ~ShuntedHttpBridge() override {} | 222 ~ShuntedHttpBridge() override {} |
141 | 223 |
142 void CallOnURLFetchComplete() { | 224 void CallOnURLFetchComplete() { |
143 ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop()); | 225 ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop()); |
144 // We return no cookies and a dummy content response. | 226 // We return no cookies and a dummy content response. |
145 net::ResponseCookies cookies; | 227 net::ResponseCookies cookies; |
146 | 228 |
147 std::string response_content = "success!"; | 229 std::string response_content = "success!"; |
148 net::TestURLFetcher fetcher(0, GURL("http://www.google.com"), NULL); | 230 net::TestURLFetcher fetcher(0, GURL("http://www.google.com"), NULL); |
| 231 scoped_refptr<net::HttpResponseHeaders> response_headers( |
| 232 new net::HttpResponseHeaders("")); |
149 fetcher.set_response_code(200); | 233 fetcher.set_response_code(200); |
150 fetcher.set_cookies(cookies); | 234 fetcher.set_cookies(cookies); |
151 fetcher.SetResponseString(response_content); | 235 fetcher.SetResponseString(response_content); |
| 236 fetcher.set_response_headers(response_headers); |
152 OnURLFetchComplete(&fetcher); | 237 OnURLFetchComplete(&fetcher); |
153 } | 238 } |
154 SyncHttpBridgeTest* test_; | 239 SyncHttpBridgeTest* test_; |
155 bool never_finishes_; | 240 bool never_finishes_; |
156 }; | 241 }; |
157 | 242 |
158 void SyncHttpBridgeTest::RunSyncThreadBridgeUseTest( | 243 void SyncHttpBridgeTest::RunSyncThreadBridgeUseTest( |
159 base::WaitableEvent* signal_when_created, | 244 base::WaitableEvent* signal_when_created, |
160 base::WaitableEvent* signal_when_released) { | 245 base::WaitableEvent* signal_when_released) { |
161 scoped_refptr<net::URLRequestContextGetter> ctx_getter( | 246 scoped_refptr<net::URLRequestContextGetter> ctx_getter( |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); | 310 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); |
226 EXPECT_TRUE(success); | 311 EXPECT_TRUE(success); |
227 EXPECT_EQ(200, response_code); | 312 EXPECT_EQ(200, response_code); |
228 EXPECT_EQ(0, os_error); | 313 EXPECT_EQ(0, os_error); |
229 | 314 |
230 EXPECT_EQ(payload.length() + 1, | 315 EXPECT_EQ(payload.length() + 1, |
231 static_cast<size_t>(http_bridge->GetResponseContentLength())); | 316 static_cast<size_t>(http_bridge->GetResponseContentLength())); |
232 EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent())); | 317 EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent())); |
233 } | 318 } |
234 | 319 |
| 320 // Full round-trip test of the HttpBridge with compressed data, check if the |
| 321 // data is correctly compressed. |
| 322 TEST_F(SyncHttpBridgeTest, CompressedRequestPayloadCheck) { |
| 323 ASSERT_TRUE(test_server_.Start()); |
| 324 |
| 325 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); |
| 326 |
| 327 std::string payload = "this should be echoed back"; |
| 328 GURL echo = test_server_.GetURL("echo"); |
| 329 http_bridge->SetURL(echo.spec().c_str(), echo.IntPort()); |
| 330 http_bridge->SetPostPayload("application/x-www-form-urlencoded", |
| 331 payload.length(), payload.c_str()); |
| 332 int os_error = 0; |
| 333 int response_code = 0; |
| 334 base::FieldTrialList field_trial_list(new base::MockEntropyProvider()); |
| 335 base::FieldTrialList::CreateFieldTrial("SyncHttpContentCompression", |
| 336 "Enabled"); |
| 337 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); |
| 338 EXPECT_TRUE(success); |
| 339 EXPECT_EQ(200, response_code); |
| 340 EXPECT_EQ(0, os_error); |
| 341 |
| 342 EXPECT_NE(payload.length() + 1, |
| 343 static_cast<size_t>(http_bridge->GetResponseContentLength())); |
| 344 std::string compressed_payload(http_bridge->GetResponseContent(), |
| 345 http_bridge->GetResponseContentLength()); |
| 346 std::string uncompressed_payload; |
| 347 GzipUncompress(compressed_payload, &uncompressed_payload); |
| 348 EXPECT_EQ(payload, uncompressed_payload); |
| 349 } |
| 350 |
| 351 // Full round-trip test of the HttpBridge with compression, check if header |
| 352 // fields("Content-Encoding" ,"Accept-Encoding" and user agent) are set |
| 353 // correctly. |
| 354 TEST_F(SyncHttpBridgeTest, CompressedRequestHeaderCheck) { |
| 355 ASSERT_TRUE(test_server_.Start()); |
| 356 |
| 357 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); |
| 358 |
| 359 GURL echo_header = test_server_.GetURL("echoall"); |
| 360 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); |
| 361 |
| 362 std::string test_payload = "###TEST PAYLOAD###"; |
| 363 http_bridge->SetPostPayload("text/html", test_payload.length() + 1, |
| 364 test_payload.c_str()); |
| 365 |
| 366 int os_error = 0; |
| 367 int response_code = 0; |
| 368 base::FieldTrialList field_trial_list(new base::MockEntropyProvider()); |
| 369 base::FieldTrialList::CreateFieldTrial("SyncHttpContentCompression", |
| 370 "Enabled"); |
| 371 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); |
| 372 EXPECT_TRUE(success); |
| 373 EXPECT_EQ(200, response_code); |
| 374 EXPECT_EQ(0, os_error); |
| 375 |
| 376 std::string response(http_bridge->GetResponseContent(), |
| 377 http_bridge->GetResponseContentLength()); |
| 378 EXPECT_NE(std::string::npos, response.find("Content-Encoding: gzip")); |
| 379 EXPECT_NE(std::string::npos, |
| 380 response.find(base::StringPrintf( |
| 381 "%s: %s", net::HttpRequestHeaders::kAcceptEncoding, |
| 382 "gzip, deflate"))); |
| 383 EXPECT_NE(std::string::npos, |
| 384 response.find(base::StringPrintf( |
| 385 "%s: %s", net::HttpRequestHeaders::kUserAgent, kUserAgent))); |
| 386 } |
| 387 |
235 // Full round-trip test of the HttpBridge. | 388 // Full round-trip test of the HttpBridge. |
236 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) { | 389 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) { |
237 ASSERT_TRUE(test_server_.Start()); | 390 ASSERT_TRUE(test_server_.Start()); |
238 | 391 |
239 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); | 392 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); |
240 | 393 |
241 GURL echo_header = test_server_.GetURL("echoall"); | 394 GURL echo_header = test_server_.GetURL("echoall"); |
242 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); | 395 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); |
243 | 396 |
244 std::string test_payload = "###TEST PAYLOAD###"; | 397 std::string test_payload = "###TEST PAYLOAD###"; |
245 http_bridge->SetPostPayload("text/html", test_payload.length() + 1, | 398 http_bridge->SetPostPayload("text/html", test_payload.length() + 1, |
246 test_payload.c_str()); | 399 test_payload.c_str()); |
247 | 400 |
248 int os_error = 0; | 401 int os_error = 0; |
249 int response_code = 0; | 402 int response_code = 0; |
250 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); | 403 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); |
251 EXPECT_TRUE(success); | 404 EXPECT_TRUE(success); |
252 EXPECT_EQ(200, response_code); | 405 EXPECT_EQ(200, response_code); |
253 EXPECT_EQ(0, os_error); | 406 EXPECT_EQ(0, os_error); |
254 | 407 |
255 std::string response(http_bridge->GetResponseContent(), | 408 std::string response(http_bridge->GetResponseContent(), |
256 http_bridge->GetResponseContentLength()); | 409 http_bridge->GetResponseContentLength()); |
257 EXPECT_EQ(std::string::npos, response.find("Cookie:")); | 410 EXPECT_EQ(std::string::npos, response.find("Cookie:")); |
258 EXPECT_NE(std::string::npos, | 411 EXPECT_NE(std::string::npos, |
| 412 response.find(base::StringPrintf( |
| 413 "%s: %s", net::HttpRequestHeaders::kAcceptEncoding, |
| 414 "deflate"))); |
| 415 EXPECT_NE(std::string::npos, |
259 response.find(base::StringPrintf("%s: %s", | 416 response.find(base::StringPrintf("%s: %s", |
260 net::HttpRequestHeaders::kUserAgent, kUserAgent))); | 417 net::HttpRequestHeaders::kUserAgent, kUserAgent))); |
261 EXPECT_NE(std::string::npos, response.find(test_payload.c_str())); | 418 EXPECT_NE(std::string::npos, response.find(test_payload.c_str())); |
262 } | 419 } |
263 | 420 |
264 TEST_F(SyncHttpBridgeTest, TestExtraRequestHeaders) { | 421 TEST_F(SyncHttpBridgeTest, TestExtraRequestHeaders) { |
265 ASSERT_TRUE(test_server_.Start()); | 422 ASSERT_TRUE(test_server_.Start()); |
266 | 423 |
267 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); | 424 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); |
268 | 425 |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
512 | 669 |
513 // Sync thread: Finally run the posted task, only to find that our | 670 // Sync thread: Finally run the posted task, only to find that our |
514 // HttpBridgeFactory has been neutered. Should not crash. | 671 // HttpBridgeFactory has been neutered. Should not crash. |
515 factory->Init("TestUserAgent"); | 672 factory->Init("TestUserAgent"); |
516 | 673 |
517 // At this point, attempting to use the factory would trigger a crash. Both | 674 // At this point, attempting to use the factory would trigger a crash. Both |
518 // this test and the real world code should make sure this never happens. | 675 // this test and the real world code should make sure this never happens. |
519 }; | 676 }; |
520 | 677 |
521 } // namespace syncer | 678 } // namespace syncer |
OLD | NEW |