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 "google_apis/gaia/gaia_auth_fetcher.h" | 5 #include "google_apis/gaia/gaia_auth_fetcher.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <utility> | 8 #include <utility> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 23 matching lines...) Expand all Loading... |
34 static bool CookiePartsContains(const std::vector<std::string>& parts, | 34 static bool CookiePartsContains(const std::vector<std::string>& parts, |
35 const char* part) { | 35 const char* part) { |
36 for (std::vector<std::string>::const_iterator it = parts.begin(); | 36 for (std::vector<std::string>::const_iterator it = parts.begin(); |
37 it != parts.end(); ++it) { | 37 it != parts.end(); ++it) { |
38 if (LowerCaseEqualsASCII(*it, part)) | 38 if (LowerCaseEqualsASCII(*it, part)) |
39 return true; | 39 return true; |
40 } | 40 } |
41 return false; | 41 return false; |
42 } | 42 } |
43 | 43 |
44 bool ExtractOAuth2TokenPairResponse(base::DictionaryValue* dict, | 44 // From the JSON string |data|, extract the |access_token| and |expires_in_secs| |
| 45 // both of which must exist. If the |refresh_token| is non-NULL, then it also |
| 46 // must exist and is extraced; if it's NULL, then no extraction is attempted. |
| 47 bool ExtractOAuth2TokenPairResponse(const std::string& data, |
45 std::string* refresh_token, | 48 std::string* refresh_token, |
46 std::string* access_token, | 49 std::string* access_token, |
47 int* expires_in_secs) { | 50 int* expires_in_secs) { |
48 DCHECK(refresh_token); | |
49 DCHECK(access_token); | 51 DCHECK(access_token); |
50 DCHECK(expires_in_secs); | 52 DCHECK(expires_in_secs); |
51 | 53 |
52 if (!dict->GetStringWithoutPathExpansion("refresh_token", refresh_token) || | 54 scoped_ptr<base::Value> value(base::JSONReader::Read(data)); |
53 !dict->GetStringWithoutPathExpansion("access_token", access_token) || | 55 if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) |
| 56 return false; |
| 57 |
| 58 base::DictionaryValue* dict = |
| 59 static_cast<base::DictionaryValue*>(value.get()); |
| 60 |
| 61 if (!dict->GetStringWithoutPathExpansion("access_token", access_token) || |
54 !dict->GetIntegerWithoutPathExpansion("expires_in", expires_in_secs)) { | 62 !dict->GetIntegerWithoutPathExpansion("expires_in", expires_in_secs)) { |
55 return false; | 63 return false; |
56 } | 64 } |
57 | 65 |
| 66 // Refresh token may not be required. |
| 67 if (refresh_token) { |
| 68 if (!dict->GetStringWithoutPathExpansion("refresh_token", refresh_token)) |
| 69 return false; |
| 70 } |
58 return true; | 71 return true; |
59 } | 72 } |
60 | 73 |
| 74 const char kListIdpServiceRequested[] = "list_idp"; |
| 75 const char kGetTokenResponseRequested[] = "get_token"; |
| 76 |
61 } // namespace | 77 } // namespace |
62 | 78 |
63 // TODO(chron): Add sourceless version of this formatter. | 79 // TODO(chron): Add sourceless version of this formatter. |
64 // static | 80 // static |
65 const char GaiaAuthFetcher::kClientLoginFormat[] = | 81 const char GaiaAuthFetcher::kClientLoginFormat[] = |
66 "Email=%s&" | 82 "Email=%s&" |
67 "Passwd=%s&" | 83 "Passwd=%s&" |
68 "PersistentCookie=%s&" | 84 "PersistentCookie=%s&" |
69 "accountType=%s&" | 85 "accountType=%s&" |
70 "source=%s&" | 86 "source=%s&" |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 oauth2_revoke_gurl_(GaiaUrls::GetInstance()->oauth2_revoke_url()), | 201 oauth2_revoke_gurl_(GaiaUrls::GetInstance()->oauth2_revoke_url()), |
186 get_user_info_gurl_(GaiaUrls::GetInstance()->get_user_info_url()), | 202 get_user_info_gurl_(GaiaUrls::GetInstance()->get_user_info_url()), |
187 merge_session_gurl_(GaiaUrls::GetInstance()->merge_session_url()), | 203 merge_session_gurl_(GaiaUrls::GetInstance()->merge_session_url()), |
188 uberauth_token_gurl_(GaiaUrls::GetInstance()->oauth1_login_url().Resolve( | 204 uberauth_token_gurl_(GaiaUrls::GetInstance()->oauth1_login_url().Resolve( |
189 base::StringPrintf(kUberAuthTokenURLFormat, source.c_str()))), | 205 base::StringPrintf(kUberAuthTokenURLFormat, source.c_str()))), |
190 oauth_login_gurl_(GaiaUrls::GetInstance()->oauth1_login_url()), | 206 oauth_login_gurl_(GaiaUrls::GetInstance()->oauth1_login_url()), |
191 list_accounts_gurl_( | 207 list_accounts_gurl_( |
192 GaiaUrls::GetInstance()->ListAccountsURLWithSource(source)), | 208 GaiaUrls::GetInstance()->ListAccountsURLWithSource(source)), |
193 get_check_connection_info_url_( | 209 get_check_connection_info_url_( |
194 GaiaUrls::GetInstance()->GetCheckConnectionInfoURLWithSource(source)), | 210 GaiaUrls::GetInstance()->GetCheckConnectionInfoURLWithSource(source)), |
| 211 oauth2_iframe_url_(GaiaUrls::GetInstance()->oauth2_iframe_url()), |
195 client_login_to_oauth2_gurl_( | 212 client_login_to_oauth2_gurl_( |
196 GaiaUrls::GetInstance()->client_login_to_oauth2_url()), | 213 GaiaUrls::GetInstance()->client_login_to_oauth2_url()), |
197 fetch_pending_(false) {} | 214 fetch_pending_(false) {} |
198 | 215 |
199 GaiaAuthFetcher::~GaiaAuthFetcher() {} | 216 GaiaAuthFetcher::~GaiaAuthFetcher() {} |
200 | 217 |
201 bool GaiaAuthFetcher::HasPendingFetch() { | 218 bool GaiaAuthFetcher::HasPendingFetch() { |
202 return fetch_pending_; | 219 return fetch_pending_; |
203 } | 220 } |
204 | 221 |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 std::string GaiaAuthFetcher::MakeOAuthLoginBody(const std::string& service, | 432 std::string GaiaAuthFetcher::MakeOAuthLoginBody(const std::string& service, |
416 const std::string& source) { | 433 const std::string& source) { |
417 std::string encoded_service = net::EscapeUrlEncodedData(service, true); | 434 std::string encoded_service = net::EscapeUrlEncodedData(service, true); |
418 std::string encoded_source = net::EscapeUrlEncodedData(source, true); | 435 std::string encoded_source = net::EscapeUrlEncodedData(source, true); |
419 return base::StringPrintf(kOAuthLoginFormat, | 436 return base::StringPrintf(kOAuthLoginFormat, |
420 encoded_service.c_str(), | 437 encoded_service.c_str(), |
421 encoded_source.c_str()); | 438 encoded_source.c_str()); |
422 } | 439 } |
423 | 440 |
424 // static | 441 // static |
| 442 std::string GaiaAuthFetcher::MakeListIDPSessionsBody( |
| 443 const std::string& scopes, |
| 444 const std::string& domain) { |
| 445 static const char getTokenResponseBodyFormat[] = |
| 446 "action=listSessions&" |
| 447 "client_id=%s&" |
| 448 "e=3100087&" // temporarily enable the experiment. |
| 449 "origin=%s&" |
| 450 "scope=%s"; |
| 451 std::string encoded_client_id = net::EscapeUrlEncodedData( |
| 452 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true); |
| 453 return base::StringPrintf(getTokenResponseBodyFormat, |
| 454 encoded_client_id.c_str(), |
| 455 domain.c_str(), |
| 456 scopes.c_str()); |
| 457 } |
| 458 |
| 459 std::string GaiaAuthFetcher::MakeGetTokenResponseBody( |
| 460 const std::string& scopes, |
| 461 const std::string& domain, |
| 462 const std::string& login_hint) { |
| 463 static const char getTokenResponseBodyFormat[] = |
| 464 "action=issueToken&" |
| 465 "client_id=%s&" |
| 466 "login_hint=%s&" |
| 467 "origin=%s&" |
| 468 "e=3100087&" // temporarily enable the experiment. |
| 469 "response_type=token&" |
| 470 "scope=%s"; |
| 471 std::string encoded_client_id = net::EscapeUrlEncodedData( |
| 472 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true); |
| 473 return base::StringPrintf(getTokenResponseBodyFormat, |
| 474 encoded_client_id.c_str(), |
| 475 login_hint.c_str(), |
| 476 domain.c_str(), |
| 477 scopes.c_str()); |
| 478 } |
| 479 |
| 480 // static |
425 void GaiaAuthFetcher::ParseClientLoginFailure(const std::string& data, | 481 void GaiaAuthFetcher::ParseClientLoginFailure(const std::string& data, |
426 std::string* error, | 482 std::string* error, |
427 std::string* error_url, | 483 std::string* error_url, |
428 std::string* captcha_url, | 484 std::string* captcha_url, |
429 std::string* captcha_token) { | 485 std::string* captcha_token) { |
430 using std::vector; | 486 using std::vector; |
431 using std::pair; | 487 using std::pair; |
432 using std::string; | 488 using std::string; |
433 | 489 |
434 vector<pair<string, string> > tokens; | 490 vector<pair<string, string> > tokens; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
477 if (StartsWithASCII( | 533 if (StartsWithASCII( |
478 part, kClientLoginToOAuth2CookiePartCodePrefix, false)) { | 534 part, kClientLoginToOAuth2CookiePartCodePrefix, false)) { |
479 auth_code->assign(part.substr( | 535 auth_code->assign(part.substr( |
480 kClientLoginToOAuth2CookiePartCodePrefixLength)); | 536 kClientLoginToOAuth2CookiePartCodePrefixLength)); |
481 return true; | 537 return true; |
482 } | 538 } |
483 } | 539 } |
484 return false; | 540 return false; |
485 } | 541 } |
486 | 542 |
| 543 // static |
| 544 bool GaiaAuthFetcher::ParseListIdpSessionsResponse(const std::string& data, |
| 545 std::string* login_hint) { |
| 546 DCHECK(login_hint); |
| 547 |
| 548 scoped_ptr<base::Value> value(base::JSONReader::Read(data)); |
| 549 if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) |
| 550 return false; |
| 551 |
| 552 base::DictionaryValue* dict = |
| 553 static_cast<base::DictionaryValue*>(value.get()); |
| 554 |
| 555 base::ListValue* sessionsList; |
| 556 if (!dict->GetList("sessions", &sessionsList)) |
| 557 return false; |
| 558 |
| 559 // Find the first login_hint present in any session. |
| 560 for (base::ListValue::iterator iter = sessionsList->begin(); |
| 561 iter != sessionsList->end(); |
| 562 iter++) { |
| 563 base::DictionaryValue* sessionDictionary; |
| 564 if (!(*iter)->GetAsDictionary(&sessionDictionary)) |
| 565 continue; |
| 566 |
| 567 if (sessionDictionary->GetString("login_hint", login_hint)) |
| 568 break; |
| 569 } |
| 570 |
| 571 if (login_hint->empty()) |
| 572 return false; |
| 573 return true; |
| 574 } |
| 575 |
487 void GaiaAuthFetcher::StartClientLogin( | 576 void GaiaAuthFetcher::StartClientLogin( |
488 const std::string& username, | 577 const std::string& username, |
489 const std::string& password, | 578 const std::string& password, |
490 const char* const service, | 579 const char* const service, |
491 const std::string& login_token, | 580 const std::string& login_token, |
492 const std::string& login_captcha, | 581 const std::string& login_captcha, |
493 HostedAccountsSetting allow_hosted_accounts) { | 582 HostedAccountsSetting allow_hosted_accounts) { |
494 | 583 |
495 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | 584 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; |
496 | 585 |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 fetcher_.reset(CreateGaiaFetcher(getter_, | 806 fetcher_.reset(CreateGaiaFetcher(getter_, |
718 std::string(), | 807 std::string(), |
719 std::string(), | 808 std::string(), |
720 get_check_connection_info_url_, | 809 get_check_connection_info_url_, |
721 kLoadFlagsIgnoreCookies, | 810 kLoadFlagsIgnoreCookies, |
722 this)); | 811 this)); |
723 fetch_pending_ = true; | 812 fetch_pending_ = true; |
724 fetcher_->Start(); | 813 fetcher_->Start(); |
725 } | 814 } |
726 | 815 |
| 816 void GaiaAuthFetcher::StartListIDPSessions(const std::string& scopes, |
| 817 const std::string& domain) { |
| 818 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; |
| 819 |
| 820 request_body_ = MakeListIDPSessionsBody(scopes, domain); |
| 821 fetcher_.reset(CreateGaiaFetcher(getter_, |
| 822 request_body_, |
| 823 std::string(), |
| 824 oauth2_iframe_url_, |
| 825 net::LOAD_NORMAL, |
| 826 this)); |
| 827 requested_service_ = kListIdpServiceRequested; |
| 828 fetch_pending_ = true; |
| 829 fetcher_->Start(); |
| 830 } |
| 831 |
| 832 void GaiaAuthFetcher::StartGetTokenResponse(const std::string& scopes, |
| 833 const std::string& domain, |
| 834 const std::string& login_hint) { |
| 835 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; |
| 836 |
| 837 request_body_ = MakeGetTokenResponseBody(scopes, domain, login_hint); |
| 838 fetcher_.reset(CreateGaiaFetcher(getter_, |
| 839 request_body_, |
| 840 std::string(), |
| 841 oauth2_iframe_url_, |
| 842 net::LOAD_NORMAL, |
| 843 this)); |
| 844 |
| 845 requested_service_ = kGetTokenResponseRequested; |
| 846 fetch_pending_ = true; |
| 847 fetcher_->Start(); |
| 848 } |
| 849 |
727 // static | 850 // static |
728 GoogleServiceAuthError GaiaAuthFetcher::GenerateAuthError( | 851 GoogleServiceAuthError GaiaAuthFetcher::GenerateAuthError( |
729 const std::string& data, | 852 const std::string& data, |
730 const net::URLRequestStatus& status) { | 853 const net::URLRequestStatus& status) { |
731 if (!status.is_success()) { | 854 if (!status.is_success()) { |
732 if (status.status() == net::URLRequestStatus::CANCELED) { | 855 if (status.status() == net::URLRequestStatus::CANCELED) { |
733 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED); | 856 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED); |
734 } | 857 } |
735 DLOG(WARNING) << "Could not reach Google Accounts servers: errno " | 858 DLOG(WARNING) << "Could not reach Google Accounts servers: errno " |
736 << status.error(); | 859 << status.error(); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
827 void GaiaAuthFetcher::OnOAuth2TokenPairFetched( | 950 void GaiaAuthFetcher::OnOAuth2TokenPairFetched( |
828 const std::string& data, | 951 const std::string& data, |
829 const net::URLRequestStatus& status, | 952 const net::URLRequestStatus& status, |
830 int response_code) { | 953 int response_code) { |
831 std::string refresh_token; | 954 std::string refresh_token; |
832 std::string access_token; | 955 std::string access_token; |
833 int expires_in_secs = 0; | 956 int expires_in_secs = 0; |
834 | 957 |
835 bool success = false; | 958 bool success = false; |
836 if (status.is_success() && response_code == net::HTTP_OK) { | 959 if (status.is_success() && response_code == net::HTTP_OK) { |
837 scoped_ptr<base::Value> value(base::JSONReader::Read(data)); | 960 success = ExtractOAuth2TokenPairResponse(data, &refresh_token, |
838 if (value.get() && value->GetType() == base::Value::TYPE_DICTIONARY) { | |
839 base::DictionaryValue* dict = | |
840 static_cast<base::DictionaryValue*>(value.get()); | |
841 success = ExtractOAuth2TokenPairResponse(dict, &refresh_token, | |
842 &access_token, &expires_in_secs); | 961 &access_token, &expires_in_secs); |
843 } | |
844 } | 962 } |
845 | 963 |
846 if (success) { | 964 if (success) { |
847 consumer_->OnClientOAuthSuccess( | 965 consumer_->OnClientOAuthSuccess( |
848 GaiaAuthConsumer::ClientOAuthResult(refresh_token, access_token, | 966 GaiaAuthConsumer::ClientOAuthResult(refresh_token, access_token, |
849 expires_in_secs)); | 967 expires_in_secs)); |
850 } else { | 968 } else { |
851 consumer_->OnClientOAuthFailure(GenerateAuthError(data, status)); | 969 consumer_->OnClientOAuthFailure(GenerateAuthError(data, status)); |
852 } | 970 } |
853 } | 971 } |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
927 const std::string& data, | 1045 const std::string& data, |
928 const net::URLRequestStatus& status, | 1046 const net::URLRequestStatus& status, |
929 int response_code) { | 1047 int response_code) { |
930 if (status.is_success() && response_code == net::HTTP_OK) { | 1048 if (status.is_success() && response_code == net::HTTP_OK) { |
931 consumer_->OnGetCheckConnectionInfoSuccess(data); | 1049 consumer_->OnGetCheckConnectionInfoSuccess(data); |
932 } else { | 1050 } else { |
933 consumer_->OnGetCheckConnectionInfoError(GenerateAuthError(data, status)); | 1051 consumer_->OnGetCheckConnectionInfoError(GenerateAuthError(data, status)); |
934 } | 1052 } |
935 } | 1053 } |
936 | 1054 |
| 1055 void GaiaAuthFetcher::OnListIdpSessionsFetched( |
| 1056 const std::string& data, |
| 1057 const net::URLRequestStatus& status, |
| 1058 int response_code) { |
| 1059 if (status.is_success() && response_code == net::HTTP_OK) { |
| 1060 DVLOG(1) << "ListIdpSessions successful!"; |
| 1061 std::string login_hint; |
| 1062 if (ParseListIdpSessionsResponse(data, &login_hint)) { |
| 1063 consumer_->OnListIdpSessionsSuccess(login_hint); |
| 1064 } else { |
| 1065 GoogleServiceAuthError auth_error( |
| 1066 GoogleServiceAuthError::FromUnexpectedServiceResponse( |
| 1067 "List Sessions response didn't contain a login_hint.")); |
| 1068 consumer_->OnListIdpSessionsError(auth_error); |
| 1069 } |
| 1070 } else { |
| 1071 consumer_->OnListIdpSessionsError(GenerateAuthError(data, status)); |
| 1072 } |
| 1073 } |
| 1074 |
| 1075 void GaiaAuthFetcher::OnGetTokenResponseFetched( |
| 1076 const std::string& data, |
| 1077 const net::URLRequestStatus& status, |
| 1078 int response_code) { |
| 1079 std::string access_token; |
| 1080 int expires_in_secs = 0; |
| 1081 bool success = false; |
| 1082 if (status.is_success() && response_code == net::HTTP_OK) { |
| 1083 DVLOG(1) << "GetTokenResponse successful!"; |
| 1084 success = ExtractOAuth2TokenPairResponse(data, NULL, |
| 1085 &access_token, &expires_in_secs); |
| 1086 } |
| 1087 |
| 1088 if (success) { |
| 1089 consumer_->OnGetTokenResponseSuccess( |
| 1090 GaiaAuthConsumer::ClientOAuthResult(std::string(), access_token, |
| 1091 expires_in_secs)); |
| 1092 } else { |
| 1093 consumer_->OnGetTokenResponseError(GenerateAuthError(data, status)); |
| 1094 } |
| 1095 } |
| 1096 |
937 void GaiaAuthFetcher::OnURLFetchComplete(const net::URLFetcher* source) { | 1097 void GaiaAuthFetcher::OnURLFetchComplete(const net::URLFetcher* source) { |
938 fetch_pending_ = false; | 1098 fetch_pending_ = false; |
939 // Some of the GAIA requests perform redirects, which results in the final | 1099 // Some of the GAIA requests perform redirects, which results in the final |
940 // URL of the fetcher not being the original URL requested. Therefore use | 1100 // URL of the fetcher not being the original URL requested. Therefore use |
941 // the original URL when determining which OnXXX function to call. | 1101 // the original URL when determining which OnXXX function to call. |
942 const GURL& url = source->GetOriginalURL(); | 1102 const GURL& url = source->GetOriginalURL(); |
943 const net::URLRequestStatus& status = source->GetStatus(); | 1103 const net::URLRequestStatus& status = source->GetStatus(); |
944 int response_code = source->GetResponseCode(); | 1104 int response_code = source->GetResponseCode(); |
945 std::string data; | 1105 std::string data; |
946 source->GetResponseAsString(&data); | 1106 source->GetResponseAsString(&data); |
(...skipping 23 matching lines...) Expand all Loading... |
970 } else if (url == uberauth_token_gurl_) { | 1130 } else if (url == uberauth_token_gurl_) { |
971 OnUberAuthTokenFetch(data, status, response_code); | 1131 OnUberAuthTokenFetch(data, status, response_code); |
972 } else if (url == oauth_login_gurl_) { | 1132 } else if (url == oauth_login_gurl_) { |
973 OnOAuthLoginFetched(data, status, response_code); | 1133 OnOAuthLoginFetched(data, status, response_code); |
974 } else if (url == oauth2_revoke_gurl_) { | 1134 } else if (url == oauth2_revoke_gurl_) { |
975 OnOAuth2RevokeTokenFetched(data, status, response_code); | 1135 OnOAuth2RevokeTokenFetched(data, status, response_code); |
976 } else if (url == list_accounts_gurl_) { | 1136 } else if (url == list_accounts_gurl_) { |
977 OnListAccountsFetched(data, status, response_code); | 1137 OnListAccountsFetched(data, status, response_code); |
978 } else if (url == get_check_connection_info_url_) { | 1138 } else if (url == get_check_connection_info_url_) { |
979 OnGetCheckConnectionInfoFetched(data, status, response_code); | 1139 OnGetCheckConnectionInfoFetched(data, status, response_code); |
| 1140 } else if (url == oauth2_iframe_url_) { |
| 1141 if (requested_service_ == kListIdpServiceRequested) |
| 1142 OnListIdpSessionsFetched(data, status, response_code); |
| 1143 else if (requested_service_ == kGetTokenResponseRequested) |
| 1144 OnGetTokenResponseFetched(data, status, response_code); |
| 1145 else |
| 1146 NOTREACHED(); |
980 } else { | 1147 } else { |
981 NOTREACHED(); | 1148 NOTREACHED(); |
982 } | 1149 } |
983 } | 1150 } |
984 | 1151 |
985 // static | 1152 // static |
986 bool GaiaAuthFetcher::IsSecondFactorSuccess( | 1153 bool GaiaAuthFetcher::IsSecondFactorSuccess( |
987 const std::string& alleged_error) { | 1154 const std::string& alleged_error) { |
988 return alleged_error.find(kSecondFactor) != | 1155 return alleged_error.find(kSecondFactor) != |
989 std::string::npos; | 1156 std::string::npos; |
990 } | 1157 } |
991 | 1158 |
992 // static | 1159 // static |
993 bool GaiaAuthFetcher::IsWebLoginRequiredSuccess( | 1160 bool GaiaAuthFetcher::IsWebLoginRequiredSuccess( |
994 const std::string& alleged_error) { | 1161 const std::string& alleged_error) { |
995 return alleged_error.find(kWebLoginRequired) != | 1162 return alleged_error.find(kWebLoginRequired) != |
996 std::string::npos; | 1163 std::string::npos; |
997 } | 1164 } |
OLD | NEW |