1b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// 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
3// found in the LICENSE file.
4
5#include "google_apis/drive/request_sender.h"
6
7#include "base/bind.h"
8#include "base/sequenced_task_runner.h"
9#include "base/stl_util.h"
10#include "google_apis/drive/auth_service.h"
11#include "google_apis/drive/base_requests.h"
12#include "net/url_request/url_request_context_getter.h"
13
14namespace google_apis {
15
16RequestSender::RequestSender(
17    AuthServiceInterface* auth_service,
18    net::URLRequestContextGetter* url_request_context_getter,
19    const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
20    const std::string& custom_user_agent)
21    : auth_service_(auth_service),
22      url_request_context_getter_(url_request_context_getter),
23      blocking_task_runner_(blocking_task_runner),
24      custom_user_agent_(custom_user_agent),
25      weak_ptr_factory_(this) {
26}
27
28RequestSender::~RequestSender() {
29  DCHECK(thread_checker_.CalledOnValidThread());
30  STLDeleteContainerPointers(in_flight_requests_.begin(),
31                             in_flight_requests_.end());
32}
33
34base::Closure RequestSender::StartRequestWithRetry(
35    AuthenticatedRequestInterface* request) {
36  DCHECK(thread_checker_.CalledOnValidThread());
37
38  in_flight_requests_.insert(request);
39
40  // TODO(kinaba): Stop relying on weak pointers. Move lifetime management
41  // of the requests to request sender.
42  base::Closure cancel_closure =
43      base::Bind(&RequestSender::CancelRequest,
44                 weak_ptr_factory_.GetWeakPtr(),
45                 request->GetWeakPtr());
46
47  if (!auth_service_->HasAccessToken()) {
48    // Fetch OAuth2 access token from the refresh token first.
49    auth_service_->StartAuthentication(
50        base::Bind(&RequestSender::OnAccessTokenFetched,
51                   weak_ptr_factory_.GetWeakPtr(),
52                   request->GetWeakPtr()));
53  } else {
54    request->Start(auth_service_->access_token(),
55                   custom_user_agent_,
56                   base::Bind(&RequestSender::RetryRequest,
57                              weak_ptr_factory_.GetWeakPtr()));
58  }
59
60  return cancel_closure;
61}
62
63void RequestSender::OnAccessTokenFetched(
64    const base::WeakPtr<AuthenticatedRequestInterface>& request,
65    GDataErrorCode code,
66    const std::string& /* access_token */) {
67  DCHECK(thread_checker_.CalledOnValidThread());
68
69  // Do nothing if the request is canceled during authentication.
70  if (!request.get())
71    return;
72
73  if (code == HTTP_SUCCESS) {
74    DCHECK(auth_service_->HasAccessToken());
75    StartRequestWithRetry(request.get());
76  } else {
77    request->OnAuthFailed(code);
78  }
79}
80
81void RequestSender::RetryRequest(AuthenticatedRequestInterface* request) {
82  DCHECK(thread_checker_.CalledOnValidThread());
83
84  auth_service_->ClearAccessToken();
85  // User authentication might have expired - rerun the request to force
86  // auth token refresh.
87  StartRequestWithRetry(request);
88}
89
90void RequestSender::CancelRequest(
91    const base::WeakPtr<AuthenticatedRequestInterface>& request) {
92  DCHECK(thread_checker_.CalledOnValidThread());
93
94  // Do nothing if the request is already finished.
95  if (!request.get())
96    return;
97  request->Cancel();
98}
99
100void RequestSender::RequestFinished(AuthenticatedRequestInterface* request) {
101  in_flight_requests_.erase(request);
102  delete request;
103}
104
105}  // namespace google_apis
106