Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsThreadUtils.h"
6 #include "nsAndroidHistory.h"
7 #include "AndroidBridge.h"
8 #include "Link.h"
9 #include "nsIURI.h"
10 #include "mozilla/Services.h"
11 #include "nsIObserverService.h"
13 #define NS_LINK_VISITED_EVENT_TOPIC "link-visited"
15 using namespace mozilla;
16 using mozilla::dom::Link;
18 NS_IMPL_ISUPPORTS(nsAndroidHistory, IHistory, nsIRunnable)
20 nsAndroidHistory* nsAndroidHistory::sHistory = nullptr;
22 /*static*/
23 nsAndroidHistory*
24 nsAndroidHistory::GetSingleton()
25 {
26 if (!sHistory) {
27 sHistory = new nsAndroidHistory();
28 NS_ENSURE_TRUE(sHistory, nullptr);
29 }
31 NS_ADDREF(sHistory);
32 return sHistory;
33 }
35 nsAndroidHistory::nsAndroidHistory()
36 {
37 }
39 NS_IMETHODIMP
40 nsAndroidHistory::RegisterVisitedCallback(nsIURI *aURI, Link *aContent)
41 {
42 if (!aContent || !aURI)
43 return NS_OK;
45 // Silently return if URI is something we would never add to DB.
46 bool canAdd;
47 nsresult rv = CanAddURI(aURI, &canAdd);
48 NS_ENSURE_SUCCESS(rv, rv);
49 if (!canAdd) {
50 return NS_OK;
51 }
53 nsAutoCString uri;
54 rv = aURI->GetSpec(uri);
55 if (NS_FAILED(rv)) return rv;
56 NS_ConvertUTF8toUTF16 uriString(uri);
58 nsTArray<Link*>* list = mListeners.Get(uriString);
59 if (! list) {
60 list = new nsTArray<Link*>();
61 mListeners.Put(uriString, list);
62 }
63 list->AppendElement(aContent);
65 if (AndroidBridge::HasEnv()) {
66 mozilla::widget::android::GeckoAppShell::CheckURIVisited(uriString);
67 }
69 return NS_OK;
70 }
72 NS_IMETHODIMP
73 nsAndroidHistory::UnregisterVisitedCallback(nsIURI *aURI, Link *aContent)
74 {
75 if (!aContent || !aURI)
76 return NS_OK;
78 nsAutoCString uri;
79 nsresult rv = aURI->GetSpec(uri);
80 if (NS_FAILED(rv)) return rv;
81 NS_ConvertUTF8toUTF16 uriString(uri);
83 nsTArray<Link*>* list = mListeners.Get(uriString);
84 if (! list)
85 return NS_OK;
87 list->RemoveElement(aContent);
88 if (list->IsEmpty()) {
89 mListeners.Remove(uriString);
90 delete list;
91 }
92 return NS_OK;
93 }
95 void
96 nsAndroidHistory::AppendToRecentlyVisitedURIs(nsIURI* aURI) {
97 if (mRecentlyVisitedURIs.Length() < RECENTLY_VISITED_URI_SIZE) {
98 // Append a new element while the array is not full.
99 mRecentlyVisitedURIs.AppendElement(aURI);
100 } else {
101 // Otherwise, replace the oldest member.
102 mRecentlyVisitedURIsNextIndex %= RECENTLY_VISITED_URI_SIZE;
103 mRecentlyVisitedURIs.ElementAt(mRecentlyVisitedURIsNextIndex) = aURI;
104 mRecentlyVisitedURIsNextIndex++;
105 }
106 }
108 inline bool
109 nsAndroidHistory::IsRecentlyVisitedURI(nsIURI* aURI) {
110 bool equals = false;
111 RecentlyVisitedArray::index_type i;
112 RecentlyVisitedArray::size_type length = mRecentlyVisitedURIs.Length();
113 for (i = 0; i < length && !equals; ++i) {
114 aURI->Equals(mRecentlyVisitedURIs.ElementAt(i), &equals);
115 }
116 return equals;
117 }
119 void
120 nsAndroidHistory::AppendToEmbedURIs(nsIURI* aURI) {
121 if (mEmbedURIs.Length() < EMBED_URI_SIZE) {
122 // Append a new element while the array is not full.
123 mEmbedURIs.AppendElement(aURI);
124 } else {
125 // Otherwise, replace the oldest member.
126 mEmbedURIsNextIndex %= EMBED_URI_SIZE;
127 mEmbedURIs.ElementAt(mEmbedURIsNextIndex) = aURI;
128 mEmbedURIsNextIndex++;
129 }
130 }
132 inline bool
133 nsAndroidHistory::IsEmbedURI(nsIURI* aURI) {
134 bool equals = false;
135 EmbedArray::index_type i;
136 EmbedArray::size_type length = mEmbedURIs.Length();
137 for (i = 0; i < length && !equals; ++i) {
138 aURI->Equals(mEmbedURIs.ElementAt(i), &equals);
139 }
140 return equals;
141 }
143 NS_IMETHODIMP
144 nsAndroidHistory::VisitURI(nsIURI *aURI, nsIURI *aLastVisitedURI, uint32_t aFlags)
145 {
146 if (!aURI)
147 return NS_OK;
149 // Silently return if URI is something we shouldn't add to DB.
150 bool canAdd;
151 nsresult rv = CanAddURI(aURI, &canAdd);
152 NS_ENSURE_SUCCESS(rv, rv);
153 if (!canAdd) {
154 return NS_OK;
155 }
157 if (aLastVisitedURI) {
158 bool same;
159 rv = aURI->Equals(aLastVisitedURI, &same);
160 NS_ENSURE_SUCCESS(rv, rv);
161 if (same && IsRecentlyVisitedURI(aURI)) {
162 // Do not save refresh visits if we have visited this URI recently.
163 return NS_OK;
164 }
165 }
167 if (!(aFlags & VisitFlags::TOP_LEVEL)) {
168 AppendToEmbedURIs(aURI);
169 return NS_OK;
170 }
172 if (aFlags & VisitFlags::REDIRECT_SOURCE)
173 return NS_OK;
175 if (aFlags & VisitFlags::UNRECOVERABLE_ERROR)
176 return NS_OK;
178 if (AndroidBridge::HasEnv()) {
179 nsAutoCString uri;
180 rv = aURI->GetSpec(uri);
181 if (NS_FAILED(rv)) return rv;
182 NS_ConvertUTF8toUTF16 uriString(uri);
183 mozilla::widget::android::GeckoAppShell::MarkURIVisited(uriString);
184 }
186 AppendToRecentlyVisitedURIs(aURI);
188 // Finally, notify that we've been visited.
189 nsCOMPtr<nsIObserverService> obsService =
190 mozilla::services::GetObserverService();
191 if (obsService) {
192 obsService->NotifyObservers(aURI, NS_LINK_VISITED_EVENT_TOPIC, nullptr);
193 }
195 return NS_OK;
196 }
198 NS_IMETHODIMP
199 nsAndroidHistory::SetURITitle(nsIURI *aURI, const nsAString& aTitle)
200 {
201 // Silently return if URI is something we shouldn't add to DB.
202 bool canAdd;
203 nsresult rv = CanAddURI(aURI, &canAdd);
204 NS_ENSURE_SUCCESS(rv, rv);
205 if (!canAdd) {
206 return NS_OK;
207 }
209 if (IsEmbedURI(aURI)) {
210 return NS_OK;
211 }
213 if (AndroidBridge::HasEnv()) {
214 nsAutoCString uri;
215 nsresult rv = aURI->GetSpec(uri);
216 if (NS_FAILED(rv)) return rv;
217 NS_ConvertUTF8toUTF16 uriString(uri);
218 mozilla::widget::android::GeckoAppShell::SetURITitle(uriString, aTitle);
219 }
220 return NS_OK;
221 }
223 NS_IMETHODIMP
224 nsAndroidHistory::NotifyVisited(nsIURI *aURI)
225 {
226 if (aURI && sHistory) {
227 nsAutoCString spec;
228 (void)aURI->GetSpec(spec);
229 sHistory->mPendingURIs.Push(NS_ConvertUTF8toUTF16(spec));
230 NS_DispatchToMainThread(sHistory);
231 }
232 return NS_OK;
233 }
235 NS_IMETHODIMP
236 nsAndroidHistory::Run()
237 {
238 while (! mPendingURIs.IsEmpty()) {
239 nsString uriString = mPendingURIs.Pop();
240 nsTArray<Link*>* list = sHistory->mListeners.Get(uriString);
241 if (list) {
242 for (unsigned int i = 0; i < list->Length(); i++) {
243 list->ElementAt(i)->SetLinkState(eLinkState_Visited);
244 }
245 // as per the IHistory interface contract, remove the
246 // Link pointers once they have been notified
247 mListeners.Remove(uriString);
248 delete list;
249 }
250 }
251 return NS_OK;
252 }
254 // Filter out unwanted URIs such as "chrome:", "mailbox:", etc.
255 //
256 // The model is if we don't know differently then add which basically means
257 // we are suppose to try all the things we know not to allow in and then if
258 // we don't bail go on and allow it in.
259 //
260 // Logic ported from nsNavHistory::CanAddURI.
262 NS_IMETHODIMP
263 nsAndroidHistory::CanAddURI(nsIURI* aURI, bool* canAdd)
264 {
265 NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
266 NS_ENSURE_ARG(aURI);
267 NS_ENSURE_ARG_POINTER(canAdd);
269 nsAutoCString scheme;
270 nsresult rv = aURI->GetScheme(scheme);
271 NS_ENSURE_SUCCESS(rv, rv);
273 // first check the most common cases (HTTP, HTTPS) to allow in to avoid most
274 // of the work
275 if (scheme.EqualsLiteral("http")) {
276 *canAdd = true;
277 return NS_OK;
278 }
279 if (scheme.EqualsLiteral("https")) {
280 *canAdd = true;
281 return NS_OK;
282 }
284 // now check for all bad things
285 if (scheme.EqualsLiteral("about") ||
286 scheme.EqualsLiteral("imap") ||
287 scheme.EqualsLiteral("news") ||
288 scheme.EqualsLiteral("mailbox") ||
289 scheme.EqualsLiteral("moz-anno") ||
290 scheme.EqualsLiteral("view-source") ||
291 scheme.EqualsLiteral("chrome") ||
292 scheme.EqualsLiteral("resource") ||
293 scheme.EqualsLiteral("data") ||
294 scheme.EqualsLiteral("wyciwyg") ||
295 scheme.EqualsLiteral("javascript") ||
296 scheme.EqualsLiteral("blob")) {
297 *canAdd = false;
298 return NS_OK;
299 }
300 *canAdd = true;
301 return NS_OK;
302 }