OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "net/http/http_network_transaction.h" | 5 #include "net/http/http_network_transaction.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <utility> | 8 #include <utility> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 } // namespace | 100 } // namespace |
101 | 101 |
102 //----------------------------------------------------------------------------- | 102 //----------------------------------------------------------------------------- |
103 | 103 |
104 HttpNetworkTransaction::HttpNetworkTransaction(RequestPriority priority, | 104 HttpNetworkTransaction::HttpNetworkTransaction(RequestPriority priority, |
105 HttpNetworkSession* session) | 105 HttpNetworkSession* session) |
106 : pending_auth_target_(HttpAuth::AUTH_NONE), | 106 : pending_auth_target_(HttpAuth::AUTH_NONE), |
107 io_callback_(base::Bind(&HttpNetworkTransaction::OnIOComplete, | 107 io_callback_(base::Bind(&HttpNetworkTransaction::OnIOComplete, |
108 base::Unretained(this))), | 108 base::Unretained(this))), |
109 session_(session), | 109 session_(session), |
110 request_(NULL), | 110 request_(nullptr), |
111 priority_(priority), | 111 priority_(priority), |
| 112 response_(new HttpResponseInfo()), |
112 headers_valid_(false), | 113 headers_valid_(false), |
113 server_ssl_failure_state_(SSL_FAILURE_NONE), | 114 server_ssl_failure_state_(SSL_FAILURE_NONE), |
114 fallback_error_code_(ERR_SSL_INAPPROPRIATE_FALLBACK), | 115 fallback_error_code_(ERR_SSL_INAPPROPRIATE_FALLBACK), |
115 fallback_failure_state_(SSL_FAILURE_NONE), | 116 fallback_failure_state_(SSL_FAILURE_NONE), |
116 request_headers_(), | 117 request_headers_(), |
117 read_buf_len_(0), | 118 read_buf_len_(0), |
118 total_received_bytes_(0), | 119 total_received_bytes_(0), |
119 total_sent_bytes_(0), | 120 total_sent_bytes_(0), |
120 next_state_(STATE_NONE), | 121 next_state_(STATE_NONE), |
121 establishing_tunnel_(false), | 122 establishing_tunnel_(false), |
(...skipping 11 matching lines...) Expand all Loading... |
133 // stream should be kept alive. No reason to compute here | 134 // stream should be kept alive. No reason to compute here |
134 // and pass it in. | 135 // and pass it in. |
135 if (!stream_->CanReuseConnection() || next_state_ != STATE_NONE) { | 136 if (!stream_->CanReuseConnection() || next_state_ != STATE_NONE) { |
136 stream_->Close(true /* not reusable */); | 137 stream_->Close(true /* not reusable */); |
137 } else if (stream_->IsResponseBodyComplete()) { | 138 } else if (stream_->IsResponseBodyComplete()) { |
138 // If the response body is complete, we can just reuse the socket. | 139 // If the response body is complete, we can just reuse the socket. |
139 stream_->Close(false /* reusable */); | 140 stream_->Close(false /* reusable */); |
140 } else { | 141 } else { |
141 // Otherwise, we try to drain the response body. | 142 // Otherwise, we try to drain the response body. |
142 HttpStream* stream = stream_.release(); | 143 HttpStream* stream = stream_.release(); |
143 stream->Drain(session_); | 144 stream->Drain(session_, std::move(response_)); |
144 } | 145 } |
145 } | 146 } |
146 | 147 |
147 if (request_ && request_->upload_data_stream) | 148 if (request_ && request_->upload_data_stream) |
148 request_->upload_data_stream->Reset(); // Invalidate pending callbacks. | 149 request_->upload_data_stream->Reset(); // Invalidate pending callbacks. |
149 } | 150 } |
150 | 151 |
151 int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info, | 152 int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info, |
152 const CompletionCallback& callback, | 153 const CompletionCallback& callback, |
153 const BoundNetLog& net_log) { | 154 const BoundNetLog& net_log) { |
154 net_log_ = net_log; | 155 net_log_ = net_log; |
155 request_ = request_info; | 156 request_ = request_info; |
156 | 157 |
157 if (request_->load_flags & LOAD_DISABLE_CERT_REVOCATION_CHECKING) { | 158 if (request_->load_flags & LOAD_DISABLE_CERT_REVOCATION_CHECKING) { |
158 server_ssl_config_.rev_checking_enabled = false; | 159 server_ssl_config_.rev_checking_enabled = false; |
159 proxy_ssl_config_.rev_checking_enabled = false; | 160 proxy_ssl_config_.rev_checking_enabled = false; |
160 } | 161 } |
161 | 162 |
162 if (request_->load_flags & LOAD_PREFETCH) | 163 if (request_->load_flags & LOAD_PREFETCH) |
163 response_.unused_since_prefetch = true; | 164 response_->unused_since_prefetch = true; |
164 | 165 |
165 // Channel ID is disabled if privacy mode is enabled for this request. | 166 // Channel ID is disabled if privacy mode is enabled for this request. |
166 if (request_->privacy_mode == PRIVACY_MODE_ENABLED) | 167 if (request_->privacy_mode == PRIVACY_MODE_ENABLED) |
167 server_ssl_config_.channel_id_enabled = false; | 168 server_ssl_config_.channel_id_enabled = false; |
168 | 169 |
169 if (session_->params().enable_token_binding && | 170 if (session_->params().enable_token_binding && |
170 session_->params().channel_id_service) { | 171 session_->params().channel_id_service) { |
171 server_ssl_config_.token_binding_params.push_back(TB_PARAM_ECDSAP256); | 172 server_ssl_config_.token_binding_params.push_back(TB_PARAM_ECDSAP256); |
172 } | 173 } |
173 | 174 |
(...skipping 21 matching lines...) Expand all Loading... |
195 int HttpNetworkTransaction::RestartWithCertificate( | 196 int HttpNetworkTransaction::RestartWithCertificate( |
196 X509Certificate* client_cert, | 197 X509Certificate* client_cert, |
197 SSLPrivateKey* client_private_key, | 198 SSLPrivateKey* client_private_key, |
198 const CompletionCallback& callback) { | 199 const CompletionCallback& callback) { |
199 // In HandleCertificateRequest(), we always tear down existing stream | 200 // In HandleCertificateRequest(), we always tear down existing stream |
200 // requests to force a new connection. So we shouldn't have one here. | 201 // requests to force a new connection. So we shouldn't have one here. |
201 DCHECK(!stream_request_.get()); | 202 DCHECK(!stream_request_.get()); |
202 DCHECK(!stream_.get()); | 203 DCHECK(!stream_.get()); |
203 DCHECK_EQ(STATE_NONE, next_state_); | 204 DCHECK_EQ(STATE_NONE, next_state_); |
204 | 205 |
205 SSLConfig* ssl_config = response_.cert_request_info->is_proxy ? | 206 SSLConfig* ssl_config = response_->cert_request_info->is_proxy |
206 &proxy_ssl_config_ : &server_ssl_config_; | 207 ? &proxy_ssl_config_ |
| 208 : &server_ssl_config_; |
207 ssl_config->send_client_cert = true; | 209 ssl_config->send_client_cert = true; |
208 ssl_config->client_cert = client_cert; | 210 ssl_config->client_cert = client_cert; |
209 ssl_config->client_private_key = client_private_key; | 211 ssl_config->client_private_key = client_private_key; |
210 session_->ssl_client_auth_cache()->Add( | 212 session_->ssl_client_auth_cache()->Add( |
211 response_.cert_request_info->host_and_port, client_cert, | 213 response_->cert_request_info->host_and_port, client_cert, |
212 client_private_key); | 214 client_private_key); |
213 // Reset the other member variables. | 215 // Reset the other member variables. |
214 // Note: this is necessary only with SSL renegotiation. | 216 // Note: this is necessary only with SSL renegotiation. |
215 ResetStateForRestart(); | 217 ResetStateForRestart(); |
216 next_state_ = STATE_CREATE_STREAM; | 218 next_state_ = STATE_CREATE_STREAM; |
217 int rv = DoLoop(OK); | 219 int rv = DoLoop(OK); |
218 if (rv == ERR_IO_PENDING) | 220 if (rv == ERR_IO_PENDING) |
219 callback_ = callback; | 221 callback_ = callback; |
220 return rv; | 222 return rv; |
221 } | 223 } |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 int64_t HttpNetworkTransaction::GetTotalSentBytes() const { | 377 int64_t HttpNetworkTransaction::GetTotalSentBytes() const { |
376 int64_t total_sent_bytes = total_sent_bytes_; | 378 int64_t total_sent_bytes = total_sent_bytes_; |
377 if (stream_) | 379 if (stream_) |
378 total_sent_bytes += stream_->GetTotalSentBytes(); | 380 total_sent_bytes += stream_->GetTotalSentBytes(); |
379 return total_sent_bytes; | 381 return total_sent_bytes; |
380 } | 382 } |
381 | 383 |
382 void HttpNetworkTransaction::DoneReading() {} | 384 void HttpNetworkTransaction::DoneReading() {} |
383 | 385 |
384 const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const { | 386 const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const { |
385 return &response_; | 387 return response_.get(); |
386 } | 388 } |
387 | 389 |
388 LoadState HttpNetworkTransaction::GetLoadState() const { | 390 LoadState HttpNetworkTransaction::GetLoadState() const { |
389 // TODO(wtc): Define a new LoadState value for the | 391 // TODO(wtc): Define a new LoadState value for the |
390 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request. | 392 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request. |
391 switch (next_state_) { | 393 switch (next_state_) { |
392 case STATE_CREATE_STREAM: | 394 case STATE_CREATE_STREAM: |
393 return LOAD_STATE_WAITING_FOR_DELEGATE; | 395 return LOAD_STATE_WAITING_FOR_DELEGATE; |
394 case STATE_CREATE_STREAM_COMPLETE: | 396 case STATE_CREATE_STREAM_COMPLETE: |
395 return stream_request_->GetLoadState(); | 397 return stream_request_->GetLoadState(); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); | 480 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); |
479 DCHECK(stream_request_.get()); | 481 DCHECK(stream_request_.get()); |
480 | 482 |
481 if (stream_) { | 483 if (stream_) { |
482 total_received_bytes_ += stream_->GetTotalReceivedBytes(); | 484 total_received_bytes_ += stream_->GetTotalReceivedBytes(); |
483 total_sent_bytes_ += stream_->GetTotalSentBytes(); | 485 total_sent_bytes_ += stream_->GetTotalSentBytes(); |
484 } | 486 } |
485 stream_.reset(stream); | 487 stream_.reset(stream); |
486 server_ssl_config_ = used_ssl_config; | 488 server_ssl_config_ = used_ssl_config; |
487 proxy_info_ = used_proxy_info; | 489 proxy_info_ = used_proxy_info; |
488 response_.was_npn_negotiated = stream_request_->was_npn_negotiated(); | 490 response_->was_npn_negotiated = stream_request_->was_npn_negotiated(); |
489 response_.npn_negotiated_protocol = SSLClientSocket::NextProtoToString( | 491 response_->npn_negotiated_protocol = SSLClientSocket::NextProtoToString( |
490 stream_request_->protocol_negotiated()); | 492 stream_request_->protocol_negotiated()); |
491 response_.was_fetched_via_spdy = stream_request_->using_spdy(); | 493 response_->was_fetched_via_spdy = stream_request_->using_spdy(); |
492 response_.was_fetched_via_proxy = !proxy_info_.is_direct(); | 494 response_->was_fetched_via_proxy = !proxy_info_.is_direct(); |
493 if (response_.was_fetched_via_proxy && !proxy_info_.is_empty()) | 495 if (response_->was_fetched_via_proxy && !proxy_info_.is_empty()) |
494 response_.proxy_server = proxy_info_.proxy_server().host_port_pair(); | 496 response_->proxy_server = proxy_info_.proxy_server().host_port_pair(); |
495 OnIOComplete(OK); | 497 OnIOComplete(OK); |
496 } | 498 } |
497 | 499 |
498 void HttpNetworkTransaction::OnBidirectionalStreamImplReady( | 500 void HttpNetworkTransaction::OnBidirectionalStreamImplReady( |
499 const SSLConfig& used_ssl_config, | 501 const SSLConfig& used_ssl_config, |
500 const ProxyInfo& used_proxy_info, | 502 const ProxyInfo& used_proxy_info, |
501 BidirectionalStreamImpl* stream) { | 503 BidirectionalStreamImpl* stream) { |
502 NOTREACHED(); | 504 NOTREACHED(); |
503 } | 505 } |
504 | 506 |
(...skipping 19 matching lines...) Expand all Loading... |
524 | 526 |
525 void HttpNetworkTransaction::OnCertificateError( | 527 void HttpNetworkTransaction::OnCertificateError( |
526 int result, | 528 int result, |
527 const SSLConfig& used_ssl_config, | 529 const SSLConfig& used_ssl_config, |
528 const SSLInfo& ssl_info) { | 530 const SSLInfo& ssl_info) { |
529 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); | 531 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); |
530 DCHECK_NE(OK, result); | 532 DCHECK_NE(OK, result); |
531 DCHECK(stream_request_.get()); | 533 DCHECK(stream_request_.get()); |
532 DCHECK(!stream_.get()); | 534 DCHECK(!stream_.get()); |
533 | 535 |
534 response_.ssl_info = ssl_info; | 536 response_->ssl_info = ssl_info; |
535 server_ssl_config_ = used_ssl_config; | 537 server_ssl_config_ = used_ssl_config; |
536 | 538 |
537 // TODO(mbelshe): For now, we're going to pass the error through, and that | 539 // TODO(mbelshe): For now, we're going to pass the error through, and that |
538 // will close the stream_request in all cases. This means that we're always | 540 // will close the stream_request in all cases. This means that we're always |
539 // going to restart an entire STATE_CREATE_STREAM, even if the connection is | 541 // going to restart an entire STATE_CREATE_STREAM, even if the connection is |
540 // good and the user chooses to ignore the error. This is not ideal, but not | 542 // good and the user chooses to ignore the error. This is not ideal, but not |
541 // the end of the world either. | 543 // the end of the world either. |
542 | 544 |
543 OnIOComplete(result); | 545 OnIOComplete(result); |
544 } | 546 } |
545 | 547 |
546 void HttpNetworkTransaction::OnNeedsProxyAuth( | 548 void HttpNetworkTransaction::OnNeedsProxyAuth( |
547 const HttpResponseInfo& proxy_response, | 549 const HttpResponseInfo& proxy_response, |
548 const SSLConfig& used_ssl_config, | 550 const SSLConfig& used_ssl_config, |
549 const ProxyInfo& used_proxy_info, | 551 const ProxyInfo& used_proxy_info, |
550 HttpAuthController* auth_controller) { | 552 HttpAuthController* auth_controller) { |
551 DCHECK(stream_request_.get()); | 553 DCHECK(stream_request_.get()); |
552 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); | 554 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); |
553 | 555 |
554 establishing_tunnel_ = true; | 556 establishing_tunnel_ = true; |
555 response_.headers = proxy_response.headers; | 557 response_->headers = proxy_response.headers; |
556 response_.auth_challenge = proxy_response.auth_challenge; | 558 response_->auth_challenge = proxy_response.auth_challenge; |
557 headers_valid_ = true; | 559 headers_valid_ = true; |
558 server_ssl_config_ = used_ssl_config; | 560 server_ssl_config_ = used_ssl_config; |
559 proxy_info_ = used_proxy_info; | 561 proxy_info_ = used_proxy_info; |
560 | 562 |
561 auth_controllers_[HttpAuth::AUTH_PROXY] = auth_controller; | 563 auth_controllers_[HttpAuth::AUTH_PROXY] = auth_controller; |
562 pending_auth_target_ = HttpAuth::AUTH_PROXY; | 564 pending_auth_target_ = HttpAuth::AUTH_PROXY; |
563 | 565 |
564 DoCallback(OK); | 566 DoCallback(OK); |
565 } | 567 } |
566 | 568 |
567 void HttpNetworkTransaction::OnNeedsClientAuth( | 569 void HttpNetworkTransaction::OnNeedsClientAuth( |
568 const SSLConfig& used_ssl_config, | 570 const SSLConfig& used_ssl_config, |
569 SSLCertRequestInfo* cert_info) { | 571 SSLCertRequestInfo* cert_info) { |
570 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); | 572 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); |
571 | 573 |
572 server_ssl_config_ = used_ssl_config; | 574 server_ssl_config_ = used_ssl_config; |
573 response_.cert_request_info = cert_info; | 575 response_->cert_request_info = cert_info; |
574 OnIOComplete(ERR_SSL_CLIENT_AUTH_CERT_NEEDED); | 576 OnIOComplete(ERR_SSL_CLIENT_AUTH_CERT_NEEDED); |
575 } | 577 } |
576 | 578 |
577 void HttpNetworkTransaction::OnHttpsProxyTunnelResponse( | 579 void HttpNetworkTransaction::OnHttpsProxyTunnelResponse( |
578 const HttpResponseInfo& response_info, | 580 const HttpResponseInfo& response_info, |
579 const SSLConfig& used_ssl_config, | 581 const SSLConfig& used_ssl_config, |
580 const ProxyInfo& used_proxy_info, | 582 const ProxyInfo& used_proxy_info, |
581 HttpStream* stream) { | 583 HttpStream* stream) { |
582 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); | 584 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); |
583 | 585 |
584 CopyConnectionAttemptsFromStreamRequest(); | 586 CopyConnectionAttemptsFromStreamRequest(); |
585 | 587 |
586 headers_valid_ = true; | 588 headers_valid_ = true; |
587 response_ = response_info; | 589 *response_ = response_info; |
588 server_ssl_config_ = used_ssl_config; | 590 server_ssl_config_ = used_ssl_config; |
589 proxy_info_ = used_proxy_info; | 591 proxy_info_ = used_proxy_info; |
590 if (stream_) { | 592 if (stream_) { |
591 total_received_bytes_ += stream_->GetTotalReceivedBytes(); | 593 total_received_bytes_ += stream_->GetTotalReceivedBytes(); |
592 total_sent_bytes_ += stream_->GetTotalSentBytes(); | 594 total_sent_bytes_ += stream_->GetTotalSentBytes(); |
593 } | 595 } |
594 stream_.reset(stream); | 596 stream_.reset(stream); |
595 stream_request_.reset(); // we're done with the stream request | 597 stream_request_.reset(); // we're done with the stream request |
596 OnIOComplete(ERR_HTTPS_PROXY_TUNNEL_RESPONSE); | 598 OnIOComplete(ERR_HTTPS_PROXY_TUNNEL_RESPONSE); |
597 } | 599 } |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
788 return OK; | 790 return OK; |
789 return ERR_IO_PENDING; | 791 return ERR_IO_PENDING; |
790 } | 792 } |
791 | 793 |
792 int HttpNetworkTransaction::DoCreateStream() { | 794 int HttpNetworkTransaction::DoCreateStream() { |
793 // TODO(mmenke): Remove ScopedTracker below once crbug.com/424359 is fixed. | 795 // TODO(mmenke): Remove ScopedTracker below once crbug.com/424359 is fixed. |
794 tracked_objects::ScopedTracker tracking_profile( | 796 tracked_objects::ScopedTracker tracking_profile( |
795 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 797 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
796 "424359 HttpNetworkTransaction::DoCreateStream")); | 798 "424359 HttpNetworkTransaction::DoCreateStream")); |
797 | 799 |
798 response_.network_accessed = true; | 800 response_->network_accessed = true; |
799 | 801 |
800 next_state_ = STATE_CREATE_STREAM_COMPLETE; | 802 next_state_ = STATE_CREATE_STREAM_COMPLETE; |
801 if (ForWebSocketHandshake()) { | 803 if (ForWebSocketHandshake()) { |
802 stream_request_.reset( | 804 stream_request_.reset( |
803 session_->http_stream_factory_for_websocket() | 805 session_->http_stream_factory_for_websocket() |
804 ->RequestWebSocketHandshakeStream( | 806 ->RequestWebSocketHandshakeStream( |
805 *request_, | 807 *request_, |
806 priority_, | 808 priority_, |
807 server_ssl_config_, | 809 server_ssl_config_, |
808 proxy_ssl_config_, | 810 proxy_ssl_config_, |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1013 if (ShouldApplyServerAuth() && HaveAuth(HttpAuth::AUTH_SERVER)) | 1015 if (ShouldApplyServerAuth() && HaveAuth(HttpAuth::AUTH_SERVER)) |
1014 auth_controllers_[HttpAuth::AUTH_SERVER]->AddAuthorizationHeader( | 1016 auth_controllers_[HttpAuth::AUTH_SERVER]->AddAuthorizationHeader( |
1015 &request_headers_); | 1017 &request_headers_); |
1016 | 1018 |
1017 request_headers_.MergeFrom(request_->extra_headers); | 1019 request_headers_.MergeFrom(request_->extra_headers); |
1018 | 1020 |
1019 if (using_http_proxy_without_tunnel && | 1021 if (using_http_proxy_without_tunnel && |
1020 !before_proxy_headers_sent_callback_.is_null()) | 1022 !before_proxy_headers_sent_callback_.is_null()) |
1021 before_proxy_headers_sent_callback_.Run(proxy_info_, &request_headers_); | 1023 before_proxy_headers_sent_callback_.Run(proxy_info_, &request_headers_); |
1022 | 1024 |
1023 response_.did_use_http_auth = | 1025 response_->did_use_http_auth = |
1024 request_headers_.HasHeader(HttpRequestHeaders::kAuthorization) || | 1026 request_headers_.HasHeader(HttpRequestHeaders::kAuthorization) || |
1025 request_headers_.HasHeader(HttpRequestHeaders::kProxyAuthorization); | 1027 request_headers_.HasHeader(HttpRequestHeaders::kProxyAuthorization); |
1026 return OK; | 1028 return OK; |
1027 } | 1029 } |
1028 | 1030 |
1029 int HttpNetworkTransaction::BuildTokenBindingHeader(std::string* out) { | 1031 int HttpNetworkTransaction::BuildTokenBindingHeader(std::string* out) { |
1030 base::TimeTicks start = base::TimeTicks::Now(); | 1032 base::TimeTicks start = base::TimeTicks::Now(); |
1031 std::vector<uint8_t> signed_ekm; | 1033 std::vector<uint8_t> signed_ekm; |
1032 int rv = stream_->GetSignedEKMForTokenBinding(token_binding_key_.get(), | 1034 int rv = stream_->GetSignedEKMForTokenBinding(token_binding_key_.get(), |
1033 &signed_ekm); | 1035 &signed_ekm); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1090 | 1092 |
1091 int HttpNetworkTransaction::DoSendRequest() { | 1093 int HttpNetworkTransaction::DoSendRequest() { |
1092 // TODO(mmenke): Remove ScopedTracker below once crbug.com/424359 is fixed. | 1094 // TODO(mmenke): Remove ScopedTracker below once crbug.com/424359 is fixed. |
1093 tracked_objects::ScopedTracker tracking_profile( | 1095 tracked_objects::ScopedTracker tracking_profile( |
1094 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 1096 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
1095 "424359 HttpNetworkTransaction::DoSendRequest")); | 1097 "424359 HttpNetworkTransaction::DoSendRequest")); |
1096 | 1098 |
1097 send_start_time_ = base::TimeTicks::Now(); | 1099 send_start_time_ = base::TimeTicks::Now(); |
1098 next_state_ = STATE_SEND_REQUEST_COMPLETE; | 1100 next_state_ = STATE_SEND_REQUEST_COMPLETE; |
1099 | 1101 |
1100 return stream_->SendRequest(request_headers_, &response_, io_callback_); | 1102 return stream_->SendRequest(request_headers_, response_.get(), io_callback_); |
1101 } | 1103 } |
1102 | 1104 |
1103 int HttpNetworkTransaction::DoSendRequestComplete(int result) { | 1105 int HttpNetworkTransaction::DoSendRequestComplete(int result) { |
1104 send_end_time_ = base::TimeTicks::Now(); | 1106 send_end_time_ = base::TimeTicks::Now(); |
1105 if (result < 0) | 1107 if (result < 0) |
1106 return HandleIOError(result); | 1108 return HandleIOError(result); |
1107 next_state_ = STATE_READ_HEADERS; | 1109 next_state_ = STATE_READ_HEADERS; |
1108 return OK; | 1110 return OK; |
1109 } | 1111 } |
1110 | 1112 |
1111 int HttpNetworkTransaction::DoReadHeaders() { | 1113 int HttpNetworkTransaction::DoReadHeaders() { |
1112 next_state_ = STATE_READ_HEADERS_COMPLETE; | 1114 next_state_ = STATE_READ_HEADERS_COMPLETE; |
1113 return stream_->ReadResponseHeaders(io_callback_); | 1115 return stream_->ReadResponseHeaders(io_callback_); |
1114 } | 1116 } |
1115 | 1117 |
1116 int HttpNetworkTransaction::DoReadHeadersComplete(int result) { | 1118 int HttpNetworkTransaction::DoReadHeadersComplete(int result) { |
1117 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here | 1119 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here |
1118 // due to SSL renegotiation. | 1120 // due to SSL renegotiation. |
1119 if (IsCertificateError(result)) { | 1121 if (IsCertificateError(result)) { |
1120 // We don't handle a certificate error during SSL renegotiation, so we | 1122 // We don't handle a certificate error during SSL renegotiation, so we |
1121 // have to return an error that's not in the certificate error range | 1123 // have to return an error that's not in the certificate error range |
1122 // (-2xx). | 1124 // (-2xx). |
1123 LOG(ERROR) << "Got a server certificate with error " << result | 1125 LOG(ERROR) << "Got a server certificate with error " << result |
1124 << " during SSL renegotiation"; | 1126 << " during SSL renegotiation"; |
1125 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION; | 1127 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION; |
1126 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { | 1128 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { |
1127 // TODO(wtc): Need a test case for this code path! | 1129 // TODO(wtc): Need a test case for this code path! |
1128 DCHECK(stream_.get()); | 1130 DCHECK(stream_.get()); |
1129 DCHECK(IsSecureRequest()); | 1131 DCHECK(IsSecureRequest()); |
1130 response_.cert_request_info = new SSLCertRequestInfo; | 1132 response_->cert_request_info = new SSLCertRequestInfo; |
1131 stream_->GetSSLCertRequestInfo(response_.cert_request_info.get()); | 1133 stream_->GetSSLCertRequestInfo(response_->cert_request_info.get()); |
1132 result = HandleCertificateRequest(result); | 1134 result = HandleCertificateRequest(result); |
1133 if (result == OK) | 1135 if (result == OK) |
1134 return result; | 1136 return result; |
1135 } | 1137 } |
1136 | 1138 |
1137 if (result == ERR_HTTP_1_1_REQUIRED || | 1139 if (result == ERR_HTTP_1_1_REQUIRED || |
1138 result == ERR_PROXY_HTTP_1_1_REQUIRED) { | 1140 result == ERR_PROXY_HTTP_1_1_REQUIRED) { |
1139 return HandleHttp11Required(result); | 1141 return HandleHttp11Required(result); |
1140 } | 1142 } |
1141 | 1143 |
1142 // ERR_CONNECTION_CLOSED is treated differently at this point; if partial | 1144 // ERR_CONNECTION_CLOSED is treated differently at this point; if partial |
1143 // response headers were received, we do the best we can to make sense of it | 1145 // response headers were received, we do the best we can to make sense of it |
1144 // and send it back up the stack. | 1146 // and send it back up the stack. |
1145 // | 1147 // |
1146 // TODO(davidben): Consider moving this to HttpBasicStream, It's a little | 1148 // TODO(davidben): Consider moving this to HttpBasicStream, It's a little |
1147 // bizarre for SPDY. Assuming this logic is useful at all. | 1149 // bizarre for SPDY. Assuming this logic is useful at all. |
1148 // TODO(davidben): Bubble the error code up so we do not cache? | 1150 // TODO(davidben): Bubble the error code up so we do not cache? |
1149 if (result == ERR_CONNECTION_CLOSED && response_.headers.get()) | 1151 if (result == ERR_CONNECTION_CLOSED && response_->headers.get()) |
1150 result = OK; | 1152 result = OK; |
1151 | 1153 |
1152 if (result < 0) | 1154 if (result < 0) |
1153 return HandleIOError(result); | 1155 return HandleIOError(result); |
1154 | 1156 |
1155 DCHECK(response_.headers.get()); | 1157 DCHECK(response_->headers.get()); |
1156 | 1158 |
1157 // On a 408 response from the server ("Request Timeout") on a stale socket, | 1159 // On a 408 response from the server ("Request Timeout") on a stale socket, |
1158 // retry the request. | 1160 // retry the request. |
1159 // Headers can be NULL because of http://crbug.com/384554. | 1161 // Headers can be NULL because of http://crbug.com/384554. |
1160 if (response_.headers.get() && response_.headers->response_code() == 408 && | 1162 if (response_->headers.get() && response_->headers->response_code() == 408 && |
1161 stream_->IsConnectionReused()) { | 1163 stream_->IsConnectionReused()) { |
1162 net_log_.AddEventWithNetErrorCode( | 1164 net_log_.AddEventWithNetErrorCode( |
1163 NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR, | 1165 NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR, |
1164 response_.headers->response_code()); | 1166 response_->headers->response_code()); |
1165 // This will close the socket - it would be weird to try and reuse it, even | 1167 // This will close the socket - it would be weird to try and reuse it, even |
1166 // if the server doesn't actually close it. | 1168 // if the server doesn't actually close it. |
1167 ResetConnectionAndRequestForResend(); | 1169 ResetConnectionAndRequestForResend(); |
1168 return OK; | 1170 return OK; |
1169 } | 1171 } |
1170 | 1172 |
1171 // Like Net.HttpResponseCode, but only for MAIN_FRAME loads. | 1173 // Like Net.HttpResponseCode, but only for MAIN_FRAME loads. |
1172 if (request_->load_flags & LOAD_MAIN_FRAME) { | 1174 if (request_->load_flags & LOAD_MAIN_FRAME) { |
1173 const int response_code = response_.headers->response_code(); | 1175 const int response_code = response_->headers->response_code(); |
1174 UMA_HISTOGRAM_ENUMERATION( | 1176 UMA_HISTOGRAM_ENUMERATION( |
1175 "Net.HttpResponseCode_Nxx_MainFrame", response_code/100, 10); | 1177 "Net.HttpResponseCode_Nxx_MainFrame", response_code/100, 10); |
1176 } | 1178 } |
1177 | 1179 |
1178 net_log_.AddEvent( | 1180 net_log_.AddEvent( |
1179 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS, | 1181 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS, |
1180 base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers)); | 1182 base::Bind(&HttpResponseHeaders::NetLogCallback, response_->headers)); |
1181 | 1183 |
1182 if (response_.headers->GetHttpVersion() < HttpVersion(1, 0)) { | 1184 if (response_->headers->GetHttpVersion() < HttpVersion(1, 0)) { |
1183 // HTTP/0.9 doesn't support the PUT method, so lack of response headers | 1185 // HTTP/0.9 doesn't support the PUT method, so lack of response headers |
1184 // indicates a buggy server. See: | 1186 // indicates a buggy server. See: |
1185 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921 | 1187 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921 |
1186 if (request_->method == "PUT") | 1188 if (request_->method == "PUT") |
1187 return ERR_METHOD_NOT_SUPPORTED; | 1189 return ERR_METHOD_NOT_SUPPORTED; |
1188 } | 1190 } |
1189 | 1191 |
1190 // Check for an intermediate 100 Continue response. An origin server is | 1192 // Check for an intermediate 100 Continue response. An origin server is |
1191 // allowed to send this response even if we didn't ask for it, so we just | 1193 // allowed to send this response even if we didn't ask for it, so we just |
1192 // need to skip over it. | 1194 // need to skip over it. |
1193 // We treat any other 1xx in this same way (although in practice getting | 1195 // We treat any other 1xx in this same way (although in practice getting |
1194 // a 1xx that isn't a 100 is rare). | 1196 // a 1xx that isn't a 100 is rare). |
1195 // Unless this is a WebSocket request, in which case we pass it on up. | 1197 // Unless this is a WebSocket request, in which case we pass it on up. |
1196 if (response_.headers->response_code() / 100 == 1 && | 1198 if (response_->headers->response_code() / 100 == 1 && |
1197 !ForWebSocketHandshake()) { | 1199 !ForWebSocketHandshake()) { |
1198 response_.headers = new HttpResponseHeaders(std::string()); | 1200 response_->headers = new HttpResponseHeaders(std::string()); |
1199 next_state_ = STATE_READ_HEADERS; | 1201 next_state_ = STATE_READ_HEADERS; |
1200 return OK; | 1202 return OK; |
1201 } | 1203 } |
1202 | 1204 |
1203 session_->http_stream_factory()->ProcessAlternativeServices( | 1205 session_->http_stream_factory()->ProcessAlternativeServices( |
1204 session_, response_.headers.get(), HostPortPair::FromURL(request_->url)); | 1206 session_, response_->headers.get(), HostPortPair::FromURL(request_->url)); |
1205 | 1207 |
1206 if (IsSecureRequest()) | 1208 if (IsSecureRequest()) |
1207 stream_->GetSSLInfo(&response_.ssl_info); | 1209 stream_->GetSSLInfo(&response_->ssl_info); |
1208 | 1210 |
1209 int rv = HandleAuthChallenge(); | 1211 int rv = HandleAuthChallenge(); |
1210 if (rv != OK) | 1212 if (rv != OK) |
1211 return rv; | 1213 return rv; |
1212 | 1214 |
1213 headers_valid_ = true; | 1215 headers_valid_ = true; |
1214 return OK; | 1216 return OK; |
1215 } | 1217 } |
1216 | 1218 |
1217 int HttpNetworkTransaction::DoReadBody() { | 1219 int HttpNetworkTransaction::DoReadBody() { |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1321 // The server is asking for a client certificate during the initial | 1323 // The server is asking for a client certificate during the initial |
1322 // handshake. | 1324 // handshake. |
1323 stream_request_.reset(); | 1325 stream_request_.reset(); |
1324 | 1326 |
1325 // If the user selected one of the certificates in client_certs or declined | 1327 // If the user selected one of the certificates in client_certs or declined |
1326 // to provide one for this server before, use the past decision | 1328 // to provide one for this server before, use the past decision |
1327 // automatically. | 1329 // automatically. |
1328 scoped_refptr<X509Certificate> client_cert; | 1330 scoped_refptr<X509Certificate> client_cert; |
1329 scoped_refptr<SSLPrivateKey> client_private_key; | 1331 scoped_refptr<SSLPrivateKey> client_private_key; |
1330 bool found_cached_cert = session_->ssl_client_auth_cache()->Lookup( | 1332 bool found_cached_cert = session_->ssl_client_auth_cache()->Lookup( |
1331 response_.cert_request_info->host_and_port, &client_cert, | 1333 response_->cert_request_info->host_and_port, &client_cert, |
1332 &client_private_key); | 1334 &client_private_key); |
1333 if (!found_cached_cert) | 1335 if (!found_cached_cert) |
1334 return error; | 1336 return error; |
1335 | 1337 |
1336 // Check that the certificate selected is still a certificate the server | 1338 // Check that the certificate selected is still a certificate the server |
1337 // is likely to accept, based on the criteria supplied in the | 1339 // is likely to accept, based on the criteria supplied in the |
1338 // CertificateRequest message. | 1340 // CertificateRequest message. |
1339 if (client_cert.get()) { | 1341 if (client_cert.get()) { |
1340 const std::vector<std::string>& cert_authorities = | 1342 const std::vector<std::string>& cert_authorities = |
1341 response_.cert_request_info->cert_authorities; | 1343 response_->cert_request_info->cert_authorities; |
1342 | 1344 |
1343 bool cert_still_valid = cert_authorities.empty() || | 1345 bool cert_still_valid = cert_authorities.empty() || |
1344 client_cert->IsIssuedByEncoded(cert_authorities); | 1346 client_cert->IsIssuedByEncoded(cert_authorities); |
1345 if (!cert_still_valid) | 1347 if (!cert_still_valid) |
1346 return error; | 1348 return error; |
1347 } | 1349 } |
1348 | 1350 |
1349 // TODO(davidben): Add a unit test which covers this path; we need to be | 1351 // TODO(davidben): Add a unit test which covers this path; we need to be |
1350 // able to send a legitimate certificate and also bypass/clear the | 1352 // able to send a legitimate certificate and also bypass/clear the |
1351 // SSL session cache. | 1353 // SSL session cache. |
1352 SSLConfig* ssl_config = response_.cert_request_info->is_proxy ? | 1354 SSLConfig* ssl_config = response_->cert_request_info->is_proxy |
1353 &proxy_ssl_config_ : &server_ssl_config_; | 1355 ? &proxy_ssl_config_ |
| 1356 : &server_ssl_config_; |
1354 ssl_config->send_client_cert = true; | 1357 ssl_config->send_client_cert = true; |
1355 ssl_config->client_cert = client_cert; | 1358 ssl_config->client_cert = client_cert; |
1356 ssl_config->client_private_key = client_private_key; | 1359 ssl_config->client_private_key = client_private_key; |
1357 next_state_ = STATE_CREATE_STREAM; | 1360 next_state_ = STATE_CREATE_STREAM; |
1358 // Reset the other member variables. | 1361 // Reset the other member variables. |
1359 // Note: this is necessary only with SSL renegotiation. | 1362 // Note: this is necessary only with SSL renegotiation. |
1360 ResetStateForRestart(); | 1363 ResetStateForRestart(); |
1361 return OK; | 1364 return OK; |
1362 } | 1365 } |
1363 | 1366 |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1515 total_sent_bytes_ += stream_->GetTotalSentBytes(); | 1518 total_sent_bytes_ += stream_->GetTotalSentBytes(); |
1516 } | 1519 } |
1517 CacheNetErrorDetailsAndResetStream(); | 1520 CacheNetErrorDetailsAndResetStream(); |
1518 } | 1521 } |
1519 | 1522 |
1520 void HttpNetworkTransaction::ResetStateForAuthRestart() { | 1523 void HttpNetworkTransaction::ResetStateForAuthRestart() { |
1521 send_start_time_ = base::TimeTicks(); | 1524 send_start_time_ = base::TimeTicks(); |
1522 send_end_time_ = base::TimeTicks(); | 1525 send_end_time_ = base::TimeTicks(); |
1523 | 1526 |
1524 pending_auth_target_ = HttpAuth::AUTH_NONE; | 1527 pending_auth_target_ = HttpAuth::AUTH_NONE; |
1525 read_buf_ = NULL; | 1528 read_buf_ = nullptr; |
1526 read_buf_len_ = 0; | 1529 read_buf_len_ = 0; |
1527 headers_valid_ = false; | 1530 headers_valid_ = false; |
1528 request_headers_.Clear(); | 1531 request_headers_.Clear(); |
1529 response_ = HttpResponseInfo(); | 1532 *response_ = HttpResponseInfo(); |
1530 establishing_tunnel_ = false; | 1533 establishing_tunnel_ = false; |
1531 remote_endpoint_ = IPEndPoint(); | 1534 remote_endpoint_ = IPEndPoint(); |
1532 net_error_details_.quic_broken = false; | 1535 net_error_details_.quic_broken = false; |
1533 net_error_details_.quic_connection_error = QUIC_NO_ERROR; | 1536 net_error_details_.quic_connection_error = QUIC_NO_ERROR; |
1534 token_binding_key_.reset(); | 1537 token_binding_key_.reset(); |
1535 } | 1538 } |
1536 | 1539 |
1537 void HttpNetworkTransaction::CacheNetErrorDetailsAndResetStream() { | 1540 void HttpNetworkTransaction::CacheNetErrorDetailsAndResetStream() { |
1538 if (stream_) | 1541 if (stream_) |
1539 stream_->PopulateNetErrorDetails(&net_error_details_); | 1542 stream_->PopulateNetErrorDetails(&net_error_details_); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1602 // Record the error code which triggered the fallback and the state the | 1605 // Record the error code which triggered the fallback and the state the |
1603 // handshake was in. | 1606 // handshake was in. |
1604 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLFallbackErrorCode", | 1607 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLFallbackErrorCode", |
1605 -fallback_error_code_); | 1608 -fallback_error_code_); |
1606 UMA_HISTOGRAM_ENUMERATION("Net.SSLFallbackFailureState", | 1609 UMA_HISTOGRAM_ENUMERATION("Net.SSLFallbackFailureState", |
1607 fallback_failure_state_, SSL_FAILURE_MAX); | 1610 fallback_failure_state_, SSL_FAILURE_MAX); |
1608 } | 1611 } |
1609 } | 1612 } |
1610 | 1613 |
1611 HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const { | 1614 HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const { |
1612 return response_.headers.get(); | 1615 return response_->headers.get(); |
1613 } | 1616 } |
1614 | 1617 |
1615 bool HttpNetworkTransaction::ShouldResendRequest() const { | 1618 bool HttpNetworkTransaction::ShouldResendRequest() const { |
1616 bool connection_is_proven = stream_->IsConnectionReused(); | 1619 bool connection_is_proven = stream_->IsConnectionReused(); |
1617 bool has_received_headers = GetResponseHeaders() != NULL; | 1620 bool has_received_headers = GetResponseHeaders() != NULL; |
1618 | 1621 |
1619 // NOTE: we resend a request only if we reused a keep-alive connection. | 1622 // NOTE: we resend a request only if we reused a keep-alive connection. |
1620 // This automatically prevents an infinite resend loop because we'll run | 1623 // This automatically prevents an infinite resend loop because we'll run |
1621 // out of the cached keep-alive connections eventually. | 1624 // out of the cached keep-alive connections eventually. |
1622 if (connection_is_proven && !has_received_headers) | 1625 if (connection_is_proven && !has_received_headers) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1658 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) | 1661 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) |
1659 return ERR_UNEXPECTED_PROXY_AUTH; | 1662 return ERR_UNEXPECTED_PROXY_AUTH; |
1660 | 1663 |
1661 // This case can trigger when an HTTPS server responds with a "Proxy | 1664 // This case can trigger when an HTTPS server responds with a "Proxy |
1662 // authentication required" status code through a non-authenticating | 1665 // authentication required" status code through a non-authenticating |
1663 // proxy. | 1666 // proxy. |
1664 if (!auth_controllers_[target].get()) | 1667 if (!auth_controllers_[target].get()) |
1665 return ERR_UNEXPECTED_PROXY_AUTH; | 1668 return ERR_UNEXPECTED_PROXY_AUTH; |
1666 | 1669 |
1667 int rv = auth_controllers_[target]->HandleAuthChallenge( | 1670 int rv = auth_controllers_[target]->HandleAuthChallenge( |
1668 headers, response_.ssl_info, | 1671 headers, response_->ssl_info, |
1669 (request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA) != 0, false, | 1672 (request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA) != 0, false, |
1670 net_log_); | 1673 net_log_); |
1671 if (auth_controllers_[target]->HaveAuthHandler()) | 1674 if (auth_controllers_[target]->HaveAuthHandler()) |
1672 pending_auth_target_ = target; | 1675 pending_auth_target_ = target; |
1673 | 1676 |
1674 scoped_refptr<AuthChallengeInfo> auth_info = | 1677 scoped_refptr<AuthChallengeInfo> auth_info = |
1675 auth_controllers_[target]->auth_info(); | 1678 auth_controllers_[target]->auth_info(); |
1676 if (auth_info.get()) | 1679 if (auth_info.get()) |
1677 response_.auth_challenge = auth_info; | 1680 response_->auth_challenge = auth_info; |
1678 | 1681 |
1679 return rv; | 1682 return rv; |
1680 } | 1683 } |
1681 | 1684 |
1682 bool HttpNetworkTransaction::HaveAuth(HttpAuth::Target target) const { | 1685 bool HttpNetworkTransaction::HaveAuth(HttpAuth::Target target) const { |
1683 return auth_controllers_[target].get() && | 1686 return auth_controllers_[target].get() && |
1684 auth_controllers_[target]->HaveAuth(); | 1687 auth_controllers_[target]->HaveAuth(); |
1685 } | 1688 } |
1686 | 1689 |
1687 GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const { | 1690 GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const { |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1756 DCHECK(stream_request_); | 1759 DCHECK(stream_request_); |
1757 | 1760 |
1758 // Since the transaction can restart with auth credentials, it may create a | 1761 // Since the transaction can restart with auth credentials, it may create a |
1759 // stream more than once. Accumulate all of the connection attempts across | 1762 // stream more than once. Accumulate all of the connection attempts across |
1760 // those streams by appending them to the vector: | 1763 // those streams by appending them to the vector: |
1761 for (const auto& attempt : stream_request_->connection_attempts()) | 1764 for (const auto& attempt : stream_request_->connection_attempts()) |
1762 connection_attempts_.push_back(attempt); | 1765 connection_attempts_.push_back(attempt); |
1763 } | 1766 } |
1764 | 1767 |
1765 } // namespace net | 1768 } // namespace net |
OLD | NEW |