Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 // TODO(ukai): code is similar with http_network_transaction.cc. We should | 5 // TODO(ukai): code is similar with http_network_transaction.cc. We should |
| 6 // think about ways to share code, if possible. | 6 // think about ways to share code, if possible. |
| 7 | 7 |
| 8 #include "net/socket_stream/socket_stream.h" | 8 #include "net/socket_stream/socket_stream.h" |
| 9 | 9 |
| 10 #include <string> | 10 #include <string> |
| 11 | 11 |
| 12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
| 15 #include "base/string_util.h" | 15 #include "base/string_util.h" |
| 16 #include "net/base/auth.h" | |
| 16 #include "net/base/host_resolver.h" | 17 #include "net/base/host_resolver.h" |
| 17 #include "net/base/io_buffer.h" | 18 #include "net/base/io_buffer.h" |
| 18 #include "net/base/net_errors.h" | 19 #include "net/base/net_errors.h" |
| 19 #include "net/base/net_util.h" | 20 #include "net/base/net_util.h" |
| 20 #include "net/http/http_response_headers.h" | 21 #include "net/http/http_response_headers.h" |
| 21 #include "net/http/http_util.h" | 22 #include "net/http/http_util.h" |
| 22 #include "net/socket/client_socket_factory.h" | 23 #include "net/socket/client_socket_factory.h" |
| 23 #include "net/socket/ssl_client_socket.h" | 24 #include "net/socket/ssl_client_socket.h" |
| 24 #include "net/socket/socks5_client_socket.h" | 25 #include "net/socket/socks5_client_socket.h" |
| 25 #include "net/socket/socks_client_socket.h" | 26 #include "net/socket/socks_client_socket.h" |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 142 return; | 143 return; |
| 143 if (socket_->IsConnected()) | 144 if (socket_->IsConnected()) |
| 144 socket_->Disconnect(); | 145 socket_->Disconnect(); |
| 145 // Close asynchronously, so that delegate won't be called | 146 // Close asynchronously, so that delegate won't be called |
| 146 // back before returning Close(). | 147 // back before returning Close(). |
| 147 MessageLoop::current()->PostTask( | 148 MessageLoop::current()->PostTask( |
| 148 FROM_HERE, | 149 FROM_HERE, |
| 149 NewRunnableMethod(this, &SocketStream::DoLoop, OK)); | 150 NewRunnableMethod(this, &SocketStream::DoLoop, OK)); |
| 150 } | 151 } |
| 151 | 152 |
| 153 void SocketStream::RestartWithAuth( | |
| 154 const std::wstring& username, const std::wstring& password) { | |
| 155 DCHECK(MessageLoop::current()) << | |
| 156 "The current MessageLoop must exist"; | |
| 157 DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) << | |
| 158 "The current MessageLoop must be TYPE_IO"; | |
| 159 DCHECK(auth_handler_); | |
| 160 if (!socket_.get()) { | |
| 161 LOG(ERROR) << "Socket is closed before restarting with auth."; | |
| 162 return; | |
| 163 } | |
| 164 | |
| 165 if (auth_identity_.invalid) { | |
| 166 // Update the username/password. | |
| 167 auth_identity_.source = HttpAuth::IDENT_SRC_EXTERNAL; | |
| 168 auth_identity_.invalid = false; | |
| 169 auth_identity_.username = username; | |
| 170 auth_identity_.password = password; | |
| 171 } | |
| 172 | |
| 173 MessageLoop::current()->PostTask( | |
| 174 FROM_HERE, | |
| 175 NewRunnableMethod(this, &SocketStream::DoRestartWithAuth)); | |
| 176 } | |
| 177 | |
| 152 void SocketStream::DetachDelegate() { | 178 void SocketStream::DetachDelegate() { |
| 153 if (!delegate_) | 179 if (!delegate_) |
| 154 return; | 180 return; |
| 155 delegate_ = NULL; | 181 delegate_ = NULL; |
| 156 Close(); | 182 Close(); |
| 157 } | 183 } |
| 158 | 184 |
| 159 void SocketStream::Finish() { | 185 void SocketStream::Finish() { |
| 160 DCHECK(MessageLoop::current()) << | 186 DCHECK(MessageLoop::current()) << |
| 161 "The current MessageLoop must exist"; | 187 "The current MessageLoop must exist"; |
| 162 DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) << | 188 DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) << |
| 163 "The current MessageLoop must be TYPE_IO"; | 189 "The current MessageLoop must be TYPE_IO"; |
| 190 DLOG(INFO) << "Finish"; | |
| 164 Delegate* delegate = delegate_; | 191 Delegate* delegate = delegate_; |
| 165 delegate_ = NULL; | 192 delegate_ = NULL; |
| 166 if (delegate) { | 193 if (delegate) { |
| 167 delegate->OnClose(this); | 194 delegate->OnClose(this); |
| 168 Release(); | 195 Release(); |
| 169 } | 196 } |
| 170 } | 197 } |
| 171 | 198 |
| 172 void SocketStream::SetHostResolver(HostResolver* host_resolver) { | 199 void SocketStream::SetHostResolver(HostResolver* host_resolver) { |
| 173 DCHECK(host_resolver); | 200 DCHECK(host_resolver); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 198 DCHECK_GT(result, 0); | 225 DCHECK_GT(result, 0); |
| 199 if (!delegate_) | 226 if (!delegate_) |
| 200 return; | 227 return; |
| 201 // Notify recevied data to delegate. | 228 // Notify recevied data to delegate. |
| 202 delegate_->OnReceivedData(this, read_buf_->data(), result); | 229 delegate_->OnReceivedData(this, read_buf_->data(), result); |
| 203 read_buf_ = NULL; | 230 read_buf_ = NULL; |
| 204 } | 231 } |
| 205 | 232 |
| 206 void SocketStream::DidSendData(int result) { | 233 void SocketStream::DidSendData(int result) { |
| 207 current_write_buf_ = NULL; | 234 current_write_buf_ = NULL; |
| 208 DCHECK(result > 0); | 235 DCHECK_GT(result, 0); |
| 209 if (!delegate_) | 236 if (!delegate_) |
| 210 return; | 237 return; |
| 211 | 238 |
| 212 delegate_->OnSentData(this, result); | 239 delegate_->OnSentData(this, result); |
| 213 int remaining_size = write_buf_size_ - write_buf_offset_ - result; | 240 int remaining_size = write_buf_size_ - write_buf_offset_ - result; |
| 214 if (remaining_size == 0) { | 241 if (remaining_size == 0) { |
| 215 if (!pending_write_bufs_.empty()) { | 242 if (!pending_write_bufs_.empty()) { |
| 216 write_buf_size_ = pending_write_bufs_.front()->size(); | 243 write_buf_size_ = pending_write_bufs_.front()->size(); |
| 217 write_buf_ = pending_write_bufs_.front(); | 244 write_buf_ = pending_write_bufs_.front(); |
| 218 pending_write_bufs_.pop_front(); | 245 pending_write_bufs_.pop_front(); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 371 | 398 |
| 372 HostResolver::RequestInfo resolve_info(host, port); | 399 HostResolver::RequestInfo resolve_info(host, port); |
| 373 | 400 |
| 374 resolver_.reset(new SingleRequestHostResolver(host_resolver_.get())); | 401 resolver_.reset(new SingleRequestHostResolver(host_resolver_.get())); |
| 375 return resolver_->Resolve(resolve_info, &addresses_, &io_callback_, NULL); | 402 return resolver_->Resolve(resolve_info, &addresses_, &io_callback_, NULL); |
| 376 } | 403 } |
| 377 | 404 |
| 378 int SocketStream::DoResolveHostComplete(int result) { | 405 int SocketStream::DoResolveHostComplete(int result) { |
| 379 if (result == OK) | 406 if (result == OK) |
| 380 next_state_ = STATE_TCP_CONNECT; | 407 next_state_ = STATE_TCP_CONNECT; |
| 408 // TODO(ukai): if error occured, reconsider proxy after error. | |
| 381 return result; | 409 return result; |
| 382 } | 410 } |
| 383 | 411 |
| 384 int SocketStream::DoTcpConnect() { | 412 int SocketStream::DoTcpConnect() { |
| 385 next_state_ = STATE_TCP_CONNECT_COMPLETE; | 413 next_state_ = STATE_TCP_CONNECT_COMPLETE; |
| 386 DCHECK(factory_); | 414 DCHECK(factory_); |
| 387 socket_.reset(factory_->CreateTCPClientSocket(addresses_)); | 415 socket_.reset(factory_->CreateTCPClientSocket(addresses_)); |
| 388 return socket_->Connect(&io_callback_); | 416 return socket_->Connect(&io_callback_); |
| 389 } | 417 } |
| 390 | 418 |
| 391 int SocketStream::DoTcpConnectComplete(int result) { | 419 int SocketStream::DoTcpConnectComplete(int result) { |
| 420 // TODO(ukai): if error occured, reconsider proxy after error. | |
| 392 if (result != OK) | 421 if (result != OK) |
| 393 return result; | 422 return result; |
| 394 | 423 |
| 395 if (proxy_mode_ == kTunnelProxy) | 424 if (proxy_mode_ == kTunnelProxy) |
| 396 next_state_ = STATE_WRITE_TUNNEL_HEADERS; | 425 next_state_ = STATE_WRITE_TUNNEL_HEADERS; |
| 397 else if (proxy_mode_ == kSOCKSProxy) | 426 else if (proxy_mode_ == kSOCKSProxy) |
| 398 next_state_ = STATE_SOCKS_CONNECT; | 427 next_state_ = STATE_SOCKS_CONNECT; |
| 399 else if (is_secure()) { | 428 else if (is_secure()) { |
| 400 next_state_ = STATE_SSL_CONNECT; | 429 next_state_ = STATE_SSL_CONNECT; |
| 401 } else { | 430 } else { |
| 402 DidEstablishConnection(); | 431 DidEstablishConnection(); |
| 403 } | 432 } |
| 404 return OK; | 433 return OK; |
| 405 } | 434 } |
| 406 | 435 |
| 407 int SocketStream::DoWriteTunnelHeaders() { | 436 int SocketStream::DoWriteTunnelHeaders() { |
| 408 DCHECK_EQ(kTunnelProxy, proxy_mode_); | 437 DCHECK_EQ(kTunnelProxy, proxy_mode_); |
| 409 | 438 |
| 410 next_state_ = STATE_WRITE_TUNNEL_HEADERS_COMPLETE; | 439 next_state_ = STATE_WRITE_TUNNEL_HEADERS_COMPLETE; |
| 411 | 440 |
| 412 if (!tunnel_request_headers_.get()) { | 441 if (!tunnel_request_headers_.get()) { |
| 413 tunnel_request_headers_ = new RequestHeaders(); | 442 tunnel_request_headers_ = new RequestHeaders(); |
| 414 tunnel_request_headers_bytes_sent_ = 0; | 443 tunnel_request_headers_bytes_sent_ = 0; |
| 415 } | 444 } |
| 416 if (tunnel_request_headers_->headers_.empty()) { | 445 if (tunnel_request_headers_->headers_.empty()) { |
| 446 std::string authorization_headers; | |
| 447 | |
| 448 if (!auth_handler_.get()) { | |
| 449 // First attempt. Find auth from the proxy address. | |
| 450 HttpAuthCache::Entry* entry = auth_cache_.LookupByPath( | |
| 451 ProxyAuthOrigin(), std::string()); | |
| 452 if (entry && !entry->handler()->is_connection_based()) { | |
| 453 auth_identity_.source = HttpAuth::IDENT_SRC_PATH_LOOKUP; | |
| 454 auth_identity_.invalid = false; | |
| 455 auth_identity_.username = entry->username(); | |
| 456 auth_identity_.password = entry->password(); | |
| 457 auth_handler_ = entry->handler(); | |
| 458 } | |
| 459 } | |
| 460 | |
| 461 // Support basic authentication scheme only, because we don't have | |
| 462 // HttpRequestInfo. | |
| 463 // TODO(ukai): Add support other authentication scheme. | |
| 464 if (auth_handler_.get() && auth_handler_->scheme() == "basic") { | |
| 465 std::string credentials = auth_handler_->GenerateCredentials( | |
| 466 auth_identity_.username, | |
| 467 auth_identity_.password, | |
| 468 NULL, | |
| 469 &proxy_info_); | |
| 470 authorization_headers.append( | |
| 471 HttpAuth::GetAuthorizationHeaderName(HttpAuth::AUTH_PROXY) + | |
| 472 ": " + credentials + "\r\n"); | |
| 473 } | |
| 474 | |
| 417 tunnel_request_headers_->headers_ = StringPrintf( | 475 tunnel_request_headers_->headers_ = StringPrintf( |
| 418 "CONNECT %s HTTP/1.1\r\n" | 476 "CONNECT %s HTTP/1.1\r\n" |
| 419 "Host: %s\r\n" | 477 "Host: %s\r\n" |
| 420 "Proxy-Connection: keep-alive\r\n", | 478 "Proxy-Connection: keep-alive\r\n", |
| 421 GetHostAndPort(url_).c_str(), | 479 GetHostAndPort(url_).c_str(), |
| 422 GetHostAndOptionalPort(url_).c_str()); | 480 GetHostAndOptionalPort(url_).c_str()); |
| 423 // TODO(ukai): set proxy auth if necessary. | 481 if (!authorization_headers.empty()) |
| 482 tunnel_request_headers_->headers_ += authorization_headers; | |
| 424 tunnel_request_headers_->headers_ += "\r\n"; | 483 tunnel_request_headers_->headers_ += "\r\n"; |
| 425 } | 484 } |
| 426 tunnel_request_headers_->SetDataOffset(tunnel_request_headers_bytes_sent_); | 485 tunnel_request_headers_->SetDataOffset(tunnel_request_headers_bytes_sent_); |
| 427 int buf_len = static_cast<int>(tunnel_request_headers_->headers_.size() - | 486 int buf_len = static_cast<int>(tunnel_request_headers_->headers_.size() - |
| 428 tunnel_request_headers_bytes_sent_); | 487 tunnel_request_headers_bytes_sent_); |
| 429 DCHECK_GT(buf_len, 0); | 488 DCHECK_GT(buf_len, 0); |
| 430 return socket_->Write(tunnel_request_headers_, buf_len, &io_callback_); | 489 return socket_->Write(tunnel_request_headers_, buf_len, &io_callback_); |
| 431 } | 490 } |
| 432 | 491 |
| 433 int SocketStream::DoWriteTunnelHeadersComplete(int result) { | 492 int SocketStream::DoWriteTunnelHeadersComplete(int result) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 504 next_state_ = STATE_SSL_CONNECT; | 563 next_state_ = STATE_SSL_CONNECT; |
| 505 } else { | 564 } else { |
| 506 DidEstablishConnection(); | 565 DidEstablishConnection(); |
| 507 if ((eoh < tunnel_response_headers_len_) && delegate_) | 566 if ((eoh < tunnel_response_headers_len_) && delegate_) |
| 508 delegate_->OnReceivedData( | 567 delegate_->OnReceivedData( |
| 509 this, tunnel_response_headers_->headers() + eoh, | 568 this, tunnel_response_headers_->headers() + eoh, |
| 510 tunnel_response_headers_len_ - eoh); | 569 tunnel_response_headers_len_ - eoh); |
| 511 } | 570 } |
| 512 return OK; | 571 return OK; |
| 513 case 407: // Proxy Authentication Required. | 572 case 407: // Proxy Authentication Required. |
| 514 // TODO(ukai): handle Proxy Authentication. | 573 result = HandleAuthChallenge(headers.get()); |
| 515 break; | 574 if (result == ERR_PROXY_AUTH_REQUESTED && |
| 575 auth_handler_.get() && delegate_) { | |
| 576 auth_info_ = new AuthChallengeInfo; | |
| 577 auth_info_->is_proxy = true; | |
| 578 auth_info_->host_and_port = | |
| 579 ASCIIToWide(proxy_info_.proxy_server().host_and_port()); | |
| 580 auth_info_->scheme = ASCIIToWide(auth_handler_->scheme()); | |
| 581 auth_info_->realm = ASCIIToWide(auth_handler_->realm()); | |
| 582 // Wait until RestartWithAuth or Close is called. | |
| 583 MessageLoop::current()->PostTask( | |
| 584 FROM_HERE, | |
| 585 NewRunnableMethod(this, &SocketStream::DoAuthRequired)); | |
| 586 return ERR_IO_PENDING; | |
| 587 } | |
| 516 default: | 588 default: |
| 517 break; | 589 break; |
| 518 } | 590 } |
| 519 return ERR_TUNNEL_CONNECTION_FAILED; | 591 return ERR_TUNNEL_CONNECTION_FAILED; |
| 520 } | 592 } |
| 521 | 593 |
| 522 int SocketStream::DoSOCKSConnect() { | 594 int SocketStream::DoSOCKSConnect() { |
| 523 DCHECK_EQ(kSOCKSProxy, proxy_mode_); | 595 DCHECK_EQ(kSOCKSProxy, proxy_mode_); |
| 524 | 596 |
| 525 next_state_ = STATE_SOCKS_CONNECT_COMPLETE; | 597 next_state_ = STATE_SOCKS_CONNECT_COMPLETE; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 608 DidSendData(result); | 680 DidSendData(result); |
| 609 return OK; | 681 return OK; |
| 610 } | 682 } |
| 611 return result; | 683 return result; |
| 612 } | 684 } |
| 613 | 685 |
| 614 // We arrived here when both operation is pending. | 686 // We arrived here when both operation is pending. |
| 615 return ERR_IO_PENDING; | 687 return ERR_IO_PENDING; |
| 616 } | 688 } |
| 617 | 689 |
| 690 GURL SocketStream::ProxyAuthOrigin() const { | |
| 691 return GURL("http://" + proxy_info_.proxy_server().host_and_port()); | |
| 692 } | |
| 693 | |
| 694 int SocketStream::HandleAuthChallenge(const HttpResponseHeaders* headers) { | |
| 695 GURL auth_origin(ProxyAuthOrigin()); | |
| 696 | |
| 697 LOG(INFO) << "The proxy " << auth_origin << " requested auth"; | |
| 698 | |
| 699 // The auth we tried just failed, hence it can't be valid. | |
| 700 // Remove it from the cache so it won't be used again. | |
| 701 if (auth_handler_.get() && !auth_identity_.invalid && | |
| 702 auth_handler_->IsFinalRound()) { | |
| 703 if (auth_identity_.source != HttpAuth::IDENT_SRC_PATH_LOOKUP) | |
| 704 auth_cache_.Remove(auth_origin, | |
| 705 auth_handler_->realm(), | |
| 706 auth_identity_.username, | |
| 707 auth_identity_.password); | |
| 708 auth_handler_ = NULL; | |
| 709 auth_identity_ = HttpAuth::Identity(); | |
| 710 } | |
| 711 | |
| 712 auth_identity_.invalid = true; | |
| 713 HttpAuth::ChooseBestChallenge(headers, HttpAuth::AUTH_PROXY, auth_origin, | |
| 714 &auth_handler_); | |
| 715 if (!auth_handler_) { | |
| 716 LOG(ERROR) << "Can't perform auth to the proxy " << auth_origin; | |
| 717 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 718 } | |
| 719 if (auth_handler_->NeedsIdentity()) { | |
| 720 HttpAuthCache::Entry* entry = auth_cache_.LookupByRealm( | |
| 721 auth_origin, auth_handler_->realm()); | |
| 722 if (entry) { | |
| 723 if (entry->handler()->scheme() != "basic") { | |
| 724 // We only support basic authentication scheme now. | |
| 725 // TODO(ukai): Support other authentication scheme. | |
| 726 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 727 } | |
| 728 auth_identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP; | |
| 729 auth_identity_.invalid = false; | |
| 730 auth_identity_.username = entry->username(); | |
| 731 auth_identity_.password = entry->password(); | |
| 732 // Restart with auth info. | |
| 733 } | |
| 734 return ERR_PROXY_AUTH_REQUESTED; | |
| 735 } else { | |
| 736 auth_identity_.invalid = false; | |
| 737 } | |
| 738 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 739 } | |
| 740 | |
| 741 void SocketStream::DoAuthRequired() { | |
| 742 if (delegate_ && auth_info_.get()) | |
| 743 delegate_->OnAuthRequired(this, auth_info_.get()); | |
| 744 else | |
| 745 DoLoop(net::ERR_UNEXPECTED); | |
| 746 } | |
| 747 | |
| 748 void SocketStream::DoRestartWithAuth() { | |
| 749 auth_cache_.Add(ProxyAuthOrigin(), auth_handler_, | |
| 750 auth_identity_.username, auth_identity_.password, | |
| 751 std::string()); | |
| 752 | |
| 753 tunnel_request_headers_ = NULL; | |
| 754 tunnel_request_headers_bytes_sent_ = 0; | |
| 755 tunnel_response_headers_ = NULL; | |
| 756 tunnel_response_headers_capacity_ = 0; | |
| 757 tunnel_response_headers_len_ = 0; | |
| 758 | |
| 759 next_state_ = STATE_TCP_CONNECT; | |
| 760 DoLoop(OK); | |
| 761 return; | |
|
tyoshino (SeeGerritForStatus)
2009/10/27 09:25:33
remove
| |
| 762 } | |
| 763 | |
| 618 int SocketStream::HandleCertificateError(int result) { | 764 int SocketStream::HandleCertificateError(int result) { |
| 619 // TODO(ukai): handle cert error properly. | 765 // TODO(ukai): handle cert error properly. |
| 620 switch (result) { | 766 switch (result) { |
| 621 case ERR_CERT_COMMON_NAME_INVALID: | 767 case ERR_CERT_COMMON_NAME_INVALID: |
| 622 case ERR_CERT_DATE_INVALID: | 768 case ERR_CERT_DATE_INVALID: |
| 623 case ERR_CERT_AUTHORITY_INVALID: | 769 case ERR_CERT_AUTHORITY_INVALID: |
| 624 result = OK; | 770 result = OK; |
| 625 break; | 771 break; |
| 626 default: | 772 default: |
| 627 break; | 773 break; |
| 628 } | 774 } |
| 629 return result; | 775 return result; |
| 630 } | 776 } |
| 631 | 777 |
| 632 bool SocketStream::is_secure() const { | 778 bool SocketStream::is_secure() const { |
| 633 return url_.SchemeIs("wss"); | 779 return url_.SchemeIs("wss"); |
| 634 } | 780 } |
| 635 | 781 |
| 636 SSLConfigService* SocketStream::ssl_config_service() const { | 782 SSLConfigService* SocketStream::ssl_config_service() const { |
| 637 return context_->ssl_config_service(); | 783 return context_->ssl_config_service(); |
| 638 } | 784 } |
| 639 | 785 |
| 640 ProxyService* SocketStream::proxy_service() const { | 786 ProxyService* SocketStream::proxy_service() const { |
| 641 return context_->proxy_service(); | 787 return context_->proxy_service(); |
| 642 } | 788 } |
| 643 | 789 |
| 644 } // namespace net | 790 } // namespace net |
| OLD | NEW |