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/files/file.h"
8 #include "base/stl_util.h"
9
10 namespace chromeos {
11 namespace file_system_provider {
12 namespace {
13
14 // Timeout in seconds, before a request is considered as stale and hence
15 // aborted.
16 const int kDefaultTimeout = 10;
17
18 } // namespace
19
RequestTypeToString(RequestType type)20 std::string RequestTypeToString(RequestType type) {
21 switch (type) {
22 case REQUEST_UNMOUNT:
23 return "REQUEST_UNMOUNT";
24 case GET_METADATA:
25 return "GET_METADATA";
26 case READ_DIRECTORY:
27 return "READ_DIRECTORY";
28 case OPEN_FILE:
29 return "OPEN_FILE";
30 case CLOSE_FILE:
31 return "CLOSE_FILE";
32 case READ_FILE:
33 return "READ_FILE";
34 case TESTING:
35 return "TESTING";
36 }
37 NOTREACHED();
38 return "";
39 }
40
RequestManager()41 RequestManager::RequestManager()
42 : next_id_(1),
43 timeout_(base::TimeDelta::FromSeconds(kDefaultTimeout)),
44 weak_ptr_factory_(this) {}
45
~RequestManager()46 RequestManager::~RequestManager() {
47 // Abort all of the active requests.
48 RequestMap::iterator it = requests_.begin();
49 while (it != requests_.end()) {
50 const int request_id = it->first;
51 ++it;
52 RejectRequest(request_id, base::File::FILE_ERROR_ABORT);
53 }
54
55 DCHECK_EQ(0u, requests_.size());
56 STLDeleteValues(&requests_);
57 }
58
CreateRequest(RequestType type,scoped_ptr<HandlerInterface> handler)59 int RequestManager::CreateRequest(RequestType type,
60 scoped_ptr<HandlerInterface> handler) {
61 // The request id is unique per request manager, so per service, thereof
62 // per profile.
63 int request_id = next_id_++;
64
65 // If cycled the int, then signal an error.
66 if (requests_.find(request_id) != requests_.end())
67 return 0;
68
69 Request* request = new Request;
70 request->handler = handler.Pass();
71 request->timeout_timer.Start(FROM_HERE,
72 timeout_,
73 base::Bind(&RequestManager::OnRequestTimeout,
74 weak_ptr_factory_.GetWeakPtr(),
75 request_id));
76 requests_[request_id] = request;
77
78 FOR_EACH_OBSERVER(Observer, observers_, OnRequestCreated(request_id, type));
79
80 // Execute the request implementation. In case of an execution failure,
81 // unregister and return 0. This may often happen, eg. if the providing
82 // extension is not listening for the request event being sent.
83 // In such case, we should abort as soon as possible.
84 if (!request->handler->Execute(request_id)) {
85 DestroyRequest(request_id);
86 return 0;
87 }
88
89 FOR_EACH_OBSERVER(Observer, observers_, OnRequestExecuted(request_id));
90
91 return request_id;
92 }
93
FulfillRequest(int request_id,scoped_ptr<RequestValue> response,bool has_more)94 bool RequestManager::FulfillRequest(int request_id,
95 scoped_ptr<RequestValue> response,
96 bool has_more) {
97 RequestMap::iterator request_it = requests_.find(request_id);
98 if (request_it == requests_.end())
99 return false;
100
101 request_it->second->handler->OnSuccess(request_id, response.Pass(), has_more);
102
103 FOR_EACH_OBSERVER(
104 Observer, observers_, OnRequestFulfilled(request_id, has_more));
105
106 if (!has_more)
107 DestroyRequest(request_id);
108 else
109 request_it->second->timeout_timer.Reset();
110
111 return true;
112 }
113
RejectRequest(int request_id,base::File::Error error)114 bool RequestManager::RejectRequest(int request_id, base::File::Error error) {
115 RequestMap::iterator request_it = requests_.find(request_id);
116 if (request_it == requests_.end())
117 return false;
118
119 request_it->second->handler->OnError(request_id, error);
120
121 FOR_EACH_OBSERVER(Observer, observers_, OnRequestRejected(request_id, error));
122
123 DestroyRequest(request_id);
124
125 return true;
126 }
127
SetTimeoutForTesting(const base::TimeDelta & timeout)128 void RequestManager::SetTimeoutForTesting(const base::TimeDelta& timeout) {
129 timeout_ = timeout;
130 }
131
GetActiveRequestsForLogging() const132 size_t RequestManager::GetActiveRequestsForLogging() const {
133 return requests_.size();
134 }
135
AddObserver(Observer * observer)136 void RequestManager::AddObserver(Observer* observer) {
137 DCHECK(observer);
138 observers_.AddObserver(observer);
139 }
140
RemoveObserver(Observer * observer)141 void RequestManager::RemoveObserver(Observer* observer) {
142 DCHECK(observer);
143 observers_.RemoveObserver(observer);
144 }
145
Request()146 RequestManager::Request::Request() {}
147
~Request()148 RequestManager::Request::~Request() {}
149
OnRequestTimeout(int request_id)150 void RequestManager::OnRequestTimeout(int request_id) {
151 FOR_EACH_OBSERVER(Observer, observers_, OnRequestTimeouted(request_id));
152
153 RejectRequest(request_id, base::File::FILE_ERROR_ABORT);
154 }
155
DestroyRequest(int request_id)156 void RequestManager::DestroyRequest(int request_id) {
157 RequestMap::iterator request_it = requests_.find(request_id);
158 if (request_it == requests_.end())
159 return;
160
161 delete request_it->second;
162 requests_.erase(request_it);
163
164 FOR_EACH_OBSERVER(Observer, observers_, OnRequestDestroyed(request_id));
165 }
166
167 } // namespace file_system_provider
168 } // namespace chromeos
169