js/xpconnect/src/XPCLocale.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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.

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

mercurial