// 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/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_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_ = 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"; } net::URLFetcher::RequestType OAuth2ApiCallFlow::GetRequestTypeForBody( const std::string& body) { return body.empty() ? URLFetcher::GET : URLFetcher::POST; } void OAuth2ApiCallFlow::OnURLFetchComplete(const net::URLFetcher* source) { CHECK(source); CHECK_EQ(API_CALL_STARTED, state_); EndApiCall(source); } scoped_ptr OAuth2ApiCallFlow::CreateURLFetcher( net::URLRequestContextGetter* context, const std::string& access_token) { std::string body = CreateApiCallBody(); net::URLFetcher::RequestType request_type = GetRequestTypeForBody(body); scoped_ptr result = net::URLFetcher::Create(0, CreateApiCallUrl(), request_type, 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); // Even if the the body is empty, we still set the Content-Type because an // empty string may be a meaningful value. For example, a Protocol Buffer // message with only default values will be serialized as an empty string. if (request_type != net::URLFetcher::GET) result->SetUploadData(CreateApiCallBodyContentType(), body); return result; }