Home | History | Annotate | Download | only in file_system_provider
      1 // Copyright 2014 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 "chrome/browser/chromeos/file_system_provider/request_manager.h"
      6 
      7 #include "base/debug/trace_event.h"
      8 #include "base/files/file.h"
      9 #include "base/stl_util.h"
     10 
     11 namespace chromeos {
     12 namespace file_system_provider {
     13 namespace {
     14 
     15 // Timeout in seconds, before a request is considered as stale and hence
     16 // aborted.
     17 const int kDefaultTimeout = 10;
     18 
     19 }  // namespace
     20 
     21 std::string RequestTypeToString(RequestType type) {
     22   switch (type) {
     23     case REQUEST_UNMOUNT:
     24       return "REQUEST_UNMOUNT";
     25     case GET_METADATA:
     26       return "GET_METADATA";
     27     case READ_DIRECTORY:
     28       return "READ_DIRECTORY";
     29     case OPEN_FILE:
     30       return "OPEN_FILE";
     31     case CLOSE_FILE:
     32       return "CLOSE_FILE";
     33     case READ_FILE:
     34       return "READ_FILE";
     35     case CREATE_DIRECTORY:
     36       return "CREATE_DIRECTORY";
     37     case DELETE_ENTRY:
     38       return "DELETE_ENTRY";
     39     case CREATE_FILE:
     40       return "CREATE_FILE";
     41     case COPY_ENTRY:
     42       return "COPY_ENTRY";
     43     case MOVE_ENTRY:
     44       return "MOVE_ENTRY";
     45     case TRUNCATE:
     46       return "TRUNCATE";
     47     case WRITE_FILE:
     48       return "WRITE_FILE";
     49     case ABORT:
     50       return "ABORT";
     51     case TESTING:
     52       return "TESTING";
     53   }
     54   NOTREACHED();
     55   return "";
     56 }
     57 
     58 RequestManager::RequestManager(
     59     NotificationManagerInterface* notification_manager)
     60     : notification_manager_(notification_manager),
     61       next_id_(1),
     62       timeout_(base::TimeDelta::FromSeconds(kDefaultTimeout)),
     63       weak_ptr_factory_(this) {
     64 }
     65 
     66 RequestManager::~RequestManager() {
     67   // Abort all of the active requests.
     68   RequestMap::iterator it = requests_.begin();
     69   while (it != requests_.end()) {
     70     const int request_id = it->first;
     71     ++it;
     72     RejectRequest(request_id,
     73                   scoped_ptr<RequestValue>(new RequestValue()),
     74                   base::File::FILE_ERROR_ABORT);
     75   }
     76 
     77   DCHECK_EQ(0u, requests_.size());
     78   STLDeleteValues(&requests_);
     79 }
     80 
     81 int RequestManager::CreateRequest(RequestType type,
     82                                   scoped_ptr<HandlerInterface> handler) {
     83   // The request id is unique per request manager, so per service, thereof
     84   // per profile.
     85   int request_id = next_id_++;
     86 
     87   // If cycled the int, then signal an error.
     88   if (requests_.find(request_id) != requests_.end())
     89     return 0;
     90 
     91   TRACE_EVENT_ASYNC_BEGIN1("file_system_provider",
     92                            "RequestManager::Request",
     93                            request_id,
     94                            "type",
     95                            type);
     96 
     97   Request* request = new Request;
     98   request->handler = handler.Pass();
     99   requests_[request_id] = request;
    100   ResetTimer(request_id);
    101 
    102   FOR_EACH_OBSERVER(Observer, observers_, OnRequestCreated(request_id, type));
    103 
    104   // Execute the request implementation. In case of an execution failure,
    105   // unregister and return 0. This may often happen, eg. if the providing
    106   // extension is not listening for the request event being sent.
    107   // In such case, we should abort as soon as possible.
    108   if (!request->handler->Execute(request_id)) {
    109     DestroyRequest(request_id);
    110     return 0;
    111   }
    112 
    113   FOR_EACH_OBSERVER(Observer, observers_, OnRequestExecuted(request_id));
    114 
    115   return request_id;
    116 }
    117 
    118 bool RequestManager::FulfillRequest(int request_id,
    119                                     scoped_ptr<RequestValue> response,
    120                                     bool has_more) {
    121   CHECK(response.get());
    122   RequestMap::iterator request_it = requests_.find(request_id);
    123   if (request_it == requests_.end())
    124     return false;
    125 
    126   FOR_EACH_OBSERVER(Observer,
    127                     observers_,
    128                     OnRequestFulfilled(request_id, *response.get(), has_more));
    129 
    130   request_it->second->handler->OnSuccess(request_id, response.Pass(), has_more);
    131 
    132   if (!has_more) {
    133     DestroyRequest(request_id);
    134   } else {
    135     if (notification_manager_)
    136       notification_manager_->HideUnresponsiveNotification(request_id);
    137     ResetTimer(request_id);
    138   }
    139 
    140   return true;
    141 }
    142 
    143 bool RequestManager::RejectRequest(int request_id,
    144                                    scoped_ptr<RequestValue> response,
    145                                    base::File::Error error) {
    146   CHECK(response.get());
    147   RequestMap::iterator request_it = requests_.find(request_id);
    148   if (request_it == requests_.end())
    149     return false;
    150 
    151   FOR_EACH_OBSERVER(Observer,
    152                     observers_,
    153                     OnRequestRejected(request_id, *response.get(), error));
    154   request_it->second->handler->OnError(request_id, response.Pass(), error);
    155   DestroyRequest(request_id);
    156 
    157   return true;
    158 }
    159 
    160 void RequestManager::SetTimeoutForTesting(const base::TimeDelta& timeout) {
    161   timeout_ = timeout;
    162 }
    163 
    164 std::vector<int> RequestManager::GetActiveRequestIds() const {
    165   std::vector<int> result;
    166 
    167   for (RequestMap::const_iterator request_it = requests_.begin();
    168        request_it != requests_.end();
    169        ++request_it) {
    170     result.push_back(request_it->first);
    171   }
    172 
    173   return result;
    174 }
    175 
    176 void RequestManager::AddObserver(Observer* observer) {
    177   DCHECK(observer);
    178   observers_.AddObserver(observer);
    179 }
    180 
    181 void RequestManager::RemoveObserver(Observer* observer) {
    182   DCHECK(observer);
    183   observers_.RemoveObserver(observer);
    184 }
    185 
    186 RequestManager::Request::Request() {}
    187 
    188 RequestManager::Request::~Request() {}
    189 
    190 void RequestManager::OnRequestTimeout(int request_id) {
    191   FOR_EACH_OBSERVER(Observer, observers_, OnRequestTimeouted(request_id));
    192 
    193   if (!notification_manager_) {
    194     RejectRequest(request_id,
    195                   scoped_ptr<RequestValue>(new RequestValue()),
    196                   base::File::FILE_ERROR_ABORT);
    197     return;
    198   }
    199 
    200   notification_manager_->ShowUnresponsiveNotification(
    201       request_id,
    202       base::Bind(&RequestManager::OnUnresponsiveNotificationResult,
    203                  weak_ptr_factory_.GetWeakPtr(),
    204                  request_id));
    205 }
    206 
    207 void RequestManager::OnUnresponsiveNotificationResult(
    208     int request_id,
    209     NotificationManagerInterface::NotificationResult result) {
    210   RequestMap::iterator request_it = requests_.find(request_id);
    211   if (request_it == requests_.end())
    212     return;
    213 
    214   if (result == NotificationManagerInterface::CONTINUE) {
    215     ResetTimer(request_id);
    216     return;
    217   }
    218 
    219   RejectRequest(request_id,
    220                 scoped_ptr<RequestValue>(new RequestValue()),
    221                 base::File::FILE_ERROR_ABORT);
    222 }
    223 
    224 void RequestManager::ResetTimer(int request_id) {
    225   RequestMap::iterator request_it = requests_.find(request_id);
    226   if (request_it == requests_.end())
    227     return;
    228 
    229   request_it->second->timeout_timer.Start(
    230       FROM_HERE,
    231       timeout_,
    232       base::Bind(&RequestManager::OnRequestTimeout,
    233                  weak_ptr_factory_.GetWeakPtr(),
    234                  request_id));
    235 }
    236 
    237 void RequestManager::DestroyRequest(int request_id) {
    238   RequestMap::iterator request_it = requests_.find(request_id);
    239   if (request_it == requests_.end())
    240     return;
    241 
    242   delete request_it->second;
    243   requests_.erase(request_it);
    244 
    245   if (notification_manager_)
    246     notification_manager_->HideUnresponsiveNotification(request_id);
    247 
    248   FOR_EACH_OBSERVER(Observer, observers_, OnRequestDestroyed(request_id));
    249 
    250   TRACE_EVENT_ASYNC_END0(
    251       "file_system_provider", "RequestManager::Request", request_id);
    252 }
    253 
    254 }  // namespace file_system_provider
    255 }  // namespace chromeos
    256