| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 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/dns/dns_transaction.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/memory/scoped_ptr.h" | |
| 9 #include "base/memory/scoped_vector.h" | |
| 10 #include "base/rand_util.h" | |
| 11 #include "base/sys_byteorder.h" | |
| 12 #include "base/test/test_timeouts.h" | |
| 13 #include "net/base/dns_util.h" | |
| 14 #include "net/base/net_log.h" | |
| 15 #include "net/dns/dns_protocol.h" | |
| 16 #include "net/dns/dns_query.h" | |
| 17 #include "net/dns/dns_response.h" | |
| 18 #include "net/dns/dns_session.h" | |
| 19 #include "net/dns/dns_test_util.h" | |
| 20 #include "net/socket/socket_test_util.h" | |
| 21 #include "testing/gtest/include/gtest/gtest.h" | |
| 22 | |
| 23 namespace net { | |
| 24 | |
| 25 namespace { | |
| 26 | |
| 27 std::string DomainFromDot(const base::StringPiece& dotted) { | |
| 28 std::string out; | |
| 29 EXPECT_TRUE(DNSDomainFromDot(dotted, &out)); | |
| 30 return out; | |
| 31 } | |
| 32 | |
| 33 // A SocketDataProvider builder. | |
| 34 class DnsSocketData { | |
| 35 public: | |
| 36 // The ctor takes parameters for the DnsQuery. | |
| 37 DnsSocketData(uint16 id, | |
| 38 const char* dotted_name, | |
| 39 uint16 qtype, | |
| 40 IoMode mode, | |
| 41 bool use_tcp) | |
| 42 : query_(new DnsQuery(id, DomainFromDot(dotted_name), qtype)), | |
| 43 use_tcp_(use_tcp) { | |
| 44 if (use_tcp_) { | |
| 45 scoped_ptr<uint16> length(new uint16); | |
| 46 *length = base::HostToNet16(query_->io_buffer()->size()); | |
| 47 writes_.push_back(MockWrite(mode, | |
| 48 reinterpret_cast<const char*>(length.get()), | |
| 49 sizeof(uint16))); | |
| 50 lengths_.push_back(length.release()); | |
| 51 } | |
| 52 writes_.push_back(MockWrite(mode, | |
| 53 query_->io_buffer()->data(), | |
| 54 query_->io_buffer()->size())); | |
| 55 } | |
| 56 ~DnsSocketData() {} | |
| 57 | |
| 58 // All responses must be added before GetProvider. | |
| 59 | |
| 60 // Adds pre-built DnsResponse. |tcp_length| will be used in TCP mode only. | |
| 61 void AddResponseWithLength(scoped_ptr<DnsResponse> response, IoMode mode, | |
| 62 uint16 tcp_length) { | |
| 63 CHECK(!provider_.get()); | |
| 64 if (use_tcp_) { | |
| 65 scoped_ptr<uint16> length(new uint16); | |
| 66 *length = base::HostToNet16(tcp_length); | |
| 67 reads_.push_back(MockRead(mode, | |
| 68 reinterpret_cast<const char*>(length.get()), | |
| 69 sizeof(uint16))); | |
| 70 lengths_.push_back(length.release()); | |
| 71 } | |
| 72 reads_.push_back(MockRead(mode, | |
| 73 response->io_buffer()->data(), | |
| 74 response->io_buffer()->size())); | |
| 75 responses_.push_back(response.release()); | |
| 76 } | |
| 77 | |
| 78 // Adds pre-built DnsResponse. | |
| 79 void AddResponse(scoped_ptr<DnsResponse> response, IoMode mode) { | |
| 80 uint16 tcp_length = response->io_buffer()->size(); | |
| 81 AddResponseWithLength(response.Pass(), mode, tcp_length); | |
| 82 } | |
| 83 | |
| 84 // Adds pre-built response from |data| buffer. | |
| 85 void AddResponseData(const uint8* data, size_t length, IoMode mode) { | |
| 86 CHECK(!provider_.get()); | |
| 87 AddResponse(make_scoped_ptr( | |
| 88 new DnsResponse(reinterpret_cast<const char*>(data), length, 0)), mode); | |
| 89 } | |
| 90 | |
| 91 // Add no-answer (RCODE only) response matching the query. | |
| 92 void AddRcode(int rcode, IoMode mode) { | |
| 93 scoped_ptr<DnsResponse> response( | |
| 94 new DnsResponse(query_->io_buffer()->data(), | |
| 95 query_->io_buffer()->size(), | |
| 96 0)); | |
| 97 dns_protocol::Header* header = | |
| 98 reinterpret_cast<dns_protocol::Header*>(response->io_buffer()->data()); | |
| 99 header->flags |= base::HostToNet16(dns_protocol::kFlagResponse | rcode); | |
| 100 AddResponse(response.Pass(), mode); | |
| 101 } | |
| 102 | |
| 103 // Add error response. | |
| 104 void AddReadError(int error, IoMode mode) { | |
| 105 reads_.push_back(MockRead(mode, error)); | |
| 106 } | |
| 107 | |
| 108 // Build, if needed, and return the SocketDataProvider. No new responses | |
| 109 // should be added afterwards. | |
| 110 SocketDataProvider* GetProvider() { | |
| 111 if (provider_.get()) | |
| 112 return provider_.get(); | |
| 113 // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to | |
| 114 // timeout. | |
| 115 reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING)); | |
| 116 provider_.reset(new DelayedSocketData(1, &reads_[0], reads_.size(), | |
| 117 &writes_[0], writes_.size())); | |
| 118 if (use_tcp_) { | |
| 119 provider_->set_connect_data(MockConnect(reads_[0].mode, OK)); | |
| 120 } | |
| 121 return provider_.get(); | |
| 122 } | |
| 123 | |
| 124 uint16 query_id() const { | |
| 125 return query_->id(); | |
| 126 } | |
| 127 | |
| 128 // Returns true if the expected query was written to the socket. | |
| 129 bool was_written() const { | |
| 130 CHECK(provider_.get()); | |
| 131 return provider_->write_index() > 0; | |
| 132 } | |
| 133 | |
| 134 private: | |
| 135 scoped_ptr<DnsQuery> query_; | |
| 136 bool use_tcp_; | |
| 137 ScopedVector<uint16> lengths_; | |
| 138 ScopedVector<DnsResponse> responses_; | |
| 139 std::vector<MockWrite> writes_; | |
| 140 std::vector<MockRead> reads_; | |
| 141 scoped_ptr<DelayedSocketData> provider_; | |
| 142 | |
| 143 DISALLOW_COPY_AND_ASSIGN(DnsSocketData); | |
| 144 }; | |
| 145 | |
| 146 class TestSocketFactory; | |
| 147 | |
| 148 // A variant of MockUDPClientSocket which always fails to Connect. | |
| 149 class FailingUDPClientSocket : public MockUDPClientSocket { | |
| 150 public: | |
| 151 FailingUDPClientSocket(SocketDataProvider* data, | |
| 152 net::NetLog* net_log) | |
| 153 : MockUDPClientSocket(data, net_log) { | |
| 154 } | |
| 155 ~FailingUDPClientSocket() override {} | |
| 156 int Connect(const IPEndPoint& endpoint) override { | |
| 157 return ERR_CONNECTION_REFUSED; | |
| 158 } | |
| 159 | |
| 160 private: | |
| 161 DISALLOW_COPY_AND_ASSIGN(FailingUDPClientSocket); | |
| 162 }; | |
| 163 | |
| 164 // A variant of MockUDPClientSocket which notifies the factory OnConnect. | |
| 165 class TestUDPClientSocket : public MockUDPClientSocket { | |
| 166 public: | |
| 167 TestUDPClientSocket(TestSocketFactory* factory, | |
| 168 SocketDataProvider* data, | |
| 169 net::NetLog* net_log) | |
| 170 : MockUDPClientSocket(data, net_log), factory_(factory) { | |
| 171 } | |
| 172 ~TestUDPClientSocket() override {} | |
| 173 int Connect(const IPEndPoint& endpoint) override; | |
| 174 | |
| 175 private: | |
| 176 TestSocketFactory* factory_; | |
| 177 | |
| 178 DISALLOW_COPY_AND_ASSIGN(TestUDPClientSocket); | |
| 179 }; | |
| 180 | |
| 181 // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect. | |
| 182 class TestSocketFactory : public MockClientSocketFactory { | |
| 183 public: | |
| 184 TestSocketFactory() : fail_next_socket_(false) {} | |
| 185 ~TestSocketFactory() override {} | |
| 186 | |
| 187 scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket( | |
| 188 DatagramSocket::BindType bind_type, | |
| 189 const RandIntCallback& rand_int_cb, | |
| 190 net::NetLog* net_log, | |
| 191 const net::NetLog::Source& source) override { | |
| 192 if (fail_next_socket_) { | |
| 193 fail_next_socket_ = false; | |
| 194 return scoped_ptr<DatagramClientSocket>( | |
| 195 new FailingUDPClientSocket(&empty_data_, net_log)); | |
| 196 } | |
| 197 SocketDataProvider* data_provider = mock_data().GetNext(); | |
| 198 scoped_ptr<TestUDPClientSocket> socket( | |
| 199 new TestUDPClientSocket(this, data_provider, net_log)); | |
| 200 data_provider->set_socket(socket.get()); | |
| 201 return socket.Pass(); | |
| 202 } | |
| 203 | |
| 204 void OnConnect(const IPEndPoint& endpoint) { | |
| 205 remote_endpoints_.push_back(endpoint); | |
| 206 } | |
| 207 | |
| 208 std::vector<IPEndPoint> remote_endpoints_; | |
| 209 bool fail_next_socket_; | |
| 210 | |
| 211 private: | |
| 212 StaticSocketDataProvider empty_data_; | |
| 213 | |
| 214 DISALLOW_COPY_AND_ASSIGN(TestSocketFactory); | |
| 215 }; | |
| 216 | |
| 217 int TestUDPClientSocket::Connect(const IPEndPoint& endpoint) { | |
| 218 factory_->OnConnect(endpoint); | |
| 219 return MockUDPClientSocket::Connect(endpoint); | |
| 220 } | |
| 221 | |
| 222 // Helper class that holds a DnsTransaction and handles OnTransactionComplete. | |
| 223 class TransactionHelper { | |
| 224 public: | |
| 225 // If |expected_answer_count| < 0 then it is the expected net error. | |
| 226 TransactionHelper(const char* hostname, | |
| 227 uint16 qtype, | |
| 228 int expected_answer_count) | |
| 229 : hostname_(hostname), | |
| 230 qtype_(qtype), | |
| 231 expected_answer_count_(expected_answer_count), | |
| 232 cancel_in_callback_(false), | |
| 233 quit_in_callback_(false), | |
| 234 completed_(false) { | |
| 235 } | |
| 236 | |
| 237 // Mark that the transaction shall be destroyed immediately upon callback. | |
| 238 void set_cancel_in_callback() { | |
| 239 cancel_in_callback_ = true; | |
| 240 } | |
| 241 | |
| 242 // Mark to call MessageLoop::Quit() upon callback. | |
| 243 void set_quit_in_callback() { | |
| 244 quit_in_callback_ = true; | |
| 245 } | |
| 246 | |
| 247 void StartTransaction(DnsTransactionFactory* factory) { | |
| 248 EXPECT_EQ(NULL, transaction_.get()); | |
| 249 transaction_ = factory->CreateTransaction( | |
| 250 hostname_, | |
| 251 qtype_, | |
| 252 base::Bind(&TransactionHelper::OnTransactionComplete, | |
| 253 base::Unretained(this)), | |
| 254 BoundNetLog()); | |
| 255 EXPECT_EQ(hostname_, transaction_->GetHostname()); | |
| 256 EXPECT_EQ(qtype_, transaction_->GetType()); | |
| 257 transaction_->Start(); | |
| 258 } | |
| 259 | |
| 260 void Cancel() { | |
| 261 ASSERT_TRUE(transaction_.get() != NULL); | |
| 262 transaction_.reset(NULL); | |
| 263 } | |
| 264 | |
| 265 void OnTransactionComplete(DnsTransaction* t, | |
| 266 int rv, | |
| 267 const DnsResponse* response) { | |
| 268 EXPECT_FALSE(completed_); | |
| 269 EXPECT_EQ(transaction_.get(), t); | |
| 270 | |
| 271 completed_ = true; | |
| 272 | |
| 273 if (cancel_in_callback_) { | |
| 274 Cancel(); | |
| 275 return; | |
| 276 } | |
| 277 | |
| 278 // Tell MessageLoop to quit now, in case any ASSERT_* fails. | |
| 279 if (quit_in_callback_) | |
| 280 base::MessageLoop::current()->Quit(); | |
| 281 | |
| 282 if (expected_answer_count_ >= 0) { | |
| 283 ASSERT_EQ(OK, rv); | |
| 284 ASSERT_TRUE(response != NULL); | |
| 285 EXPECT_EQ(static_cast<unsigned>(expected_answer_count_), | |
| 286 response->answer_count()); | |
| 287 EXPECT_EQ(qtype_, response->qtype()); | |
| 288 | |
| 289 DnsRecordParser parser = response->Parser(); | |
| 290 DnsResourceRecord record; | |
| 291 for (int i = 0; i < expected_answer_count_; ++i) { | |
| 292 EXPECT_TRUE(parser.ReadRecord(&record)); | |
| 293 } | |
| 294 } else { | |
| 295 EXPECT_EQ(expected_answer_count_, rv); | |
| 296 } | |
| 297 } | |
| 298 | |
| 299 bool has_completed() const { | |
| 300 return completed_; | |
| 301 } | |
| 302 | |
| 303 // Shorthands for commonly used commands. | |
| 304 | |
| 305 bool Run(DnsTransactionFactory* factory) { | |
| 306 StartTransaction(factory); | |
| 307 base::MessageLoop::current()->RunUntilIdle(); | |
| 308 return has_completed(); | |
| 309 } | |
| 310 | |
| 311 // Use when some of the responses are timeouts. | |
| 312 bool RunUntilDone(DnsTransactionFactory* factory) { | |
| 313 set_quit_in_callback(); | |
| 314 StartTransaction(factory); | |
| 315 base::MessageLoop::current()->Run(); | |
| 316 return has_completed(); | |
| 317 } | |
| 318 | |
| 319 private: | |
| 320 std::string hostname_; | |
| 321 uint16 qtype_; | |
| 322 scoped_ptr<DnsTransaction> transaction_; | |
| 323 int expected_answer_count_; | |
| 324 bool cancel_in_callback_; | |
| 325 bool quit_in_callback_; | |
| 326 | |
| 327 bool completed_; | |
| 328 }; | |
| 329 | |
| 330 class DnsTransactionTest : public testing::Test { | |
| 331 public: | |
| 332 DnsTransactionTest() {} | |
| 333 | |
| 334 // Generates |nameservers| for DnsConfig. | |
| 335 void ConfigureNumServers(unsigned num_servers) { | |
| 336 CHECK_LE(num_servers, 255u); | |
| 337 config_.nameservers.clear(); | |
| 338 IPAddressNumber dns_ip; | |
| 339 { | |
| 340 bool rv = ParseIPLiteralToNumber("192.168.1.0", &dns_ip); | |
| 341 EXPECT_TRUE(rv); | |
| 342 } | |
| 343 for (unsigned i = 0; i < num_servers; ++i) { | |
| 344 dns_ip[3] = i; | |
| 345 config_.nameservers.push_back(IPEndPoint(dns_ip, | |
| 346 dns_protocol::kDefaultPort)); | |
| 347 } | |
| 348 } | |
| 349 | |
| 350 // Called after fully configuring |config|. | |
| 351 void ConfigureFactory() { | |
| 352 socket_factory_.reset(new TestSocketFactory()); | |
| 353 session_ = new DnsSession( | |
| 354 config_, | |
| 355 DnsSocketPool::CreateNull(socket_factory_.get()), | |
| 356 base::Bind(&DnsTransactionTest::GetNextId, base::Unretained(this)), | |
| 357 NULL /* NetLog */); | |
| 358 transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get()); | |
| 359 } | |
| 360 | |
| 361 void AddSocketData(scoped_ptr<DnsSocketData> data) { | |
| 362 CHECK(socket_factory_.get()); | |
| 363 transaction_ids_.push_back(data->query_id()); | |
| 364 socket_factory_->AddSocketDataProvider(data->GetProvider()); | |
| 365 socket_data_.push_back(data.release()); | |
| 366 } | |
| 367 | |
| 368 // Add expected query for |dotted_name| and |qtype| with |id| and response | |
| 369 // taken verbatim from |data| of |data_length| bytes. The transaction id in | |
| 370 // |data| should equal |id|, unless testing mismatched response. | |
| 371 void AddQueryAndResponse(uint16 id, | |
| 372 const char* dotted_name, | |
| 373 uint16 qtype, | |
| 374 const uint8* response_data, | |
| 375 size_t response_length, | |
| 376 IoMode mode, | |
| 377 bool use_tcp) { | |
| 378 CHECK(socket_factory_.get()); | |
| 379 scoped_ptr<DnsSocketData> data( | |
| 380 new DnsSocketData(id, dotted_name, qtype, mode, use_tcp)); | |
| 381 data->AddResponseData(response_data, response_length, mode); | |
| 382 AddSocketData(data.Pass()); | |
| 383 } | |
| 384 | |
| 385 void AddAsyncQueryAndResponse(uint16 id, | |
| 386 const char* dotted_name, | |
| 387 uint16 qtype, | |
| 388 const uint8* data, | |
| 389 size_t data_length) { | |
| 390 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC, | |
| 391 false); | |
| 392 } | |
| 393 | |
| 394 void AddSyncQueryAndResponse(uint16 id, | |
| 395 const char* dotted_name, | |
| 396 uint16 qtype, | |
| 397 const uint8* data, | |
| 398 size_t data_length) { | |
| 399 AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS, | |
| 400 false); | |
| 401 } | |
| 402 | |
| 403 // Add expected query of |dotted_name| and |qtype| and no response. | |
| 404 void AddQueryAndTimeout(const char* dotted_name, uint16 qtype) { | |
| 405 uint16 id = base::RandInt(0, kuint16max); | |
| 406 scoped_ptr<DnsSocketData> data( | |
| 407 new DnsSocketData(id, dotted_name, qtype, ASYNC, false)); | |
| 408 AddSocketData(data.Pass()); | |
| 409 } | |
| 410 | |
| 411 // Add expected query of |dotted_name| and |qtype| and matching response with | |
| 412 // no answer and RCODE set to |rcode|. The id will be generated randomly. | |
| 413 void AddQueryAndRcode(const char* dotted_name, | |
| 414 uint16 qtype, | |
| 415 int rcode, | |
| 416 IoMode mode, | |
| 417 bool use_tcp) { | |
| 418 CHECK_NE(dns_protocol::kRcodeNOERROR, rcode); | |
| 419 uint16 id = base::RandInt(0, kuint16max); | |
| 420 scoped_ptr<DnsSocketData> data( | |
| 421 new DnsSocketData(id, dotted_name, qtype, mode, use_tcp)); | |
| 422 data->AddRcode(rcode, mode); | |
| 423 AddSocketData(data.Pass()); | |
| 424 } | |
| 425 | |
| 426 void AddAsyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) { | |
| 427 AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC, false); | |
| 428 } | |
| 429 | |
| 430 void AddSyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) { | |
| 431 AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS, false); | |
| 432 } | |
| 433 | |
| 434 // Checks if the sockets were connected in the order matching the indices in | |
| 435 // |servers|. | |
| 436 void CheckServerOrder(const unsigned* servers, size_t num_attempts) { | |
| 437 ASSERT_EQ(num_attempts, socket_factory_->remote_endpoints_.size()); | |
| 438 for (size_t i = 0; i < num_attempts; ++i) { | |
| 439 EXPECT_EQ(socket_factory_->remote_endpoints_[i], | |
| 440 session_->config().nameservers[servers[i]]); | |
| 441 } | |
| 442 } | |
| 443 | |
| 444 void SetUp() override { | |
| 445 // By default set one server, | |
| 446 ConfigureNumServers(1); | |
| 447 // and no retransmissions, | |
| 448 config_.attempts = 1; | |
| 449 // but long enough timeout for memory tests. | |
| 450 config_.timeout = TestTimeouts::action_timeout(); | |
| 451 ConfigureFactory(); | |
| 452 } | |
| 453 | |
| 454 void TearDown() override { | |
| 455 // Check that all socket data was at least written to. | |
| 456 for (size_t i = 0; i < socket_data_.size(); ++i) { | |
| 457 EXPECT_TRUE(socket_data_[i]->was_written()) << i; | |
| 458 } | |
| 459 } | |
| 460 | |
| 461 protected: | |
| 462 int GetNextId(int min, int max) { | |
| 463 EXPECT_FALSE(transaction_ids_.empty()); | |
| 464 int id = transaction_ids_.front(); | |
| 465 transaction_ids_.pop_front(); | |
| 466 EXPECT_GE(id, min); | |
| 467 EXPECT_LE(id, max); | |
| 468 return id; | |
| 469 } | |
| 470 | |
| 471 DnsConfig config_; | |
| 472 | |
| 473 ScopedVector<DnsSocketData> socket_data_; | |
| 474 | |
| 475 std::deque<int> transaction_ids_; | |
| 476 scoped_ptr<TestSocketFactory> socket_factory_; | |
| 477 scoped_refptr<DnsSession> session_; | |
| 478 scoped_ptr<DnsTransactionFactory> transaction_factory_; | |
| 479 }; | |
| 480 | |
| 481 TEST_F(DnsTransactionTest, Lookup) { | |
| 482 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
| 483 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
| 484 | |
| 485 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
| 486 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 487 } | |
| 488 | |
| 489 // Concurrent lookup tests assume that DnsTransaction::Start immediately | |
| 490 // consumes a socket from ClientSocketFactory. | |
| 491 TEST_F(DnsTransactionTest, ConcurrentLookup) { | |
| 492 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
| 493 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
| 494 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype, | |
| 495 kT1ResponseDatagram, arraysize(kT1ResponseDatagram)); | |
| 496 | |
| 497 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
| 498 helper0.StartTransaction(transaction_factory_.get()); | |
| 499 TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount); | |
| 500 helper1.StartTransaction(transaction_factory_.get()); | |
| 501 | |
| 502 base::MessageLoop::current()->RunUntilIdle(); | |
| 503 | |
| 504 EXPECT_TRUE(helper0.has_completed()); | |
| 505 EXPECT_TRUE(helper1.has_completed()); | |
| 506 } | |
| 507 | |
| 508 TEST_F(DnsTransactionTest, CancelLookup) { | |
| 509 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
| 510 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
| 511 AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype, | |
| 512 kT1ResponseDatagram, arraysize(kT1ResponseDatagram)); | |
| 513 | |
| 514 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
| 515 helper0.StartTransaction(transaction_factory_.get()); | |
| 516 TransactionHelper helper1(kT1HostName, kT1Qtype, kT1RecordCount); | |
| 517 helper1.StartTransaction(transaction_factory_.get()); | |
| 518 | |
| 519 helper0.Cancel(); | |
| 520 | |
| 521 base::MessageLoop::current()->RunUntilIdle(); | |
| 522 | |
| 523 EXPECT_FALSE(helper0.has_completed()); | |
| 524 EXPECT_TRUE(helper1.has_completed()); | |
| 525 } | |
| 526 | |
| 527 TEST_F(DnsTransactionTest, DestroyFactory) { | |
| 528 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
| 529 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
| 530 | |
| 531 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
| 532 helper0.StartTransaction(transaction_factory_.get()); | |
| 533 | |
| 534 // Destroying the client does not affect running requests. | |
| 535 transaction_factory_.reset(NULL); | |
| 536 | |
| 537 base::MessageLoop::current()->RunUntilIdle(); | |
| 538 | |
| 539 EXPECT_TRUE(helper0.has_completed()); | |
| 540 } | |
| 541 | |
| 542 TEST_F(DnsTransactionTest, CancelFromCallback) { | |
| 543 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
| 544 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
| 545 | |
| 546 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
| 547 helper0.set_cancel_in_callback(); | |
| 548 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 549 } | |
| 550 | |
| 551 TEST_F(DnsTransactionTest, MismatchedResponseSync) { | |
| 552 config_.attempts = 2; | |
| 553 config_.timeout = TestTimeouts::tiny_timeout(); | |
| 554 ConfigureFactory(); | |
| 555 | |
| 556 // Attempt receives mismatched response followed by valid response. | |
| 557 scoped_ptr<DnsSocketData> data( | |
| 558 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS, false)); | |
| 559 data->AddResponseData(kT1ResponseDatagram, | |
| 560 arraysize(kT1ResponseDatagram), SYNCHRONOUS); | |
| 561 data->AddResponseData(kT0ResponseDatagram, | |
| 562 arraysize(kT0ResponseDatagram), SYNCHRONOUS); | |
| 563 AddSocketData(data.Pass()); | |
| 564 | |
| 565 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
| 566 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); | |
| 567 } | |
| 568 | |
| 569 TEST_F(DnsTransactionTest, MismatchedResponseAsync) { | |
| 570 config_.attempts = 2; | |
| 571 config_.timeout = TestTimeouts::tiny_timeout(); | |
| 572 ConfigureFactory(); | |
| 573 | |
| 574 // First attempt receives mismatched response followed by valid response. | |
| 575 // Second attempt times out. | |
| 576 scoped_ptr<DnsSocketData> data( | |
| 577 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, false)); | |
| 578 data->AddResponseData(kT1ResponseDatagram, | |
| 579 arraysize(kT1ResponseDatagram), ASYNC); | |
| 580 data->AddResponseData(kT0ResponseDatagram, | |
| 581 arraysize(kT0ResponseDatagram), ASYNC); | |
| 582 AddSocketData(data.Pass()); | |
| 583 AddQueryAndTimeout(kT0HostName, kT0Qtype); | |
| 584 | |
| 585 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
| 586 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); | |
| 587 } | |
| 588 | |
| 589 TEST_F(DnsTransactionTest, MismatchedResponseFail) { | |
| 590 config_.timeout = TestTimeouts::tiny_timeout(); | |
| 591 ConfigureFactory(); | |
| 592 | |
| 593 // Attempt receives mismatched response but times out because only one attempt | |
| 594 // is allowed. | |
| 595 AddAsyncQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype, | |
| 596 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
| 597 | |
| 598 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); | |
| 599 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); | |
| 600 } | |
| 601 | |
| 602 TEST_F(DnsTransactionTest, ServerFail) { | |
| 603 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL); | |
| 604 | |
| 605 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED); | |
| 606 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 607 } | |
| 608 | |
| 609 TEST_F(DnsTransactionTest, NoDomain) { | |
| 610 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN); | |
| 611 | |
| 612 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED); | |
| 613 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 614 } | |
| 615 | |
| 616 TEST_F(DnsTransactionTest, Timeout) { | |
| 617 config_.attempts = 3; | |
| 618 // Use short timeout to speed up the test. | |
| 619 config_.timeout = TestTimeouts::tiny_timeout(); | |
| 620 ConfigureFactory(); | |
| 621 | |
| 622 AddQueryAndTimeout(kT0HostName, kT0Qtype); | |
| 623 AddQueryAndTimeout(kT0HostName, kT0Qtype); | |
| 624 AddQueryAndTimeout(kT0HostName, kT0Qtype); | |
| 625 | |
| 626 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); | |
| 627 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); | |
| 628 EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); | |
| 629 } | |
| 630 | |
| 631 TEST_F(DnsTransactionTest, ServerFallbackAndRotate) { | |
| 632 // Test that we fallback on both server failure and timeout. | |
| 633 config_.attempts = 2; | |
| 634 // The next request should start from the next server. | |
| 635 config_.rotate = true; | |
| 636 ConfigureNumServers(3); | |
| 637 // Use short timeout to speed up the test. | |
| 638 config_.timeout = TestTimeouts::tiny_timeout(); | |
| 639 ConfigureFactory(); | |
| 640 | |
| 641 // Responses for first request. | |
| 642 AddQueryAndTimeout(kT0HostName, kT0Qtype); | |
| 643 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL); | |
| 644 AddQueryAndTimeout(kT0HostName, kT0Qtype); | |
| 645 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL); | |
| 646 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN); | |
| 647 // Responses for second request. | |
| 648 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL); | |
| 649 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL); | |
| 650 AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeNXDOMAIN); | |
| 651 | |
| 652 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_NAME_NOT_RESOLVED); | |
| 653 TransactionHelper helper1(kT1HostName, kT1Qtype, ERR_NAME_NOT_RESOLVED); | |
| 654 | |
| 655 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); | |
| 656 EXPECT_TRUE(helper1.Run(transaction_factory_.get())); | |
| 657 | |
| 658 unsigned kOrder[] = { | |
| 659 0, 1, 2, 0, 1, // The first transaction. | |
| 660 1, 2, 0, // The second transaction starts from the next server. | |
| 661 }; | |
| 662 CheckServerOrder(kOrder, arraysize(kOrder)); | |
| 663 } | |
| 664 | |
| 665 TEST_F(DnsTransactionTest, SuffixSearchAboveNdots) { | |
| 666 config_.ndots = 2; | |
| 667 config_.search.push_back("a"); | |
| 668 config_.search.push_back("b"); | |
| 669 config_.search.push_back("c"); | |
| 670 config_.rotate = true; | |
| 671 ConfigureNumServers(2); | |
| 672 ConfigureFactory(); | |
| 673 | |
| 674 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA, | |
| 675 dns_protocol::kRcodeNXDOMAIN); | |
| 676 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA, | |
| 677 dns_protocol::kRcodeNXDOMAIN); | |
| 678 AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA, | |
| 679 dns_protocol::kRcodeNXDOMAIN); | |
| 680 AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA, | |
| 681 dns_protocol::kRcodeNXDOMAIN); | |
| 682 | |
| 683 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, | |
| 684 ERR_NAME_NOT_RESOLVED); | |
| 685 | |
| 686 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 687 | |
| 688 // Also check if suffix search causes server rotation. | |
| 689 unsigned kOrder0[] = { 0, 1, 0, 1 }; | |
| 690 CheckServerOrder(kOrder0, arraysize(kOrder0)); | |
| 691 } | |
| 692 | |
| 693 TEST_F(DnsTransactionTest, SuffixSearchBelowNdots) { | |
| 694 config_.ndots = 2; | |
| 695 config_.search.push_back("a"); | |
| 696 config_.search.push_back("b"); | |
| 697 config_.search.push_back("c"); | |
| 698 ConfigureFactory(); | |
| 699 | |
| 700 // Responses for first transaction. | |
| 701 AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA, | |
| 702 dns_protocol::kRcodeNXDOMAIN); | |
| 703 AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA, | |
| 704 dns_protocol::kRcodeNXDOMAIN); | |
| 705 AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA, | |
| 706 dns_protocol::kRcodeNXDOMAIN); | |
| 707 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA, | |
| 708 dns_protocol::kRcodeNXDOMAIN); | |
| 709 // Responses for second transaction. | |
| 710 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA, | |
| 711 dns_protocol::kRcodeNXDOMAIN); | |
| 712 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA, | |
| 713 dns_protocol::kRcodeNXDOMAIN); | |
| 714 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA, | |
| 715 dns_protocol::kRcodeNXDOMAIN); | |
| 716 // Responses for third transaction. | |
| 717 AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA, | |
| 718 dns_protocol::kRcodeNXDOMAIN); | |
| 719 | |
| 720 TransactionHelper helper0("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); | |
| 721 | |
| 722 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 723 | |
| 724 // A single-label name. | |
| 725 TransactionHelper helper1("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); | |
| 726 | |
| 727 EXPECT_TRUE(helper1.Run(transaction_factory_.get())); | |
| 728 | |
| 729 // A fully-qualified name. | |
| 730 TransactionHelper helper2("x.", dns_protocol::kTypeAAAA, | |
| 731 ERR_NAME_NOT_RESOLVED); | |
| 732 | |
| 733 EXPECT_TRUE(helper2.Run(transaction_factory_.get())); | |
| 734 } | |
| 735 | |
| 736 TEST_F(DnsTransactionTest, EmptySuffixSearch) { | |
| 737 // Responses for first transaction. | |
| 738 AddAsyncQueryAndRcode("x", dns_protocol::kTypeA, | |
| 739 dns_protocol::kRcodeNXDOMAIN); | |
| 740 | |
| 741 // A fully-qualified name. | |
| 742 TransactionHelper helper0("x.", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); | |
| 743 | |
| 744 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 745 | |
| 746 // A single label name is not even attempted. | |
| 747 TransactionHelper helper1("singlelabel", dns_protocol::kTypeA, | |
| 748 ERR_DNS_SEARCH_EMPTY); | |
| 749 | |
| 750 helper1.Run(transaction_factory_.get()); | |
| 751 EXPECT_TRUE(helper1.has_completed()); | |
| 752 } | |
| 753 | |
| 754 TEST_F(DnsTransactionTest, DontAppendToMultiLabelName) { | |
| 755 config_.search.push_back("a"); | |
| 756 config_.search.push_back("b"); | |
| 757 config_.search.push_back("c"); | |
| 758 config_.append_to_multi_label_name = false; | |
| 759 ConfigureFactory(); | |
| 760 | |
| 761 // Responses for first transaction. | |
| 762 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA, | |
| 763 dns_protocol::kRcodeNXDOMAIN); | |
| 764 // Responses for second transaction. | |
| 765 AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA, | |
| 766 dns_protocol::kRcodeNXDOMAIN); | |
| 767 // Responses for third transaction. | |
| 768 AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA, | |
| 769 dns_protocol::kRcodeNXDOMAIN); | |
| 770 AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA, | |
| 771 dns_protocol::kRcodeNXDOMAIN); | |
| 772 AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA, | |
| 773 dns_protocol::kRcodeNXDOMAIN); | |
| 774 | |
| 775 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, | |
| 776 ERR_NAME_NOT_RESOLVED); | |
| 777 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 778 | |
| 779 TransactionHelper helper1("x.y", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); | |
| 780 EXPECT_TRUE(helper1.Run(transaction_factory_.get())); | |
| 781 | |
| 782 TransactionHelper helper2("x", dns_protocol::kTypeA, ERR_NAME_NOT_RESOLVED); | |
| 783 EXPECT_TRUE(helper2.Run(transaction_factory_.get())); | |
| 784 } | |
| 785 | |
| 786 const uint8 kResponseNoData[] = { | |
| 787 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, | |
| 788 // Question | |
| 789 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01, | |
| 790 // Authority section, SOA record, TTL 0x3E6 | |
| 791 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6, | |
| 792 // Minimal RDATA, 18 bytes | |
| 793 0x00, 0x12, | |
| 794 0x00, 0x00, | |
| 795 0x00, 0x00, 0x00, 0x00, | |
| 796 0x00, 0x00, 0x00, 0x00, | |
| 797 0x00, 0x00, 0x00, 0x00, | |
| 798 0x00, 0x00, 0x00, 0x00, | |
| 799 }; | |
| 800 | |
| 801 TEST_F(DnsTransactionTest, SuffixSearchStop) { | |
| 802 config_.ndots = 2; | |
| 803 config_.search.push_back("a"); | |
| 804 config_.search.push_back("b"); | |
| 805 config_.search.push_back("c"); | |
| 806 ConfigureFactory(); | |
| 807 | |
| 808 AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA, | |
| 809 dns_protocol::kRcodeNXDOMAIN); | |
| 810 AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA, | |
| 811 dns_protocol::kRcodeNXDOMAIN); | |
| 812 AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA, | |
| 813 kResponseNoData, arraysize(kResponseNoData)); | |
| 814 | |
| 815 TransactionHelper helper0("x.y.z", dns_protocol::kTypeA, 0 /* answers */); | |
| 816 | |
| 817 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 818 } | |
| 819 | |
| 820 TEST_F(DnsTransactionTest, SyncFirstQuery) { | |
| 821 config_.search.push_back("lab.ccs.neu.edu"); | |
| 822 config_.search.push_back("ccs.neu.edu"); | |
| 823 ConfigureFactory(); | |
| 824 | |
| 825 AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
| 826 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
| 827 | |
| 828 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
| 829 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 830 } | |
| 831 | |
| 832 TEST_F(DnsTransactionTest, SyncFirstQueryWithSearch) { | |
| 833 config_.search.push_back("lab.ccs.neu.edu"); | |
| 834 config_.search.push_back("ccs.neu.edu"); | |
| 835 ConfigureFactory(); | |
| 836 | |
| 837 AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype, | |
| 838 dns_protocol::kRcodeNXDOMAIN); | |
| 839 // "www.ccs.neu.edu" | |
| 840 AddAsyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype, | |
| 841 kT2ResponseDatagram, arraysize(kT2ResponseDatagram)); | |
| 842 | |
| 843 TransactionHelper helper0("www", kT2Qtype, kT2RecordCount); | |
| 844 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 845 } | |
| 846 | |
| 847 TEST_F(DnsTransactionTest, SyncSearchQuery) { | |
| 848 config_.search.push_back("lab.ccs.neu.edu"); | |
| 849 config_.search.push_back("ccs.neu.edu"); | |
| 850 ConfigureFactory(); | |
| 851 | |
| 852 AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA, | |
| 853 dns_protocol::kRcodeNXDOMAIN); | |
| 854 AddSyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype, | |
| 855 kT2ResponseDatagram, arraysize(kT2ResponseDatagram)); | |
| 856 | |
| 857 TransactionHelper helper0("www", kT2Qtype, kT2RecordCount); | |
| 858 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 859 } | |
| 860 | |
| 861 TEST_F(DnsTransactionTest, ConnectFailure) { | |
| 862 socket_factory_->fail_next_socket_ = true; | |
| 863 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt. | |
| 864 TransactionHelper helper0("www.chromium.org", dns_protocol::kTypeA, | |
| 865 ERR_CONNECTION_REFUSED); | |
| 866 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 867 } | |
| 868 | |
| 869 TEST_F(DnsTransactionTest, ConnectFailureFollowedBySuccess) { | |
| 870 // Retry after server failure. | |
| 871 config_.attempts = 2; | |
| 872 ConfigureFactory(); | |
| 873 // First server connection attempt fails. | |
| 874 transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt. | |
| 875 socket_factory_->fail_next_socket_ = true; | |
| 876 // Second DNS query succeeds. | |
| 877 AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
| 878 kT0ResponseDatagram, arraysize(kT0ResponseDatagram)); | |
| 879 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
| 880 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 881 } | |
| 882 | |
| 883 TEST_F(DnsTransactionTest, TCPLookup) { | |
| 884 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
| 885 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
| 886 AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, | |
| 887 kT0ResponseDatagram, arraysize(kT0ResponseDatagram), | |
| 888 ASYNC, true /* use_tcp */); | |
| 889 | |
| 890 TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount); | |
| 891 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 892 } | |
| 893 | |
| 894 TEST_F(DnsTransactionTest, TCPFailure) { | |
| 895 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
| 896 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
| 897 AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL, | |
| 898 ASYNC, true /* use_tcp */); | |
| 899 | |
| 900 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED); | |
| 901 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 902 } | |
| 903 | |
| 904 TEST_F(DnsTransactionTest, TCPMalformed) { | |
| 905 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
| 906 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
| 907 scoped_ptr<DnsSocketData> data( | |
| 908 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); | |
| 909 // Valid response but length too short. | |
| 910 // This must be truncated in the question section. The DnsResponse doesn't | |
| 911 // examine the answer section until asked to parse it, so truncating it in | |
| 912 // the answer section would result in the DnsTransaction itself succeeding. | |
| 913 data->AddResponseWithLength( | |
| 914 make_scoped_ptr( | |
| 915 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram), | |
| 916 arraysize(kT0ResponseDatagram), 0)), | |
| 917 ASYNC, | |
| 918 static_cast<uint16>(kT0QuerySize - 1)); | |
| 919 AddSocketData(data.Pass()); | |
| 920 | |
| 921 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_MALFORMED_RESPONSE); | |
| 922 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 923 } | |
| 924 | |
| 925 TEST_F(DnsTransactionTest, TCPTimeout) { | |
| 926 config_.timeout = TestTimeouts::tiny_timeout(); | |
| 927 ConfigureFactory(); | |
| 928 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
| 929 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
| 930 AddSocketData(make_scoped_ptr( | |
| 931 new DnsSocketData(1 /* id */, kT0HostName, kT0Qtype, ASYNC, true))); | |
| 932 | |
| 933 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); | |
| 934 EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); | |
| 935 } | |
| 936 | |
| 937 TEST_F(DnsTransactionTest, TCPReadReturnsZeroAsync) { | |
| 938 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
| 939 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
| 940 scoped_ptr<DnsSocketData> data( | |
| 941 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); | |
| 942 // Return all but the last byte of the response. | |
| 943 data->AddResponseWithLength( | |
| 944 make_scoped_ptr( | |
| 945 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram), | |
| 946 arraysize(kT0ResponseDatagram) - 1, 0)), | |
| 947 ASYNC, | |
| 948 static_cast<uint16>(arraysize(kT0ResponseDatagram))); | |
| 949 // Then return a 0-length read. | |
| 950 data->AddReadError(0, ASYNC); | |
| 951 AddSocketData(data.Pass()); | |
| 952 | |
| 953 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED); | |
| 954 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 955 } | |
| 956 | |
| 957 TEST_F(DnsTransactionTest, TCPReadReturnsZeroSynchronous) { | |
| 958 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
| 959 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
| 960 scoped_ptr<DnsSocketData> data( | |
| 961 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); | |
| 962 // Return all but the last byte of the response. | |
| 963 data->AddResponseWithLength( | |
| 964 make_scoped_ptr( | |
| 965 new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram), | |
| 966 arraysize(kT0ResponseDatagram) - 1, 0)), | |
| 967 SYNCHRONOUS, | |
| 968 static_cast<uint16>(arraysize(kT0ResponseDatagram))); | |
| 969 // Then return a 0-length read. | |
| 970 data->AddReadError(0, SYNCHRONOUS); | |
| 971 AddSocketData(data.Pass()); | |
| 972 | |
| 973 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED); | |
| 974 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 975 } | |
| 976 | |
| 977 TEST_F(DnsTransactionTest, TCPConnectionClosedAsync) { | |
| 978 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
| 979 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
| 980 scoped_ptr<DnsSocketData> data( | |
| 981 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); | |
| 982 data->AddReadError(ERR_CONNECTION_CLOSED, ASYNC); | |
| 983 AddSocketData(data.Pass()); | |
| 984 | |
| 985 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED); | |
| 986 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 987 } | |
| 988 | |
| 989 TEST_F(DnsTransactionTest, TCPConnectionClosedSynchronous) { | |
| 990 AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, | |
| 991 dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC); | |
| 992 scoped_ptr<DnsSocketData> data( | |
| 993 new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true)); | |
| 994 data->AddReadError(ERR_CONNECTION_CLOSED, SYNCHRONOUS); | |
| 995 AddSocketData(data.Pass()); | |
| 996 | |
| 997 TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_CONNECTION_CLOSED); | |
| 998 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 999 } | |
| 1000 | |
| 1001 TEST_F(DnsTransactionTest, InvalidQuery) { | |
| 1002 config_.timeout = TestTimeouts::tiny_timeout(); | |
| 1003 ConfigureFactory(); | |
| 1004 | |
| 1005 TransactionHelper helper0(".", dns_protocol::kTypeA, ERR_INVALID_ARGUMENT); | |
| 1006 EXPECT_TRUE(helper0.Run(transaction_factory_.get())); | |
| 1007 } | |
| 1008 | |
| 1009 } // namespace | |
| 1010 | |
| 1011 } // namespace net | |
| OLD | NEW |