OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/dom_ui/chrome_url_data_manager.h" | 5 #include "chrome/browser/dom_ui/chrome_url_data_manager.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include <vector> |
8 | |
8 #include "base/i18n/rtl.h" | 9 #include "base/i18n/rtl.h" |
9 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
10 #include "base/path_service.h" | |
11 #include "base/ref_counted_memory.h" | 11 #include "base/ref_counted_memory.h" |
12 #include "base/singleton.h" | |
13 #include "base/stl_util-inl.h" | |
14 #include "base/string_util.h" | 12 #include "base/string_util.h" |
15 #include "base/threading/thread.h" | 13 #include "base/synchronization/lock.h" |
16 #include "base/values.h" | 14 #include "base/values.h" |
15 #include "chrome/browser/browser_thread.h" | |
16 #include "chrome/browser/dom_ui/chrome_url_data_manager_backend.h" | |
17 #include "chrome/browser/net/chrome_url_request_context.h" | |
18 #include "chrome/browser/profiles/profile.h" | |
19 #include "grit/platform_locale_settings.h" | |
20 #include "ui/base/l10n/l10n_util.h" | |
21 | |
17 #if defined(OS_WIN) | 22 #if defined(OS_WIN) |
18 #include "base/win/windows_version.h" | 23 #include "base/win/windows_version.h" |
19 #endif | 24 #endif |
20 #include "chrome/browser/appcache/view_appcache_internals_job_factory.h" | |
21 #include "chrome/browser/browser_thread.h" | |
22 #include "chrome/browser/dom_ui/shared_resources_data_source.h" | |
23 #include "chrome/browser/net/chrome_url_request_context.h" | |
24 #include "chrome/browser/net/view_blob_internals_job_factory.h" | |
25 #include "chrome/browser/net/view_http_cache_job_factory.h" | |
26 #include "chrome/common/chrome_paths.h" | |
27 #include "chrome/common/ref_counted_util.h" | |
28 #include "chrome/common/url_constants.h" | |
29 #include "googleurl/src/url_util.h" | |
30 #include "grit/platform_locale_settings.h" | |
31 #include "net/base/io_buffer.h" | |
32 #include "net/base/net_errors.h" | |
33 #include "net/url_request/url_request.h" | |
34 #include "net/url_request/url_request_file_job.h" | |
35 #include "net/url_request/url_request_job.h" | |
36 #include "ui/base/l10n/l10n_util.h" | |
37 | 25 |
38 // URLRequestChromeJob is a net::URLRequestJob that manages running | 26 // static |
39 // chrome-internal resource requests asynchronously. | 27 base::Lock ChromeURLDataManager::delete_lock_; |
40 // It hands off URL requests to ChromeURLDataManager, which asynchronously | |
41 // calls back once the data is available. | |
42 class URLRequestChromeJob : public net::URLRequestJob { | |
43 public: | |
44 explicit URLRequestChromeJob(net::URLRequest* request); | |
45 | 28 |
46 // net::URLRequestJob implementation. | 29 // static |
47 virtual void Start(); | 30 ChromeURLDataManager::DataSources* ChromeURLDataManager::data_sources_ = NULL; |
48 virtual void Kill(); | |
49 virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read); | |
50 virtual bool GetMimeType(std::string* mime_type) const; | |
51 | 31 |
52 // Called by ChromeURLDataManager to notify us that the data blob is ready | 32 // Invoked on the IO thread to do the actual adding of the DataSource. |
53 // for us. | 33 static void AddDataSourceOnIOThread( |
54 void DataAvailable(RefCountedMemory* bytes); | 34 scoped_refptr<URLRequestContextGetter> context_getter, |
35 scoped_refptr<ChromeURLDataManager::DataSource> data_source) { | |
36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
37 static_cast<ChromeURLRequestContext*>( | |
38 context_getter->GetURLRequestContext())-> | |
39 GetChromeURLDataManagerBackend()->AddDataSource(data_source.get()); | |
40 } | |
55 | 41 |
56 void SetMimeType(const std::string& mime_type) { | 42 ChromeURLDataManager::ChromeURLDataManager(Profile* profile) |
57 mime_type_ = mime_type; | 43 : profile_(profile) { |
44 } | |
45 | |
46 ChromeURLDataManager::~ChromeURLDataManager() { | |
47 } | |
48 | |
49 void ChromeURLDataManager::AddDataSource(DataSource* source) { | |
50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
51 BrowserThread::PostTask( | |
52 BrowserThread::IO, FROM_HERE, | |
53 NewRunnableFunction(AddDataSourceOnIOThread, | |
54 make_scoped_refptr(profile_->GetRequestContext()), | |
55 make_scoped_refptr(source))); | |
56 } | |
57 | |
58 // static | |
59 void ChromeURLDataManager::DeleteDataSources() { | |
60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
61 DataSources sources; | |
62 { | |
63 base::AutoLock lock(delete_lock_); | |
64 if (!data_sources_) | |
65 return; | |
66 data_sources_->swap(sources); | |
67 } | |
68 for (size_t i = 0; i < sources.size(); ++i) | |
69 delete sources[i]; | |
70 } | |
71 | |
72 // static | |
73 void ChromeURLDataManager::DeleteDataSource(const DataSource* data_source) { | |
74 // Invoked when a DataSource is no longer referenced and needs to be deleted. | |
75 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
76 // We're on the UI thread, delete right away. | |
77 delete data_source; | |
78 return; | |
58 } | 79 } |
59 | 80 |
60 private: | 81 // We're not on the UI thread, add the DataSource to the list of DataSources |
61 virtual ~URLRequestChromeJob(); | 82 // to delete. |
62 | 83 bool schedule_delete = false; |
63 // Helper for Start(), to let us start asynchronously. | 84 { |
64 // (This pattern is shared by most net::URLRequestJob implementations.) | 85 base::AutoLock lock(delete_lock_); |
65 void StartAsync(); | 86 if (!data_sources_) |
66 | 87 data_sources_ = new DataSources(); |
67 // Do the actual copy from data_ (the data we're serving) into |buf|. | 88 schedule_delete = data_sources_->empty(); |
68 // Separate from ReadRawData so we can handle async I/O. | 89 data_sources_->push_back(data_source); |
69 void CompleteRead(net::IOBuffer* buf, int buf_size, int* bytes_read); | |
70 | |
71 // The actual data we're serving. NULL until it's been fetched. | |
72 scoped_refptr<RefCountedMemory> data_; | |
73 // The current offset into the data that we're handing off to our | |
74 // callers via the Read interfaces. | |
75 int data_offset_; | |
76 | |
77 // For async reads, we keep around a pointer to the buffer that | |
78 // we're reading into. | |
79 scoped_refptr<net::IOBuffer> pending_buf_; | |
80 int pending_buf_size_; | |
81 std::string mime_type_; | |
82 | |
83 DISALLOW_COPY_AND_ASSIGN(URLRequestChromeJob); | |
84 }; | |
85 | |
86 // URLRequestChromeFileJob is a net::URLRequestJob that acts like a file:// URL | |
87 class URLRequestChromeFileJob : public net::URLRequestFileJob { | |
88 public: | |
89 URLRequestChromeFileJob(net::URLRequest* request, const FilePath& path); | |
90 | |
91 private: | |
92 virtual ~URLRequestChromeFileJob(); | |
93 | |
94 DISALLOW_COPY_AND_ASSIGN(URLRequestChromeFileJob); | |
95 }; | |
96 | |
97 void RegisterURLRequestChromeJob() { | |
98 FilePath inspector_dir; | |
99 if (PathService::Get(chrome::DIR_INSPECTOR, &inspector_dir)) { | |
100 ChromeURLDataManager::GetInstance()->AddFileSource( | |
101 chrome::kChromeUIDevToolsHost, inspector_dir); | |
102 } | 90 } |
103 | 91 if (schedule_delete) { |
104 SharedResourcesDataSource::Register(); | 92 // Schedule a task to delete the DataSource back on the UI thread. |
105 net::URLRequest::RegisterProtocolFactory(chrome::kChromeDevToolsScheme, | 93 BrowserThread::PostTask(BrowserThread::UI, |
106 &ChromeURLDataManager::Factory); | 94 FROM_HERE, |
107 net::URLRequest::RegisterProtocolFactory(chrome::kChromeUIScheme, | 95 NewRunnableFunction( |
108 &ChromeURLDataManager::Factory); | 96 &ChromeURLDataManager::DeleteDataSources)); |
109 } | |
110 | |
111 void UnregisterURLRequestChromeJob() { | |
112 FilePath inspector_dir; | |
113 if (PathService::Get(chrome::DIR_INSPECTOR, &inspector_dir)) { | |
114 ChromeURLDataManager::GetInstance()->RemoveFileSource( | |
115 chrome::kChromeUIDevToolsHost); | |
116 } | 97 } |
117 } | 98 } |
118 | 99 |
119 // static | 100 // static |
120 void ChromeURLDataManager::URLToRequest(const GURL& url, | 101 bool ChromeURLDataManager::IsScheduledForDeletion( |
121 std::string* source_name, | 102 const DataSource* data_source) { |
122 std::string* path) { | 103 base::AutoLock lock(delete_lock_); |
123 DCHECK(url.SchemeIs(chrome::kChromeDevToolsScheme) || | 104 if (!data_sources_) |
124 url.SchemeIs(chrome::kChromeUIScheme)); | |
125 | |
126 if (!url.is_valid()) { | |
127 NOTREACHED(); | |
128 return; | |
129 } | |
130 | |
131 // Our input looks like: chrome://source_name/extra_bits?foo . | |
132 // So the url's "host" is our source, and everything after the host is | |
133 // the path. | |
134 source_name->assign(url.host()); | |
135 | |
136 const std::string& spec = url.possibly_invalid_spec(); | |
137 const url_parse::Parsed& parsed = url.parsed_for_possibly_invalid_spec(); | |
138 // + 1 to skip the slash at the beginning of the path. | |
139 int offset = parsed.CountCharactersBefore(url_parse::Parsed::PATH, false) + 1; | |
140 | |
141 if (offset < static_cast<int>(spec.size())) | |
142 path->assign(spec.substr(offset)); | |
143 } | |
144 | |
145 // static | |
146 bool ChromeURLDataManager::URLToFilePath(const GURL& url, | |
147 FilePath* file_path) { | |
148 // Parse the URL into a request for a source and path. | |
149 std::string source_name; | |
150 std::string relative_path; | |
151 | |
152 // Remove Query and Ref from URL. | |
153 GURL stripped_url; | |
154 GURL::Replacements replacements; | |
155 replacements.ClearQuery(); | |
156 replacements.ClearRef(); | |
157 stripped_url = url.ReplaceComponents(replacements); | |
158 | |
159 URLToRequest(stripped_url, &source_name, &relative_path); | |
160 | |
161 FileSourceMap::const_iterator i( | |
162 ChromeURLDataManager::GetInstance()->file_sources_.find(source_name)); | |
163 if (i == ChromeURLDataManager::GetInstance()->file_sources_.end()) | |
164 return false; | 105 return false; |
165 | 106 return std::find(data_sources_->begin(), data_sources_->end(), data_source) != |
166 // Check that |relative_path| is not an absolute path (otherwise AppendASCII() | 107 data_sources_->end(); |
167 // will DCHECK). The awkward use of StringType is because on some systems | |
168 // FilePath expects a std::string, but on others a std::wstring. | |
169 FilePath p(FilePath::StringType(relative_path.begin(), relative_path.end())); | |
170 if (p.IsAbsolute()) | |
171 return false; | |
172 | |
173 *file_path = i->second.AppendASCII(relative_path); | |
174 | |
175 return true; | |
176 } | |
177 | |
178 ChromeURLDataManager::ChromeURLDataManager() : next_request_id_(0) { } | |
179 | |
180 ChromeURLDataManager::~ChromeURLDataManager() { | |
181 // This is used as a Singleton, so it is only called at exit cleanup time. | |
182 // This means it is called on the main (UI) thread. | |
183 // | |
184 // It will break if it is called at shutdown time on a different thread, as | |
185 // it will attempt to call the destructors for its |data_source_|s on the | |
186 // UI thread, but the UI thread's message loop will be not be running | |
187 // -- so the destructor calls will be dropped and we will leak the objects. | |
188 } | |
189 | |
190 // static | |
191 ChromeURLDataManager* ChromeURLDataManager::GetInstance() { | |
192 return Singleton<ChromeURLDataManager>::get(); | |
193 } | |
194 | |
195 void ChromeURLDataManager::AddDataSource(scoped_refptr<DataSource> source) { | |
196 // Some |DataSource|-derived classes, notably |FileIconSource| and | |
197 // |WebUIFavIconSource|, have members that will DCHECK if they are not | |
198 // destructed in the same thread as they are constructed (the UI thread). | |
199 // | |
200 // If |AddDataSource| is called more than once, it will destruct the object | |
201 // that it had before, as it is the only thing still holding a reference to | |
202 // that object. |DataSource| uses the |DeleteOnUIThread| trait to insure | |
203 // that the destructor is called on the UI thread. | |
204 // | |
205 // TODO(jackson): A new data source with same name should not clobber the | |
206 // existing one. | |
207 data_sources_[source->source_name()] = source; | |
208 } | |
209 | |
210 void ChromeURLDataManager::RemoveDataSourceForTest(const char* source_name) { | |
211 DataSourceMap::iterator i = data_sources_.find(source_name); | |
212 if (i == data_sources_.end()) | |
213 return; | |
214 (*i).second = NULL; // Calls Release(). | |
215 data_sources_.erase(i); | |
216 } | |
217 | |
218 void ChromeURLDataManager::RemoveAllDataSources() { | |
219 for (DataSourceMap::iterator i = data_sources_.begin(); | |
220 i != data_sources_.end(); | |
221 i = data_sources_.begin()) { | |
222 (*i).second = NULL; // Calls Release(). | |
223 data_sources_.erase(i); | |
224 } | |
225 } | |
226 | |
227 void ChromeURLDataManager::AddFileSource(const std::string& source_name, | |
228 const FilePath& file_path) { | |
229 DCHECK(file_sources_.count(source_name) == 0); | |
230 file_sources_[source_name] = file_path; | |
231 } | |
232 | |
233 void ChromeURLDataManager::RemoveFileSource(const std::string& source_name) { | |
234 DCHECK(file_sources_.count(source_name) == 1); | |
235 file_sources_.erase(source_name); | |
236 } | |
237 | |
238 bool ChromeURLDataManager::HasPendingJob(URLRequestChromeJob* job) const { | |
239 for (PendingRequestMap::const_iterator i = pending_requests_.begin(); | |
240 i != pending_requests_.end(); ++i) { | |
241 if (i->second == job) | |
242 return true; | |
243 } | |
244 | |
245 return false; | |
246 } | |
247 | |
248 bool ChromeURLDataManager::StartRequest(const GURL& url, | |
249 URLRequestChromeJob* job) { | |
250 // Parse the URL into a request for a source and path. | |
251 std::string source_name; | |
252 std::string path; | |
253 URLToRequest(url, &source_name, &path); | |
254 | |
255 // Look up the data source for the request. | |
256 DataSourceMap::iterator i = data_sources_.find(source_name); | |
257 if (i == data_sources_.end()) | |
258 return false; | |
259 DataSource* source = i->second; | |
260 | |
261 // Save this request so we know where to send the data. | |
262 RequestID request_id = next_request_id_++; | |
263 pending_requests_.insert(std::make_pair(request_id, job)); | |
264 | |
265 // TODO(eroman): would be nicer if the mimetype were set at the same time | |
266 // as the data blob. For now do it here, since NotifyHeadersComplete() is | |
267 // going to get called once we return. | |
268 job->SetMimeType(source->GetMimeType(path)); | |
269 | |
270 ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>( | |
271 job->request()->context()); | |
272 | |
273 // Forward along the request to the data source. | |
274 MessageLoop* target_message_loop = source->MessageLoopForRequestPath(path); | |
275 if (!target_message_loop) { | |
276 // The DataSource is agnostic to which thread StartDataRequest is called | |
277 // on for this path. Call directly into it from this thread, the IO | |
278 // thread. | |
279 source->StartDataRequest(path, context->is_off_the_record(), request_id); | |
280 } else { | |
281 // The DataSource wants StartDataRequest to be called on a specific thread, | |
282 // usually the UI thread, for this path. | |
283 target_message_loop->PostTask(FROM_HERE, | |
284 NewRunnableMethod(source, &DataSource::StartDataRequest, | |
285 path, context->is_off_the_record(), request_id)); | |
286 } | |
287 return true; | |
288 } | |
289 | |
290 void ChromeURLDataManager::RemoveRequest(URLRequestChromeJob* job) { | |
291 // Remove the request from our list of pending requests. | |
292 // If/when the source sends the data that was requested, the data will just | |
293 // be thrown away. | |
294 for (PendingRequestMap::iterator i = pending_requests_.begin(); | |
295 i != pending_requests_.end(); ++i) { | |
296 if (i->second == job) { | |
297 pending_requests_.erase(i); | |
298 return; | |
299 } | |
300 } | |
301 } | |
302 | |
303 void ChromeURLDataManager::DataAvailable( | |
304 RequestID request_id, | |
305 scoped_refptr<RefCountedMemory> bytes) { | |
306 // Forward this data on to the pending net::URLRequest, if it exists. | |
307 PendingRequestMap::iterator i = pending_requests_.find(request_id); | |
308 if (i != pending_requests_.end()) { | |
309 // We acquire a reference to the job so that it doesn't disappear under the | |
310 // feet of any method invoked here (we could trigger a callback). | |
311 scoped_refptr<URLRequestChromeJob> job(i->second); | |
312 pending_requests_.erase(i); | |
313 job->DataAvailable(bytes); | |
314 } | |
315 } | 108 } |
316 | 109 |
317 ChromeURLDataManager::DataSource::DataSource(const std::string& source_name, | 110 ChromeURLDataManager::DataSource::DataSource(const std::string& source_name, |
318 MessageLoop* message_loop) | 111 MessageLoop* message_loop) |
319 : source_name_(source_name), message_loop_(message_loop) { | 112 : source_name_(source_name), |
113 message_loop_(message_loop), | |
114 backend_(NULL) { | |
320 } | 115 } |
321 | 116 |
322 ChromeURLDataManager::DataSource::~DataSource() { | 117 ChromeURLDataManager::DataSource::~DataSource() { |
323 } | 118 } |
324 | 119 |
325 void ChromeURLDataManager::DataSource::SendResponse( | 120 void ChromeURLDataManager::DataSource::SendResponse(int request_id, |
326 RequestID request_id, | 121 RefCountedMemory* bytes) { |
327 RefCountedMemory* bytes) { | 122 if (IsScheduledForDeletion(this)) { |
joth
2011/07/25 11:39:04
This doesn't seem quite sufficient? Between this f
sky
2011/07/25 14:20:26
This is a problem with any delayed deletion.
I do
| |
123 // We're scheduled for deletion. Servicing the request would result in | |
124 // this->AddRef being invoked, even though the ref count is 0 and 'this' is | |
125 // about to be deleted. If the AddRef were allowed through, when 'this' is | |
126 // released it would be deleted again. | |
127 // | |
128 // This scenario occurs with DataSources that make history requests. Such | |
129 // DataSources do a history query in |StartDataRequest| and the request is | |
130 // live until the object is deleted (history requests don't up the ref | |
131 // count). This means it's entirely possible for the DataSource to invoke | |
132 // |SendResponse| between the time when there are no more refs and the time | |
133 // when the object is deleted. | |
134 return; | |
135 } | |
328 BrowserThread::PostTask( | 136 BrowserThread::PostTask( |
329 BrowserThread::IO, FROM_HERE, | 137 BrowserThread::IO, FROM_HERE, |
330 NewRunnableMethod(ChromeURLDataManager::GetInstance(), | 138 NewRunnableMethod(this, &DataSource::SendResponseOnIOThread, |
331 &ChromeURLDataManager::DataAvailable, | 139 request_id, make_scoped_refptr(bytes))); |
332 request_id, scoped_refptr<RefCountedMemory>(bytes))); | |
333 } | 140 } |
334 | 141 |
335 MessageLoop* ChromeURLDataManager::DataSource::MessageLoopForRequestPath( | 142 MessageLoop* ChromeURLDataManager::DataSource::MessageLoopForRequestPath( |
336 const std::string& path) const { | 143 const std::string& path) const { |
337 return message_loop_; | 144 return message_loop_; |
338 } | 145 } |
339 | 146 |
340 // static | 147 // static |
341 void ChromeURLDataManager::DataSource::SetFontAndTextDirection( | 148 void ChromeURLDataManager::DataSource::SetFontAndTextDirection( |
342 DictionaryValue* localized_strings) { | 149 DictionaryValue* localized_strings) { |
343 localized_strings->SetString("fontfamily", | 150 localized_strings->SetString("fontfamily", |
344 l10n_util::GetStringUTF16(IDS_WEB_FONT_FAMILY)); | 151 l10n_util::GetStringUTF16(IDS_WEB_FONT_FAMILY)); |
345 | 152 |
346 int web_font_size_id = IDS_WEB_FONT_SIZE; | 153 int web_font_size_id = IDS_WEB_FONT_SIZE; |
347 #if defined(OS_WIN) | 154 #if defined(OS_WIN) |
348 // Some fonts used for some languages changed a lot in terms of the font | 155 // Some fonts used for some languages changed a lot in terms of the font |
349 // metric in Vista. So, we need to use different size before Vista. | 156 // metric in Vista. So, we need to use different size before Vista. |
350 if (base::win::GetVersion() < base::win::VERSION_VISTA) | 157 if (base::win::GetVersion() < base::win::VERSION_VISTA) |
351 web_font_size_id = IDS_WEB_FONT_SIZE_XP; | 158 web_font_size_id = IDS_WEB_FONT_SIZE_XP; |
352 #endif | 159 #endif |
353 localized_strings->SetString("fontsize", | 160 localized_strings->SetString("fontsize", |
354 l10n_util::GetStringUTF16(web_font_size_id)); | 161 l10n_util::GetStringUTF16(web_font_size_id)); |
355 | 162 |
356 localized_strings->SetString("textdirection", | 163 localized_strings->SetString("textdirection", |
357 base::i18n::IsRTL() ? "rtl" : "ltr"); | 164 base::i18n::IsRTL() ? "rtl" : "ltr"); |
358 } | 165 } |
359 | 166 |
360 net::URLRequestJob* ChromeURLDataManager::Factory(net::URLRequest* request, | 167 void ChromeURLDataManager::DataSource::SendResponseOnIOThread( |
361 const std::string& scheme) { | 168 int request_id, |
362 // Try first with a file handler | 169 scoped_refptr<RefCountedMemory> bytes) { |
363 FilePath path; | 170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
364 if (ChromeURLDataManager::URLToFilePath(request->url(), &path)) | 171 if (backend_) |
365 return new URLRequestChromeFileJob(request, path); | 172 backend_->DataAvailable(request_id, bytes); |
366 | |
367 // Next check for chrome://view-http-cache/*, which uses its own job type. | |
368 if (ViewHttpCacheJobFactory::IsSupportedURL(request->url())) | |
369 return ViewHttpCacheJobFactory::CreateJobForRequest(request); | |
370 | |
371 // Next check for chrome://appcache-internals/, which uses its own job type. | |
372 if (ViewAppCacheInternalsJobFactory::IsSupportedURL(request->url())) | |
373 return ViewAppCacheInternalsJobFactory::CreateJobForRequest(request); | |
374 | |
375 // Next check for chrome://blob-internals/, which uses its own job type. | |
376 if (ViewBlobInternalsJobFactory::IsSupportedURL(request->url())) | |
377 return ViewBlobInternalsJobFactory::CreateJobForRequest(request); | |
378 | |
379 // Fall back to using a custom handler | |
380 return new URLRequestChromeJob(request); | |
381 } | 173 } |
382 | |
383 URLRequestChromeJob::URLRequestChromeJob(net::URLRequest* request) | |
384 : net::URLRequestJob(request), | |
385 data_offset_(0), | |
386 pending_buf_size_(0) { | |
387 } | |
388 | |
389 URLRequestChromeJob::~URLRequestChromeJob() { | |
390 CHECK(!ChromeURLDataManager::GetInstance()->HasPendingJob(this)); | |
391 } | |
392 | |
393 void URLRequestChromeJob::Start() { | |
394 // Start reading asynchronously so that all error reporting and data | |
395 // callbacks happen as they would for network requests. | |
396 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( | |
397 this, &URLRequestChromeJob::StartAsync)); | |
398 } | |
399 | |
400 void URLRequestChromeJob::Kill() { | |
401 ChromeURLDataManager::GetInstance()->RemoveRequest(this); | |
402 } | |
403 | |
404 bool URLRequestChromeJob::GetMimeType(std::string* mime_type) const { | |
405 *mime_type = mime_type_; | |
406 return !mime_type_.empty(); | |
407 } | |
408 | |
409 void URLRequestChromeJob::DataAvailable(RefCountedMemory* bytes) { | |
410 if (bytes) { | |
411 // The request completed, and we have all the data. | |
412 // Clear any IO pending status. | |
413 SetStatus(net::URLRequestStatus()); | |
414 | |
415 data_ = bytes; | |
416 int bytes_read; | |
417 if (pending_buf_.get()) { | |
418 CHECK(pending_buf_->data()); | |
419 CompleteRead(pending_buf_, pending_buf_size_, &bytes_read); | |
420 pending_buf_ = NULL; | |
421 NotifyReadComplete(bytes_read); | |
422 } | |
423 } else { | |
424 // The request failed. | |
425 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, | |
426 net::ERR_FAILED)); | |
427 } | |
428 } | |
429 | |
430 bool URLRequestChromeJob::ReadRawData(net::IOBuffer* buf, int buf_size, | |
431 int* bytes_read) { | |
432 if (!data_.get()) { | |
433 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); | |
434 DCHECK(!pending_buf_.get()); | |
435 CHECK(buf->data()); | |
436 pending_buf_ = buf; | |
437 pending_buf_size_ = buf_size; | |
438 return false; // Tell the caller we're still waiting for data. | |
439 } | |
440 | |
441 // Otherwise, the data is available. | |
442 CompleteRead(buf, buf_size, bytes_read); | |
443 return true; | |
444 } | |
445 | |
446 void URLRequestChromeJob::CompleteRead(net::IOBuffer* buf, int buf_size, | |
447 int* bytes_read) { | |
448 int remaining = static_cast<int>(data_->size()) - data_offset_; | |
449 if (buf_size > remaining) | |
450 buf_size = remaining; | |
451 if (buf_size > 0) { | |
452 memcpy(buf->data(), data_->front() + data_offset_, buf_size); | |
453 data_offset_ += buf_size; | |
454 } | |
455 *bytes_read = buf_size; | |
456 } | |
457 | |
458 void URLRequestChromeJob::StartAsync() { | |
459 if (!request_) | |
460 return; | |
461 | |
462 if (ChromeURLDataManager::GetInstance()->StartRequest(request_->url(), | |
463 this)) { | |
464 NotifyHeadersComplete(); | |
465 } else { | |
466 NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, | |
467 net::ERR_INVALID_URL)); | |
468 } | |
469 } | |
470 | |
471 URLRequestChromeFileJob::URLRequestChromeFileJob(net::URLRequest* request, | |
472 const FilePath& path) | |
473 : net::URLRequestFileJob(request, path) { | |
474 } | |
475 | |
476 URLRequestChromeFileJob::~URLRequestChromeFileJob() { } | |
OLD | NEW |