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 11namespace chromeos { 12namespace file_system_provider { 13namespace { 14 15// Timeout in seconds, before a request is considered as stale and hence 16// aborted. 17const int kDefaultTimeout = 10; 18 19} // namespace 20 21std::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 58RequestManager::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 66RequestManager::~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 81int 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 118bool 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 143bool 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 160void RequestManager::SetTimeoutForTesting(const base::TimeDelta& timeout) { 161 timeout_ = timeout; 162} 163 164std::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 176void RequestManager::AddObserver(Observer* observer) { 177 DCHECK(observer); 178 observers_.AddObserver(observer); 179} 180 181void RequestManager::RemoveObserver(Observer* observer) { 182 DCHECK(observer); 183 observers_.RemoveObserver(observer); 184} 185 186RequestManager::Request::Request() {} 187 188RequestManager::Request::~Request() {} 189 190void 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 207void 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 224void 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 237void 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