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 |