Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(665)

Side by Side Diff: net/socket_stream/socket_stream.cc

Issue 330016: Add proxy basic auth support in net/socket_stream. (Closed)
Patch Set: update comment Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/socket_stream/socket_stream.h ('k') | net/socket_stream/socket_stream_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « net/socket_stream/socket_stream.h ('k') | net/socket_stream/socket_stream_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698