// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "google_apis/gaia/oauth2_api_call_flow.h" #include #include #include "base/basictypes.h" #include "base/strings/stringprintf.h" #include "google_apis/gaia/gaia_urls.h" #include "net/base/escape.h" #include "net/base/load_flags.h" #include "net/http/http_status_code.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_status.h" using net::ResponseCookies; using net::URLFetcher; using net::URLFetcherDelegate; using net::URLRequestContextGetter; using net::URLRequestStatus; namespace { static const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s"; static std::string MakeAuthorizationHeader(const std::string& auth_token) { return base::StringPrintf(kAuthorizationHeaderFormat, auth_token.c_str()); } } // namespace OAuth2ApiCallFlow::OAuth2ApiCallFlow() : state_(INITIAL) { } OAuth2ApiCallFlow::~OAuth2ApiCallFlow() {} void OAuth2ApiCallFlow::Start(net::URLRequestContextGetter* context, const std::string& access_token) { CHECK(state_ == INITIAL); state_ = API_CALL_STARTED; url_fetcher_.reset(CreateURLFetcher(context, access_token)); url_fetcher_->Start(); // OnURLFetchComplete will be called. } void OAuth2ApiCallFlow::EndApiCall(const net::URLFetcher* source) { CHECK_EQ(API_CALL_STARTED, state_); URLRequestStatus status = source->GetStatus(); int status_code = source->GetResponseCode(); if (!status.is_success() || (status_code != net::HTTP_OK && status_code != net::HTTP_NO_CONTENT)) { state_ = ERROR_STATE; ProcessApiCallFailure(source); } else { state_ = API_CALL_DONE; ProcessApiCallSuccess(source); } } std::string OAuth2ApiCallFlow::CreateApiCallBodyContentType() { return "application/x-www-form-urlencoded"; } void OAuth2ApiCallFlow::OnURLFetchComplete(const net::URLFetcher* source) { CHECK(source); CHECK_EQ(API_CALL_STARTED, state_); EndApiCall(source); } URLFetcher* OAuth2ApiCallFlow::CreateURLFetcher( net::URLRequestContextGetter* context, const std::string& access_token) { std::string body = CreateApiCallBody(); bool empty_body = body.empty(); URLFetcher* result = net::URLFetcher::Create( 0, CreateApiCallUrl(), empty_body ? URLFetcher::GET : URLFetcher::POST, this); result->SetRequestContext(context); result->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); result->AddExtraRequestHeader(MakeAuthorizationHeader(access_token)); // Fetchers are sometimes cancelled because a network change was detected, // especially at startup and after sign-in on ChromeOS. Retrying once should // be enough in those cases; let the fetcher retry up to 3 times just in case. // http://crbug.com/163710 result->SetAutomaticallyRetryOnNetworkChanges(3); if (!empty_body) result->SetUploadData(CreateApiCallBodyContentType(), body); return result; }