OLD | NEW |
| (Empty) |
1 // 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 "chrome/browser/ui/webui/chrome_url_data_manager.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/lazy_instance.h" | |
11 #include "base/memory/ref_counted_memory.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/message_loop.h" | |
14 #include "base/string_util.h" | |
15 #include "base/synchronization/lock.h" | |
16 #include "chrome/browser/profiles/profile.h" | |
17 #include "chrome/browser/ui/webui/chrome_url_data_manager_factory.h" | |
18 #include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h" | |
19 #include "chrome/browser/ui/webui/chrome_web_ui_data_source.h" | |
20 #include "content/public/browser/browser_thread.h" | |
21 #include "content/public/browser/url_data_source.h" | |
22 | |
23 using content::BrowserThread; | |
24 | |
25 static base::LazyInstance<base::Lock>::Leaky | |
26 g_delete_lock = LAZY_INSTANCE_INITIALIZER; | |
27 | |
28 // static | |
29 ChromeURLDataManager::URLDataSources* ChromeURLDataManager::data_sources_ = | |
30 NULL; | |
31 | |
32 // Invoked on the IO thread to do the actual adding of the DataSource. | |
33 static void AddDataSourceOnIOThread( | |
34 const base::Callback<ChromeURLDataManagerBackend*(void)>& backend, | |
35 scoped_refptr<URLDataSourceImpl> data_source) { | |
36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
37 backend.Run()->AddDataSource(data_source.get()); | |
38 } | |
39 | |
40 ChromeURLDataManager::ChromeURLDataManager( | |
41 const base::Callback<ChromeURLDataManagerBackend*(void)>& backend) | |
42 : backend_(backend) { | |
43 } | |
44 | |
45 ChromeURLDataManager::~ChromeURLDataManager() { | |
46 } | |
47 | |
48 void ChromeURLDataManager::AddDataSource(URLDataSourceImpl* source) { | |
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
50 BrowserThread::PostTask( | |
51 BrowserThread::IO, FROM_HERE, | |
52 base::Bind(&AddDataSourceOnIOThread, | |
53 backend_, make_scoped_refptr(source))); | |
54 } | |
55 | |
56 // static | |
57 void ChromeURLDataManager::DeleteDataSources() { | |
58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
59 URLDataSources sources; | |
60 { | |
61 base::AutoLock lock(g_delete_lock.Get()); | |
62 if (!data_sources_) | |
63 return; | |
64 data_sources_->swap(sources); | |
65 } | |
66 for (size_t i = 0; i < sources.size(); ++i) | |
67 delete sources[i]; | |
68 } | |
69 | |
70 // static | |
71 void ChromeURLDataManager::DeleteDataSource( | |
72 const URLDataSourceImpl* data_source) { | |
73 // Invoked when a DataSource is no longer referenced and needs to be deleted. | |
74 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
75 // We're on the UI thread, delete right away. | |
76 delete data_source; | |
77 return; | |
78 } | |
79 | |
80 // We're not on the UI thread, add the DataSource to the list of DataSources | |
81 // to delete. | |
82 bool schedule_delete = false; | |
83 { | |
84 base::AutoLock lock(g_delete_lock.Get()); | |
85 if (!data_sources_) | |
86 data_sources_ = new URLDataSources(); | |
87 schedule_delete = data_sources_->empty(); | |
88 data_sources_->push_back(data_source); | |
89 } | |
90 if (schedule_delete) { | |
91 // Schedule a task to delete the DataSource back on the UI thread. | |
92 BrowserThread::PostTask( | |
93 BrowserThread::UI, FROM_HERE, | |
94 base::Bind(&ChromeURLDataManager::DeleteDataSources)); | |
95 } | |
96 } | |
97 | |
98 // static | |
99 void ChromeURLDataManager::AddDataSource( | |
100 Profile* profile, | |
101 content::URLDataSource* source) { | |
102 ChromeURLDataManagerFactory::GetForProfile(profile)->AddDataSource( | |
103 new URLDataSourceImpl(source->GetSource(), source)); | |
104 } | |
105 | |
106 // static | |
107 void ChromeURLDataManager::AddWebUIDataSource( | |
108 Profile* profile, | |
109 content::WebUIDataSource* source) { | |
110 ChromeWebUIDataSource* impl = static_cast<ChromeWebUIDataSource*>(source); | |
111 ChromeURLDataManagerFactory::GetForProfile(profile)->AddDataSource(impl); | |
112 } | |
113 | |
114 // static | |
115 bool ChromeURLDataManager::IsScheduledForDeletion( | |
116 const URLDataSourceImpl* data_source) { | |
117 base::AutoLock lock(g_delete_lock.Get()); | |
118 if (!data_sources_) | |
119 return false; | |
120 return std::find(data_sources_->begin(), data_sources_->end(), data_source) != | |
121 data_sources_->end(); | |
122 } | |
123 | |
124 URLDataSourceImpl::URLDataSourceImpl(const std::string& source_name, | |
125 content::URLDataSource* source) | |
126 : source_name_(source_name), | |
127 backend_(NULL), | |
128 source_(source) { | |
129 } | |
130 | |
131 URLDataSourceImpl::~URLDataSourceImpl() { | |
132 } | |
133 | |
134 void URLDataSourceImpl::SendResponse( | |
135 int request_id, | |
136 base::RefCountedMemory* bytes) { | |
137 // Take a ref-pointer on entry so byte->Release() will always get called. | |
138 scoped_refptr<base::RefCountedMemory> bytes_ptr(bytes); | |
139 if (ChromeURLDataManager::IsScheduledForDeletion(this)) { | |
140 // We're scheduled for deletion. Servicing the request would result in | |
141 // this->AddRef being invoked, even though the ref count is 0 and 'this' is | |
142 // about to be deleted. If the AddRef were allowed through, when 'this' is | |
143 // released it would be deleted again. | |
144 // | |
145 // This scenario occurs with DataSources that make history requests. Such | |
146 // DataSources do a history query in |StartDataRequest| and the request is | |
147 // live until the object is deleted (history requests don't up the ref | |
148 // count). This means it's entirely possible for the DataSource to invoke | |
149 // |SendResponse| between the time when there are no more refs and the time | |
150 // when the object is deleted. | |
151 return; | |
152 } | |
153 BrowserThread::PostTask( | |
154 BrowserThread::IO, FROM_HERE, | |
155 base::Bind(&URLDataSourceImpl::SendResponseOnIOThread, this, request_id, | |
156 bytes_ptr)); | |
157 } | |
158 | |
159 void URLDataSourceImpl::SendResponseOnIOThread( | |
160 int request_id, | |
161 scoped_refptr<base::RefCountedMemory> bytes) { | |
162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
163 if (backend_) | |
164 backend_->DataAvailable(request_id, bytes); | |
165 } | |
OLD | NEW |