1 // Copyright 2014 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/http/http_transaction_test_util.h"
6
7 #include <algorithm>
8 #include <unordered_map>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/location.h"
13 #include "base/run_loop.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/stl_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/threading/thread_task_runner_handle.h"
18 #include "base/time/clock.h"
19 #include "base/time/time.h"
20 #include "net/base/ip_address.h"
21 #include "net/base/ip_endpoint.h"
22 #include "net/base/load_flags.h"
23 #include "net/base/load_timing_info.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/network_isolation_key.h"
26 #include "net/cert/x509_certificate.h"
27 #include "net/disk_cache/disk_cache.h"
28 #include "net/http/http_cache.h"
29 #include "net/http/http_request_info.h"
30 #include "net/http/http_response_info.h"
31 #include "net/http/http_transaction.h"
32 #include "net/log/net_log.h"
33 #include "net/log/net_log_source.h"
34 #include "net/log/net_log_with_source.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36
37 namespace net {
38
39 namespace {
40 using MockTransactionMap =
41 std::unordered_map<std::string, const MockTransaction*>;
42 static MockTransactionMap mock_transactions;
43 } // namespace
44
DefaultTransportInfo()45 TransportInfo DefaultTransportInfo() {
46 return TransportInfo(TransportType::kDirect,
47 IPEndPoint(IPAddress::IPv4Localhost(), 80));
48 }
49
50 //-----------------------------------------------------------------------------
51 // mock transaction data
52
53 const MockTransaction kSimpleGET_Transaction = {
54 "http://www.google.com/",
55 "GET",
56 base::Time(),
57 "",
58 LOAD_NORMAL,
59 DefaultTransportInfo(),
60 "HTTP/1.1 200 OK",
61 "Cache-Control: max-age=10000\n",
62 base::Time(),
63 "<html><body>Google Blah Blah</body></html>",
64 TEST_MODE_NORMAL,
65 nullptr,
66 nullptr,
67 nullptr,
68 0,
69 0,
70 OK,
71 OK,
72 };
73
74 const MockTransaction kSimplePOST_Transaction = {
75 "http://bugdatabase.com/edit",
76 "POST",
77 base::Time(),
78 "",
79 LOAD_NORMAL,
80 DefaultTransportInfo(),
81 "HTTP/1.1 200 OK",
82 "",
83 base::Time(),
84 "<html><body>Google Blah Blah</body></html>",
85 TEST_MODE_NORMAL,
86 nullptr,
87 nullptr,
88 nullptr,
89 0,
90 0,
91 OK,
92 OK,
93 };
94
95 const MockTransaction kTypicalGET_Transaction = {
96 "http://www.example.com/~foo/bar.html",
97 "GET",
98 base::Time(),
99 "",
100 LOAD_NORMAL,
101 DefaultTransportInfo(),
102 "HTTP/1.1 200 OK",
103 "Date: Wed, 28 Nov 2007 09:40:09 GMT\n"
104 "Last-Modified: Wed, 28 Nov 2007 00:40:09 GMT\n",
105 base::Time(),
106 "<html><body>Google Blah Blah</body></html>",
107 TEST_MODE_NORMAL,
108 nullptr,
109 nullptr,
110 nullptr,
111 0,
112 0,
113 OK,
114 OK,
115 };
116
117 const MockTransaction kETagGET_Transaction = {
118 "http://www.google.com/foopy",
119 "GET",
120 base::Time(),
121 "",
122 LOAD_NORMAL,
123 DefaultTransportInfo(),
124 "HTTP/1.1 200 OK",
125 "Cache-Control: max-age=10000\n"
126 "Etag: \"foopy\"\n",
127 base::Time(),
128 "<html><body>Google Blah Blah</body></html>",
129 TEST_MODE_NORMAL,
130 nullptr,
131 nullptr,
132 nullptr,
133 0,
134 0,
135 OK,
136 OK,
137 };
138
139 const MockTransaction kRangeGET_Transaction = {
140 "http://www.google.com/",
141 "GET",
142 base::Time(),
143 "Range: 0-100\r\n",
144 LOAD_NORMAL,
145 DefaultTransportInfo(),
146 "HTTP/1.1 200 OK",
147 "Cache-Control: max-age=10000\n",
148 base::Time(),
149 "<html><body>Google Blah Blah</body></html>",
150 TEST_MODE_NORMAL,
151 nullptr,
152 nullptr,
153 nullptr,
154 0,
155 0,
156 OK,
157 OK,
158 };
159
160 static const MockTransaction* const kBuiltinMockTransactions[] = {
161 &kSimpleGET_Transaction,
162 &kSimplePOST_Transaction,
163 &kTypicalGET_Transaction,
164 &kETagGET_Transaction,
165 &kRangeGET_Transaction
166 };
167
FindMockTransaction(const GURL & url)168 const MockTransaction* FindMockTransaction(const GURL& url) {
169 // look for overrides:
170 MockTransactionMap::const_iterator it = mock_transactions.find(url.spec());
171 if (it != mock_transactions.end())
172 return it->second;
173
174 // look for builtins:
175 for (size_t i = 0; i < base::size(kBuiltinMockTransactions); ++i) {
176 if (url == GURL(kBuiltinMockTransactions[i]->url))
177 return kBuiltinMockTransactions[i];
178 }
179 return nullptr;
180 }
181
AddMockTransaction(const MockTransaction * trans)182 void AddMockTransaction(const MockTransaction* trans) {
183 mock_transactions[GURL(trans->url).spec()] = trans;
184 }
185
RemoveMockTransaction(const MockTransaction * trans)186 void RemoveMockTransaction(const MockTransaction* trans) {
187 mock_transactions.erase(GURL(trans->url).spec());
188 }
189
MockHttpRequest(const MockTransaction & t)190 MockHttpRequest::MockHttpRequest(const MockTransaction& t) {
191 url = GURL(t.url);
192 method = t.method;
193 extra_headers.AddHeadersFromString(t.request_headers);
194 load_flags = t.load_flags;
195 url::Origin origin = url::Origin::Create(url);
196 network_isolation_key = NetworkIsolationKey(origin, origin);
197 }
198
CacheKey()199 std::string MockHttpRequest::CacheKey() {
200 return HttpCache::GenerateCacheKeyForTest(this);
201 }
202
203 //-----------------------------------------------------------------------------
204
205 // static
206 int TestTransactionConsumer::quit_counter_ = 0;
207
TestTransactionConsumer(RequestPriority priority,HttpTransactionFactory * factory)208 TestTransactionConsumer::TestTransactionConsumer(
209 RequestPriority priority,
210 HttpTransactionFactory* factory)
211 : state_(IDLE), error_(OK) {
212 // Disregard the error code.
213 factory->CreateTransaction(priority, &trans_);
214 ++quit_counter_;
215 }
216
217 TestTransactionConsumer::~TestTransactionConsumer() = default;
218
Start(const HttpRequestInfo * request,const NetLogWithSource & net_log)219 void TestTransactionConsumer::Start(const HttpRequestInfo* request,
220 const NetLogWithSource& net_log) {
221 state_ = STARTING;
222 int result =
223 trans_->Start(request,
224 base::BindOnce(&TestTransactionConsumer::OnIOComplete,
225 base::Unretained(this)),
226 net_log);
227 if (result != ERR_IO_PENDING)
228 DidStart(result);
229 }
230
DidStart(int result)231 void TestTransactionConsumer::DidStart(int result) {
232 if (result != OK) {
233 DidFinish(result);
234 } else {
235 Read();
236 }
237 }
238
DidRead(int result)239 void TestTransactionConsumer::DidRead(int result) {
240 if (result <= 0) {
241 DidFinish(result);
242 } else {
243 content_.append(read_buf_->data(), result);
244 Read();
245 }
246 }
247
DidFinish(int result)248 void TestTransactionConsumer::DidFinish(int result) {
249 state_ = DONE;
250 error_ = result;
251 if (--quit_counter_ == 0)
252 base::RunLoop::QuitCurrentWhenIdleDeprecated();
253 }
254
Read()255 void TestTransactionConsumer::Read() {
256 state_ = READING;
257 read_buf_ = base::MakeRefCounted<IOBuffer>(1024);
258 int result =
259 trans_->Read(read_buf_.get(), 1024,
260 base::BindOnce(&TestTransactionConsumer::OnIOComplete,
261 base::Unretained(this)));
262 if (result != ERR_IO_PENDING)
263 DidRead(result);
264 }
265
OnIOComplete(int result)266 void TestTransactionConsumer::OnIOComplete(int result) {
267 switch (state_) {
268 case STARTING:
269 DidStart(result);
270 break;
271 case READING:
272 DidRead(result);
273 break;
274 default:
275 NOTREACHED();
276 }
277 }
278
MockNetworkTransaction(RequestPriority priority,MockNetworkLayer * factory)279 MockNetworkTransaction::MockNetworkTransaction(RequestPriority priority,
280 MockNetworkLayer* factory)
281 : request_(nullptr),
282 data_cursor_(0),
283 content_length_(0),
284 priority_(priority),
285 read_handler_(nullptr),
286 websocket_handshake_stream_create_helper_(nullptr),
287 transaction_factory_(factory->AsWeakPtr()),
288 received_bytes_(0),
289 sent_bytes_(0),
290 socket_log_id_(NetLogSource::kInvalidId),
291 done_reading_called_(false),
292 reading_(false) {}
293
~MockNetworkTransaction()294 MockNetworkTransaction::~MockNetworkTransaction() {
295 // Use request_ as in ~HttpNetworkTransaction to make sure its valid and not
296 // already freed by the consumer. Only check till Read is invoked since
297 // HttpNetworkTransaction sets request_ to nullptr when Read is invoked.
298 // See crbug.com/734037.
299 if (request_ && !reading_)
300 DCHECK(request_->load_flags >= 0);
301 }
302
Start(const HttpRequestInfo * request,CompletionOnceCallback callback,const NetLogWithSource & net_log)303 int MockNetworkTransaction::Start(const HttpRequestInfo* request,
304 CompletionOnceCallback callback,
305 const NetLogWithSource& net_log) {
306 if (request_)
307 return ERR_FAILED;
308
309 request_ = request;
310 return StartInternal(request, std::move(callback), net_log);
311 }
312
RestartIgnoringLastError(CompletionOnceCallback callback)313 int MockNetworkTransaction::RestartIgnoringLastError(
314 CompletionOnceCallback callback) {
315 return ERR_FAILED;
316 }
317
RestartWithCertificate(scoped_refptr<X509Certificate> client_cert,scoped_refptr<SSLPrivateKey> client_private_key,CompletionOnceCallback callback)318 int MockNetworkTransaction::RestartWithCertificate(
319 scoped_refptr<X509Certificate> client_cert,
320 scoped_refptr<SSLPrivateKey> client_private_key,
321 CompletionOnceCallback callback) {
322 return ERR_FAILED;
323 }
324
RestartWithAuth(const AuthCredentials & credentials,CompletionOnceCallback callback)325 int MockNetworkTransaction::RestartWithAuth(const AuthCredentials& credentials,
326 CompletionOnceCallback callback) {
327 if (!IsReadyToRestartForAuth())
328 return ERR_FAILED;
329
330 HttpRequestInfo auth_request_info = *request_;
331 auth_request_info.extra_headers.SetHeader("Authorization", "Bar");
332
333 // Let the MockTransactionHandler worry about this: the only way for this
334 // test to succeed is by using an explicit handler for the transaction so
335 // that server behavior can be simulated.
336 return StartInternal(&auth_request_info, std::move(callback),
337 NetLogWithSource());
338 }
339
PopulateNetErrorDetails(NetErrorDetails *) const340 void MockNetworkTransaction::PopulateNetErrorDetails(
341 NetErrorDetails* /*details*/) const {
342 NOTIMPLEMENTED();
343 }
344
IsReadyToRestartForAuth()345 bool MockNetworkTransaction::IsReadyToRestartForAuth() {
346 if (!request_)
347 return false;
348
349 if (!request_->extra_headers.HasHeader("X-Require-Mock-Auth"))
350 return false;
351
352 // Allow the mock server to decide whether authentication is required or not.
353 std::string status_line = response_.headers->GetStatusLine();
354 return status_line.find(" 401 ") != std::string::npos ||
355 status_line.find(" 407 ") != std::string::npos;
356 }
357
Read(net::IOBuffer * buf,int buf_len,CompletionOnceCallback callback)358 int MockNetworkTransaction::Read(net::IOBuffer* buf,
359 int buf_len,
360 CompletionOnceCallback callback) {
361 const MockTransaction* t = FindMockTransaction(request_->url);
362 DCHECK(t);
363
364 CHECK(!done_reading_called_);
365 reading_ = true;
366
367 int num = t->read_return_code;
368
369 if (OK == num) {
370 if (read_handler_) {
371 num = (*read_handler_)(content_length_, data_cursor_, buf, buf_len);
372 data_cursor_ += num;
373 } else {
374 int data_len = static_cast<int>(data_.size());
375 num = std::min(static_cast<int64_t>(buf_len), data_len - data_cursor_);
376 if (test_mode_ & TEST_MODE_SLOW_READ)
377 num = std::min(num, 1);
378 if (num) {
379 memcpy(buf->data(), data_.data() + data_cursor_, num);
380 data_cursor_ += num;
381 }
382 }
383 }
384
385 if (test_mode_ & TEST_MODE_SYNC_NET_READ)
386 return num;
387
388 CallbackLater(std::move(callback), num);
389 return ERR_IO_PENDING;
390 }
391
StopCaching()392 void MockNetworkTransaction::StopCaching() {
393 if (transaction_factory_.get())
394 transaction_factory_->TransactionStopCaching();
395 }
396
GetTotalReceivedBytes() const397 int64_t MockNetworkTransaction::GetTotalReceivedBytes() const {
398 return received_bytes_;
399 }
400
GetTotalSentBytes() const401 int64_t MockNetworkTransaction::GetTotalSentBytes() const {
402 return sent_bytes_;
403 }
404
DoneReading()405 void MockNetworkTransaction::DoneReading() {
406 CHECK(!done_reading_called_);
407 done_reading_called_ = true;
408 if (transaction_factory_.get())
409 transaction_factory_->TransactionDoneReading();
410 }
411
GetResponseInfo() const412 const HttpResponseInfo* MockNetworkTransaction::GetResponseInfo() const {
413 return &response_;
414 }
415
GetLoadState() const416 LoadState MockNetworkTransaction::GetLoadState() const {
417 if (data_cursor_)
418 return LOAD_STATE_READING_RESPONSE;
419 return LOAD_STATE_IDLE;
420 }
421
SetQuicServerInfo(QuicServerInfo * quic_server_info)422 void MockNetworkTransaction::SetQuicServerInfo(
423 QuicServerInfo* quic_server_info) {
424 }
425
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const426 bool MockNetworkTransaction::GetLoadTimingInfo(
427 LoadTimingInfo* load_timing_info) const {
428 if (socket_log_id_ != NetLogSource::kInvalidId) {
429 // The minimal set of times for a request that gets a response, assuming it
430 // gets a new socket.
431 load_timing_info->socket_reused = false;
432 load_timing_info->socket_log_id = socket_log_id_;
433 load_timing_info->connect_timing.connect_start = base::TimeTicks::Now();
434 load_timing_info->connect_timing.connect_end = base::TimeTicks::Now();
435 load_timing_info->send_start = base::TimeTicks::Now();
436 load_timing_info->send_end = base::TimeTicks::Now();
437 } else {
438 // If there's no valid socket ID, just use the generic socket reused values.
439 // No tests currently depend on this, just should not match the values set
440 // by a cache hit.
441 load_timing_info->socket_reused = true;
442 load_timing_info->send_start = base::TimeTicks::Now();
443 load_timing_info->send_end = base::TimeTicks::Now();
444 }
445 return true;
446 }
447
GetRemoteEndpoint(IPEndPoint * endpoint) const448 bool MockNetworkTransaction::GetRemoteEndpoint(IPEndPoint* endpoint) const {
449 *endpoint = IPEndPoint(IPAddress(127, 0, 0, 1), 80);
450 return true;
451 }
452
SetPriority(RequestPriority priority)453 void MockNetworkTransaction::SetPriority(RequestPriority priority) {
454 priority_ = priority;
455 }
456
SetWebSocketHandshakeStreamCreateHelper(WebSocketHandshakeStreamBase::CreateHelper * create_helper)457 void MockNetworkTransaction::SetWebSocketHandshakeStreamCreateHelper(
458 WebSocketHandshakeStreamBase::CreateHelper* create_helper) {
459 websocket_handshake_stream_create_helper_ = create_helper;
460 }
461
462 // static
463 const int64_t MockNetworkTransaction::kTotalReceivedBytes = 1000;
464
465 // static
466 const int64_t MockNetworkTransaction::kTotalSentBytes = 100;
467
StartInternal(const HttpRequestInfo * request,CompletionOnceCallback callback,const NetLogWithSource & net_log)468 int MockNetworkTransaction::StartInternal(const HttpRequestInfo* request,
469 CompletionOnceCallback callback,
470 const NetLogWithSource& net_log) {
471 const MockTransaction* t = FindMockTransaction(request->url);
472 if (!t)
473 return ERR_FAILED;
474
475 test_mode_ = t->test_mode;
476
477 // Return immediately if we're returning an error.
478 if (OK != t->start_return_code) {
479 if (test_mode_ & TEST_MODE_SYNC_NET_START)
480 return t->start_return_code;
481 CallbackLater(std::move(callback), t->start_return_code);
482 return ERR_IO_PENDING;
483 }
484
485 sent_bytes_ = kTotalSentBytes;
486 received_bytes_ = kTotalReceivedBytes;
487
488 std::string resp_status = t->status;
489 std::string resp_headers = t->response_headers;
490 std::string resp_data = t->data;
491 if (t->handler)
492 (t->handler)(request, &resp_status, &resp_headers, &resp_data);
493 if (t->read_handler)
494 read_handler_ = t->read_handler;
495
496 std::string header_data = base::StringPrintf(
497 "%s\n%s\n", resp_status.c_str(), resp_headers.c_str());
498 std::replace(header_data.begin(), header_data.end(), '\n', '\0');
499
500 response_.request_time = transaction_factory_->Now();
501 if (!t->request_time.is_null())
502 response_.request_time = t->request_time;
503
504 response_.was_cached = false;
505 response_.network_accessed = true;
506
507 response_.response_time = transaction_factory_->Now();
508 if (!t->response_time.is_null())
509 response_.response_time = t->response_time;
510
511 response_.headers = new HttpResponseHeaders(header_data);
512 response_.vary_data.Init(*request, *response_.headers.get());
513 response_.ssl_info.cert = t->cert;
514 response_.ssl_info.cert_status = t->cert_status;
515 response_.ssl_info.connection_status = t->ssl_connection_status;
516 data_ = resp_data;
517 content_length_ = response_.headers->GetContentLength();
518
519 if (net_log.net_log())
520 socket_log_id_ = net_log.net_log()->NextID();
521
522 if (request_->load_flags & LOAD_PREFETCH)
523 response_.unused_since_prefetch = true;
524
525 if (request_->load_flags & LOAD_RESTRICTED_PREFETCH) {
526 DCHECK(response_.unused_since_prefetch);
527 response_.restricted_prefetch = true;
528 }
529
530 // Pause and resume.
531 if (!before_network_start_callback_.is_null()) {
532 bool defer = false;
533 std::move(before_network_start_callback_).Run(&defer);
534 if (defer) {
535 resume_start_callback_ = std::move(callback);
536 return net::ERR_IO_PENDING;
537 }
538 }
539
540 if (test_mode_ & TEST_MODE_SYNC_NET_START)
541 return OK;
542
543 int result = OK;
544 if (!connected_callback_.is_null()) {
545 result = connected_callback_.Run(t->transport_info);
546 }
547
548 CallbackLater(std::move(callback), result);
549 return ERR_IO_PENDING;
550 }
551
SetBeforeNetworkStartCallback(BeforeNetworkStartCallback callback)552 void MockNetworkTransaction::SetBeforeNetworkStartCallback(
553 BeforeNetworkStartCallback callback) {
554 before_network_start_callback_ = std::move(callback);
555 }
556
SetConnectedCallback(const ConnectedCallback & callback)557 void MockNetworkTransaction::SetConnectedCallback(
558 const ConnectedCallback& callback) {
559 connected_callback_ = callback;
560 }
561
ResumeNetworkStart()562 int MockNetworkTransaction::ResumeNetworkStart() {
563 DCHECK(!resume_start_callback_.is_null());
564 CallbackLater(std::move(resume_start_callback_), OK);
565 return ERR_IO_PENDING;
566 }
567
GetConnectionAttempts(ConnectionAttempts * out) const568 void MockNetworkTransaction::GetConnectionAttempts(
569 ConnectionAttempts* out) const {
570 NOTIMPLEMENTED();
571 }
572
CallbackLater(CompletionOnceCallback callback,int result)573 void MockNetworkTransaction::CallbackLater(CompletionOnceCallback callback,
574 int result) {
575 base::ThreadTaskRunnerHandle::Get()->PostTask(
576 FROM_HERE,
577 base::BindOnce(&MockNetworkTransaction::RunCallback,
578 weak_factory_.GetWeakPtr(), std::move(callback), result));
579 }
580
RunCallback(CompletionOnceCallback callback,int result)581 void MockNetworkTransaction::RunCallback(CompletionOnceCallback callback,
582 int result) {
583 std::move(callback).Run(result);
584 }
585
MockNetworkLayer()586 MockNetworkLayer::MockNetworkLayer()
587 : transaction_count_(0),
588 done_reading_called_(false),
589 stop_caching_called_(false),
590 last_create_transaction_priority_(DEFAULT_PRIORITY),
591 clock_(nullptr) {
592 }
593
594 MockNetworkLayer::~MockNetworkLayer() = default;
595
TransactionDoneReading()596 void MockNetworkLayer::TransactionDoneReading() {
597 CHECK(!done_reading_called_);
598 done_reading_called_ = true;
599 }
600
TransactionStopCaching()601 void MockNetworkLayer::TransactionStopCaching() {
602 stop_caching_called_ = true;
603 }
604
ResetTransactionCount()605 void MockNetworkLayer::ResetTransactionCount() {
606 transaction_count_ = 0;
607 }
608
CreateTransaction(RequestPriority priority,std::unique_ptr<HttpTransaction> * trans)609 int MockNetworkLayer::CreateTransaction(
610 RequestPriority priority,
611 std::unique_ptr<HttpTransaction>* trans) {
612 transaction_count_++;
613 last_create_transaction_priority_ = priority;
614 std::unique_ptr<MockNetworkTransaction> mock_transaction(
615 new MockNetworkTransaction(priority, this));
616 last_transaction_ = mock_transaction->AsWeakPtr();
617 *trans = std::move(mock_transaction);
618 return OK;
619 }
620
GetCache()621 HttpCache* MockNetworkLayer::GetCache() {
622 return nullptr;
623 }
624
GetSession()625 HttpNetworkSession* MockNetworkLayer::GetSession() {
626 return nullptr;
627 }
628
SetClock(base::Clock * clock)629 void MockNetworkLayer::SetClock(base::Clock* clock) {
630 DCHECK(!clock_);
631 clock_ = clock;
632 }
633
Now()634 base::Time MockNetworkLayer::Now() {
635 if (clock_)
636 return clock_->Now();
637 return base::Time::Now();
638 }
639
640 //-----------------------------------------------------------------------------
641 // helpers
642
ReadTransaction(HttpTransaction * trans,std::string * result)643 int ReadTransaction(HttpTransaction* trans, std::string* result) {
644 int rv;
645
646 std::string content;
647 do {
648 TestCompletionCallback callback;
649 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(256);
650 rv = trans->Read(buf.get(), 256, callback.callback());
651 if (rv == ERR_IO_PENDING) {
652 rv = callback.WaitForResult();
653 base::RunLoop().RunUntilIdle();
654 }
655
656 if (rv > 0)
657 content.append(buf->data(), rv);
658 else if (rv < 0)
659 return rv;
660 } while (rv > 0);
661
662 result->swap(content);
663 return OK;
664 }
665
666 //-----------------------------------------------------------------------------
667 // connected callback handler
668
669 ConnectedHandler::ConnectedHandler() = default;
670 ConnectedHandler::~ConnectedHandler() = default;
671
672 ConnectedHandler::ConnectedHandler(const ConnectedHandler&) = default;
673 ConnectedHandler& ConnectedHandler::operator=(const ConnectedHandler&) =
674 default;
675 ConnectedHandler::ConnectedHandler(ConnectedHandler&&) = default;
676 ConnectedHandler& ConnectedHandler::operator=(ConnectedHandler&&) = default;
677
OnConnected(const TransportInfo & info)678 int ConnectedHandler::OnConnected(const TransportInfo& info) {
679 transports_.push_back(info);
680 return result_;
681 }
682
683 } // namespace net
684