Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/Assertions.h"
9 #include "jsapi.h"
11 #include "nsCollationCID.h"
12 #include "nsJSUtils.h"
13 #include "nsICharsetConverterManager.h"
14 #include "nsIPlatformCharset.h"
15 #include "nsILocaleService.h"
16 #include "nsICollation.h"
17 #include "nsUnicharUtils.h"
18 #include "nsComponentManagerUtils.h"
19 #include "nsServiceManagerUtils.h"
21 #include "xpcpublic.h"
23 using namespace JS;
25 /**
26 * JS locale callbacks implemented by XPCOM modules. These are theoretically
27 * safe for use on multiple threads. Unfortunately, the intl code underlying
28 * these XPCOM modules doesn't yet support this, so in practice
29 * XPCLocaleCallbacks are limited to the main thread.
30 */
31 struct XPCLocaleCallbacks : public JSLocaleCallbacks
32 {
33 XPCLocaleCallbacks()
34 #ifdef DEBUG
35 : mThread(PR_GetCurrentThread())
36 #endif
37 {
38 MOZ_COUNT_CTOR(XPCLocaleCallbacks);
40 localeToUpperCase = LocaleToUpperCase;
41 localeToLowerCase = LocaleToLowerCase;
42 localeCompare = LocaleCompare;
43 localeToUnicode = LocaleToUnicode;
44 localeGetErrorMessage = nullptr;
45 }
47 ~XPCLocaleCallbacks()
48 {
49 AssertThreadSafety();
50 MOZ_COUNT_DTOR(XPCLocaleCallbacks);
51 }
53 /**
54 * Return the XPCLocaleCallbacks that's hidden away in |rt|. (This impl uses
55 * the locale callbacks struct to store away its per-runtime data.)
56 */
57 static XPCLocaleCallbacks*
58 This(JSRuntime *rt)
59 {
60 // Locale information for |rt| was associated using xpc_LocalizeRuntime;
61 // assert and double-check this.
62 JSLocaleCallbacks* lc = JS_GetLocaleCallbacks(rt);
63 MOZ_ASSERT(lc);
64 MOZ_ASSERT(lc->localeToUpperCase == LocaleToUpperCase);
65 MOZ_ASSERT(lc->localeToLowerCase == LocaleToLowerCase);
66 MOZ_ASSERT(lc->localeCompare == LocaleCompare);
67 MOZ_ASSERT(lc->localeToUnicode == LocaleToUnicode);
69 XPCLocaleCallbacks* ths = static_cast<XPCLocaleCallbacks*>(lc);
70 ths->AssertThreadSafety();
71 return ths;
72 }
74 static bool
75 LocaleToUpperCase(JSContext *cx, HandleString src, MutableHandleValue rval)
76 {
77 return ChangeCase(cx, src, rval, ToUpperCase);
78 }
80 static bool
81 LocaleToLowerCase(JSContext *cx, HandleString src, MutableHandleValue rval)
82 {
83 return ChangeCase(cx, src, rval, ToLowerCase);
84 }
86 static bool
87 LocaleToUnicode(JSContext* cx, const char* src, MutableHandleValue rval)
88 {
89 return This(JS_GetRuntime(cx))->ToUnicode(cx, src, rval);
90 }
92 static bool
93 LocaleCompare(JSContext *cx, HandleString src1, HandleString src2, MutableHandleValue rval)
94 {
95 return This(JS_GetRuntime(cx))->Compare(cx, src1, src2, rval);
96 }
98 private:
99 static bool
100 ChangeCase(JSContext* cx, HandleString src, MutableHandleValue rval,
101 void(*changeCaseFnc)(const nsAString&, nsAString&))
102 {
103 nsDependentJSString depStr;
104 if (!depStr.init(cx, src)) {
105 return false;
106 }
108 nsAutoString result;
109 changeCaseFnc(depStr, result);
111 JSString *ucstr =
112 JS_NewUCStringCopyN(cx, result.get(), result.Length());
113 if (!ucstr) {
114 return false;
115 }
117 rval.set(STRING_TO_JSVAL(ucstr));
118 return true;
119 }
121 bool
122 Compare(JSContext *cx, HandleString src1, HandleString src2, MutableHandleValue rval)
123 {
124 nsresult rv;
126 if (!mCollation) {
127 nsCOMPtr<nsILocaleService> localeService =
128 do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
130 if (NS_SUCCEEDED(rv)) {
131 nsCOMPtr<nsILocale> locale;
132 rv = localeService->GetApplicationLocale(getter_AddRefs(locale));
134 if (NS_SUCCEEDED(rv)) {
135 nsCOMPtr<nsICollationFactory> colFactory =
136 do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID, &rv);
138 if (NS_SUCCEEDED(rv)) {
139 rv = colFactory->CreateCollation(locale, getter_AddRefs(mCollation));
140 }
141 }
142 }
144 if (NS_FAILED(rv)) {
145 xpc::Throw(cx, rv);
146 return false;
147 }
148 }
150 nsDependentJSString depStr1, depStr2;
151 if (!depStr1.init(cx, src1) || !depStr2.init(cx, src2)) {
152 return false;
153 }
155 int32_t result;
156 rv = mCollation->CompareString(nsICollation::kCollationStrengthDefault,
157 depStr1, depStr2, &result);
159 if (NS_FAILED(rv)) {
160 xpc::Throw(cx, rv);
161 return false;
162 }
164 rval.set(INT_TO_JSVAL(result));
165 return true;
166 }
168 bool
169 ToUnicode(JSContext* cx, const char* src, MutableHandleValue rval)
170 {
171 nsresult rv;
173 if (!mDecoder) {
174 // use app default locale
175 nsCOMPtr<nsILocaleService> localeService =
176 do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
177 if (NS_SUCCEEDED(rv)) {
178 nsCOMPtr<nsILocale> appLocale;
179 rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
180 if (NS_SUCCEEDED(rv)) {
181 nsAutoString localeStr;
182 rv = appLocale->
183 GetCategory(NS_LITERAL_STRING(NSILOCALE_TIME), localeStr);
184 MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to get app locale info");
186 nsCOMPtr<nsIPlatformCharset> platformCharset =
187 do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
189 if (NS_SUCCEEDED(rv)) {
190 nsAutoCString charset;
191 rv = platformCharset->GetDefaultCharsetForLocale(localeStr, charset);
192 if (NS_SUCCEEDED(rv)) {
193 // get/create unicode decoder for charset
194 nsCOMPtr<nsICharsetConverterManager> ccm =
195 do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
196 if (NS_SUCCEEDED(rv))
197 ccm->GetUnicodeDecoder(charset.get(), getter_AddRefs(mDecoder));
198 }
199 }
200 }
201 }
202 }
204 int32_t srcLength = strlen(src);
206 if (mDecoder) {
207 int32_t unicharLength = srcLength;
208 char16_t *unichars =
209 (char16_t *)JS_malloc(cx, (srcLength + 1) * sizeof(char16_t));
210 if (unichars) {
211 rv = mDecoder->Convert(src, &srcLength, unichars, &unicharLength);
212 if (NS_SUCCEEDED(rv)) {
213 // terminate the returned string
214 unichars[unicharLength] = 0;
216 // nsIUnicodeDecoder::Convert may use fewer than srcLength PRUnichars
217 if (unicharLength + 1 < srcLength + 1) {
218 char16_t *shrunkUnichars =
219 (char16_t *)JS_realloc(cx, unichars,
220 (unicharLength + 1) * sizeof(char16_t));
221 if (shrunkUnichars)
222 unichars = shrunkUnichars;
223 }
224 JSString *str = JS_NewUCString(cx, reinterpret_cast<jschar*>(unichars), unicharLength);
225 if (str) {
226 rval.setString(str);
227 return true;
228 }
229 }
230 JS_free(cx, unichars);
231 }
232 }
234 xpc::Throw(cx, NS_ERROR_OUT_OF_MEMORY);
235 return false;
236 }
238 void AssertThreadSafety()
239 {
240 MOZ_ASSERT(mThread == PR_GetCurrentThread(),
241 "XPCLocaleCallbacks used unsafely!");
242 }
244 nsCOMPtr<nsICollation> mCollation;
245 nsCOMPtr<nsIUnicodeDecoder> mDecoder;
246 #ifdef DEBUG
247 PRThread* mThread;
248 #endif
249 };
251 bool
252 xpc_LocalizeRuntime(JSRuntime *rt)
253 {
254 JS_SetLocaleCallbacks(rt, new XPCLocaleCallbacks());
256 // Set the default locale.
257 nsCOMPtr<nsILocaleService> localeService =
258 do_GetService(NS_LOCALESERVICE_CONTRACTID);
259 if (!localeService)
260 return false;
262 nsCOMPtr<nsILocale> appLocale;
263 nsresult rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
264 if (NS_FAILED(rv))
265 return false;
267 nsAutoString localeStr;
268 rv = appLocale->GetCategory(NS_LITERAL_STRING(NSILOCALE_TIME), localeStr);
269 MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to get app locale info");
270 NS_LossyConvertUTF16toASCII locale(localeStr);
272 return !!JS_SetDefaultLocale(rt, locale.get());
273 }
275 void
276 xpc_DelocalizeRuntime(JSRuntime *rt)
277 {
278 XPCLocaleCallbacks* lc = XPCLocaleCallbacks::This(rt);
279 JS_SetLocaleCallbacks(rt, nullptr);
280 delete lc;
281 }