diff options
author | fgorski@chromium.org <fgorski@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-21 03:23:16 +0000 |
---|---|---|
committer | fgorski@chromium.org <fgorski@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-21 03:23:16 +0000 |
commit | bdbe2b126637d186dbcb049276522411013f04ca (patch) | |
tree | 8bc020bbbab0aedcbcdf64be7dd261a00db06fcd /google_apis | |
parent | 921d7af9ba4a54a98ba6bb1bd9234613075dff5b (diff) | |
download | chromium_src-bdbe2b126637d186dbcb049276522411013f04ca.zip chromium_src-bdbe2b126637d186dbcb049276522411013f04ca.tar.gz chromium_src-bdbe2b126637d186dbcb049276522411013f04ca.tar.bz2 |
* Introducing Service Error and Unexpected Response for better handling of
errors Google Authentication service included in response body.
* Adding parsing to the Failure situation in OAuth2MintTokenFlow
BUG=121976
Review URL: https://chromiumcodereview.appspot.com/17286013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207681 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'google_apis')
-rw-r--r-- | google_apis/gaia/google_service_auth_error.cc | 34 | ||||
-rw-r--r-- | google_apis/gaia/google_service_auth_error.h | 23 | ||||
-rw-r--r-- | google_apis/gaia/oauth2_mint_token_flow.cc | 58 |
3 files changed, 96 insertions, 19 deletions
diff --git a/google_apis/gaia/google_service_auth_error.cc b/google_apis/gaia/google_service_auth_error.cc index fcb7c00..59569c7 100644 --- a/google_apis/gaia/google_service_auth_error.cc +++ b/google_apis/gaia/google_service_auth_error.cc @@ -35,7 +35,6 @@ bool GoogleServiceAuthError::Captcha::operator==(const Captcha& b) const { image_height == b.image_height); } - GoogleServiceAuthError::SecondFactor::SecondFactor() : field_length(0) { } @@ -57,7 +56,6 @@ bool GoogleServiceAuthError::SecondFactor::operator==( field_length == b.field_length); } - bool GoogleServiceAuthError::operator==( const GoogleServiceAuthError& b) const { return (state_ == b.state_ && @@ -75,6 +73,14 @@ GoogleServiceAuthError::GoogleServiceAuthError(State s) } } +GoogleServiceAuthError::GoogleServiceAuthError( + State state, + const std::string& error_message) + : state_(state), + network_error_(0), + error_message_(error_message) { +} + GoogleServiceAuthError::GoogleServiceAuthError(const std::string& error_message) : state_(INVALID_GAIA_CREDENTIALS), network_error_(0), @@ -96,6 +102,19 @@ GoogleServiceAuthError GoogleServiceAuthError::FromClientLoginCaptchaChallenge( captcha_image_url, captcha_unlock_url, 0, 0); } +// static +GoogleServiceAuthError GoogleServiceAuthError::FromServiceError( + const std::string& error_message) { + return GoogleServiceAuthError(SERVICE_ERROR, error_message); +} + +// static +GoogleServiceAuthError GoogleServiceAuthError::FromUnexpectedServiceResponse( + const std::string& error_message) { + return GoogleServiceAuthError(UNEXPECTED_SERVICE_RESPONSE, error_message); +} + +// static GoogleServiceAuthError GoogleServiceAuthError::AuthErrorNone() { return GoogleServiceAuthError(NONE); } @@ -151,12 +170,17 @@ DictionaryValue* GoogleServiceAuthError::ToValue() const { STATE_CASE(TWO_FACTOR); STATE_CASE(REQUEST_CANCELED); STATE_CASE(HOSTED_NOT_ALLOWED); + STATE_CASE(UNEXPECTED_SERVICE_RESPONSE); + STATE_CASE(SERVICE_ERROR); #undef STATE_CASE default: NOTREACHED(); break; } value->SetString("state", state_str); + if (!error_message_.empty()) { + value->SetString("errorMessage", error_message_); + } if (state_ == CAPTCHA_REQUIRED) { DictionaryValue* captcha_value = new DictionaryValue(); value->Set("captcha", captcha_value); @@ -205,6 +229,12 @@ std::string GoogleServiceAuthError::ToString() const { return "Request canceled."; case HOSTED_NOT_ALLOWED: return "Google account required."; + case UNEXPECTED_SERVICE_RESPONSE: + return base::StringPrintf("Unexpected service response (%s)", + error_message_.c_str()); + case SERVICE_ERROR: + return base::StringPrintf("Service responded with error: '%s'", + error_message_.c_str()); default: NOTREACHED(); return std::string(); diff --git a/google_apis/gaia/google_service_auth_error.h b/google_apis/gaia/google_service_auth_error.h index 0ac0974..ddfa2d0 100644 --- a/google_apis/gaia/google_service_auth_error.h +++ b/google_apis/gaia/google_service_auth_error.h @@ -78,8 +78,16 @@ class GoogleServiceAuthError { // a GOOGLE account. HOSTED_NOT_ALLOWED = 10, + // Indicates the service responded to a request, but we cannot + // interpret the response. + UNEXPECTED_SERVICE_RESPONSE = 11, + + // Indicates the service responded and response carried details of the + // application error. + SERVICE_ERROR = 12, + // The number of known error states. - NUM_STATES = 11, + NUM_STATES = 13, }; // Additional data for CAPTCHA_REQUIRED errors. @@ -145,6 +153,16 @@ class GoogleServiceAuthError { const GURL& captcha_image_url, const GURL& captcha_unlock_url); + // Construct a SERVICE_ERROR error, e.g. invalid client ID, with an + // |error_message| which provides more information about the service error. + static GoogleServiceAuthError FromServiceError( + const std::string& error_message); + + // Construct an UNEXPECTED_SERVICE_RESPONSE error, with an |error_message| + // detailing the problems with the response. + static GoogleServiceAuthError FromUnexpectedServiceResponse( + const std::string& error_message); + // Provided for convenience for clients needing to reset an instance to NONE. // (avoids err_ = GoogleServiceAuthError(GoogleServiceAuthError::NONE), due // to explicit class and State enum relation. Note: shouldn't be inlined! @@ -168,6 +186,9 @@ class GoogleServiceAuthError { private: GoogleServiceAuthError(State s, int error); + // Construct a GoogleServiceAuthError from |state| and |error_message|. + GoogleServiceAuthError(State state, const std::string& error_message); + explicit GoogleServiceAuthError(const std::string& error_message); GoogleServiceAuthError(State s, const std::string& captcha_token, diff --git a/google_apis/gaia/oauth2_mint_token_flow.cc b/google_apis/gaia/oauth2_mint_token_flow.cc index 5b02446..f8680e3 100644 --- a/google_apis/gaia/oauth2_mint_token_flow.cc +++ b/google_apis/gaia/oauth2_mint_token_flow.cc @@ -51,18 +51,40 @@ static const char kScopesKey[] = "scopes"; static const char kDescriptionKey[] = "description"; static const char kDetailKey[] = "detail"; static const char kDetailSeparators[] = "\n"; +static const char kError[] = "error"; +static const char kMessage[] = "message"; -static GoogleServiceAuthError CreateAuthError(URLRequestStatus status) { +static GoogleServiceAuthError CreateAuthError(const net::URLFetcher* source) { + URLRequestStatus status = source->GetStatus(); if (status.status() == URLRequestStatus::CANCELED) { return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED); - } else { - // TODO(munjal): Improve error handling. Currently we return connection - // error for even application level errors. We need to either expand the - // GoogleServiceAuthError enum or create a new one to report better - // errors. + } + if (status.status() == URLRequestStatus::FAILED) { DLOG(WARNING) << "Server returned error: errno " << status.error(); return GoogleServiceAuthError::FromConnectionError(status.error()); } + + std::string response_body; + source->GetResponseAsString(&response_body); + scoped_ptr<Value> value(base::JSONReader::Read(response_body)); + DictionaryValue* response; + if (!value.get() || !value->GetAsDictionary(&response)) { + return GoogleServiceAuthError::FromUnexpectedServiceResponse( + base::StringPrintf( + "Not able to parse a JSON object from a service response. " + "HTTP Status of the response is: %d", source->GetResponseCode())); + } + DictionaryValue* error; + if (!response->GetDictionary(kError, &error)) { + return GoogleServiceAuthError::FromUnexpectedServiceResponse( + "Not able to find a detailed error in a service response."); + } + std::string message; + if (!error->GetString(kMessage, &message)) { + return GoogleServiceAuthError::FromUnexpectedServiceResponse( + "Not able to find an error message within a service error."); + } + return GoogleServiceAuthError::FromServiceError(message); } } // namespace @@ -153,35 +175,39 @@ std::string OAuth2MintTokenFlow::CreateApiCallBody() { void OAuth2MintTokenFlow::ProcessApiCallSuccess( const net::URLFetcher* source) { - // TODO(munjal): Change error code paths in this method to report an - // internal error. std::string response_body; source->GetResponseAsString(&response_body); scoped_ptr<base::Value> value(base::JSONReader::Read(response_body)); DictionaryValue* dict = NULL; if (!value.get() || !value->GetAsDictionary(&dict)) { - ReportFailure(GoogleServiceAuthError::FromConnectionError(101)); + ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse( + "Not able to parse a JSON object from a service response.")); return; } - std::string issue_advice; - if (!dict->GetString(kIssueAdviceKey, &issue_advice)) { - ReportFailure(GoogleServiceAuthError::FromConnectionError(101)); + std::string issue_advice_value; + if (!dict->GetString(kIssueAdviceKey, &issue_advice_value)) { + ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse( + "Not able to find an issueAdvice in a service response.")); return; } - if (issue_advice == kIssueAdviceValueConsent) { + if (issue_advice_value == kIssueAdviceValueConsent) { IssueAdviceInfo issue_advice; if (ParseIssueAdviceResponse(dict, &issue_advice)) ReportIssueAdviceSuccess(issue_advice); else - ReportFailure(GoogleServiceAuthError::FromConnectionError(101)); + ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse( + "Not able to parse the contents of consent " + "from a service response.")); } else { std::string access_token; int time_to_live; if (ParseMintTokenResponse(dict, &access_token, &time_to_live)) ReportSuccess(access_token, time_to_live); else - ReportFailure(GoogleServiceAuthError::FromConnectionError(101)); + ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse( + "Not able to parse the contents of access token " + "from a service response.")); } // |this| may be deleted! @@ -189,7 +215,7 @@ void OAuth2MintTokenFlow::ProcessApiCallSuccess( void OAuth2MintTokenFlow::ProcessApiCallFailure( const net::URLFetcher* source) { - ReportFailure(CreateAuthError(source->GetStatus())); + ReportFailure(CreateAuthError(source)); } void OAuth2MintTokenFlow::ProcessNewAccessToken( const std::string& access_token) { |