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.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ |
michael@0 | 2 | /* vim: set ts=2 sw=2 et tw=79: */ |
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 file, |
michael@0 | 5 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | /** |
michael@0 | 8 | * Conversions from jsval to primitive values |
michael@0 | 9 | */ |
michael@0 | 10 | |
michael@0 | 11 | #ifndef mozilla_dom_PrimitiveConversions_h |
michael@0 | 12 | #define mozilla_dom_PrimitiveConversions_h |
michael@0 | 13 | |
michael@0 | 14 | #include <limits> |
michael@0 | 15 | #include <math.h> |
michael@0 | 16 | #include <stdint.h> |
michael@0 | 17 | |
michael@0 | 18 | #include "jsapi.h" |
michael@0 | 19 | #include "mozilla/Assertions.h" |
michael@0 | 20 | #include "mozilla/ErrorResult.h" |
michael@0 | 21 | #include "mozilla/FloatingPoint.h" |
michael@0 | 22 | |
michael@0 | 23 | namespace mozilla { |
michael@0 | 24 | namespace dom { |
michael@0 | 25 | |
michael@0 | 26 | template<typename T> |
michael@0 | 27 | struct TypeName { |
michael@0 | 28 | }; |
michael@0 | 29 | |
michael@0 | 30 | template<> |
michael@0 | 31 | struct TypeName<int8_t> { |
michael@0 | 32 | static const char* value() { |
michael@0 | 33 | return "byte"; |
michael@0 | 34 | } |
michael@0 | 35 | }; |
michael@0 | 36 | template<> |
michael@0 | 37 | struct TypeName<uint8_t> { |
michael@0 | 38 | static const char* value() { |
michael@0 | 39 | return "octet"; |
michael@0 | 40 | } |
michael@0 | 41 | }; |
michael@0 | 42 | template<> |
michael@0 | 43 | struct TypeName<int16_t> { |
michael@0 | 44 | static const char* value() { |
michael@0 | 45 | return "short"; |
michael@0 | 46 | } |
michael@0 | 47 | }; |
michael@0 | 48 | template<> |
michael@0 | 49 | struct TypeName<uint16_t> { |
michael@0 | 50 | static const char* value() { |
michael@0 | 51 | return "unsigned short"; |
michael@0 | 52 | } |
michael@0 | 53 | }; |
michael@0 | 54 | template<> |
michael@0 | 55 | struct TypeName<int32_t> { |
michael@0 | 56 | static const char* value() { |
michael@0 | 57 | return "long"; |
michael@0 | 58 | } |
michael@0 | 59 | }; |
michael@0 | 60 | template<> |
michael@0 | 61 | struct TypeName<uint32_t> { |
michael@0 | 62 | static const char* value() { |
michael@0 | 63 | return "unsigned long"; |
michael@0 | 64 | } |
michael@0 | 65 | }; |
michael@0 | 66 | template<> |
michael@0 | 67 | struct TypeName<int64_t> { |
michael@0 | 68 | static const char* value() { |
michael@0 | 69 | return "long long"; |
michael@0 | 70 | } |
michael@0 | 71 | }; |
michael@0 | 72 | template<> |
michael@0 | 73 | struct TypeName<uint64_t> { |
michael@0 | 74 | static const char* value() { |
michael@0 | 75 | return "unsigned long long"; |
michael@0 | 76 | } |
michael@0 | 77 | }; |
michael@0 | 78 | |
michael@0 | 79 | |
michael@0 | 80 | enum ConversionBehavior { |
michael@0 | 81 | eDefault, |
michael@0 | 82 | eEnforceRange, |
michael@0 | 83 | eClamp |
michael@0 | 84 | }; |
michael@0 | 85 | |
michael@0 | 86 | template<typename T, ConversionBehavior B> |
michael@0 | 87 | struct PrimitiveConversionTraits { |
michael@0 | 88 | }; |
michael@0 | 89 | |
michael@0 | 90 | template<typename T> |
michael@0 | 91 | struct DisallowedConversion { |
michael@0 | 92 | typedef int jstype; |
michael@0 | 93 | typedef int intermediateType; |
michael@0 | 94 | |
michael@0 | 95 | private: |
michael@0 | 96 | static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v, |
michael@0 | 97 | jstype* retval) { |
michael@0 | 98 | MOZ_CRASH("This should never be instantiated!"); |
michael@0 | 99 | } |
michael@0 | 100 | }; |
michael@0 | 101 | |
michael@0 | 102 | struct PrimitiveConversionTraits_smallInt { |
michael@0 | 103 | // The output of JS::ToInt32 is determined as follows: |
michael@0 | 104 | // 1) The value is converted to a double |
michael@0 | 105 | // 2) Anything that's not a finite double returns 0 |
michael@0 | 106 | // 3) The double is rounded towards zero to the nearest integer |
michael@0 | 107 | // 4) The resulting integer is reduced mod 2^32. The output of this |
michael@0 | 108 | // operation is an integer in the range [0, 2^32). |
michael@0 | 109 | // 5) If the resulting number is >= 2^31, 2^32 is subtracted from it. |
michael@0 | 110 | // |
michael@0 | 111 | // The result of all this is a number in the range [-2^31, 2^31) |
michael@0 | 112 | // |
michael@0 | 113 | // WebIDL conversions for the 8-bit, 16-bit, and 32-bit integer types |
michael@0 | 114 | // are defined in the same way, except that step 4 uses reduction mod |
michael@0 | 115 | // 2^8 and 2^16 for the 8-bit and 16-bit types respectively, and step 5 |
michael@0 | 116 | // is only done for the signed types. |
michael@0 | 117 | // |
michael@0 | 118 | // C/C++ define integer conversion semantics to unsigned types as taking |
michael@0 | 119 | // your input integer mod (1 + largest value representable in the |
michael@0 | 120 | // unsigned type). Since 2^32 is zero mod 2^8, 2^16, and 2^32, |
michael@0 | 121 | // converting to the unsigned int of the relevant width will correctly |
michael@0 | 122 | // perform step 4; in particular, the 2^32 possibly subtracted in step 5 |
michael@0 | 123 | // will become 0. |
michael@0 | 124 | // |
michael@0 | 125 | // Once we have step 4 done, we're just going to assume 2s-complement |
michael@0 | 126 | // representation and cast directly to the type we really want. |
michael@0 | 127 | // |
michael@0 | 128 | // So we can cast directly for all unsigned types and for int32_t; for |
michael@0 | 129 | // the smaller-width signed types we need to cast through the |
michael@0 | 130 | // corresponding unsigned type. |
michael@0 | 131 | typedef int32_t jstype; |
michael@0 | 132 | typedef int32_t intermediateType; |
michael@0 | 133 | static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v, |
michael@0 | 134 | jstype* retval) { |
michael@0 | 135 | return JS::ToInt32(cx, v, retval); |
michael@0 | 136 | } |
michael@0 | 137 | }; |
michael@0 | 138 | template<> |
michael@0 | 139 | struct PrimitiveConversionTraits<int8_t, eDefault> : PrimitiveConversionTraits_smallInt { |
michael@0 | 140 | typedef uint8_t intermediateType; |
michael@0 | 141 | }; |
michael@0 | 142 | template<> |
michael@0 | 143 | struct PrimitiveConversionTraits<uint8_t, eDefault> : PrimitiveConversionTraits_smallInt { |
michael@0 | 144 | }; |
michael@0 | 145 | template<> |
michael@0 | 146 | struct PrimitiveConversionTraits<int16_t, eDefault> : PrimitiveConversionTraits_smallInt { |
michael@0 | 147 | typedef uint16_t intermediateType; |
michael@0 | 148 | }; |
michael@0 | 149 | template<> |
michael@0 | 150 | struct PrimitiveConversionTraits<uint16_t, eDefault> : PrimitiveConversionTraits_smallInt { |
michael@0 | 151 | }; |
michael@0 | 152 | template<> |
michael@0 | 153 | struct PrimitiveConversionTraits<int32_t, eDefault> : PrimitiveConversionTraits_smallInt { |
michael@0 | 154 | }; |
michael@0 | 155 | template<> |
michael@0 | 156 | struct PrimitiveConversionTraits<uint32_t, eDefault> : PrimitiveConversionTraits_smallInt { |
michael@0 | 157 | }; |
michael@0 | 158 | |
michael@0 | 159 | template<> |
michael@0 | 160 | struct PrimitiveConversionTraits<int64_t, eDefault> { |
michael@0 | 161 | typedef int64_t jstype; |
michael@0 | 162 | typedef int64_t intermediateType; |
michael@0 | 163 | static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v, |
michael@0 | 164 | jstype* retval) { |
michael@0 | 165 | return JS::ToInt64(cx, v, retval); |
michael@0 | 166 | } |
michael@0 | 167 | }; |
michael@0 | 168 | |
michael@0 | 169 | template<> |
michael@0 | 170 | struct PrimitiveConversionTraits<uint64_t, eDefault> { |
michael@0 | 171 | typedef uint64_t jstype; |
michael@0 | 172 | typedef uint64_t intermediateType; |
michael@0 | 173 | static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v, |
michael@0 | 174 | jstype* retval) { |
michael@0 | 175 | return JS::ToUint64(cx, v, retval); |
michael@0 | 176 | } |
michael@0 | 177 | }; |
michael@0 | 178 | |
michael@0 | 179 | template<typename T> |
michael@0 | 180 | struct PrimitiveConversionTraits_Limits { |
michael@0 | 181 | static inline T min() { |
michael@0 | 182 | return std::numeric_limits<T>::min(); |
michael@0 | 183 | } |
michael@0 | 184 | static inline T max() { |
michael@0 | 185 | return std::numeric_limits<T>::max(); |
michael@0 | 186 | } |
michael@0 | 187 | }; |
michael@0 | 188 | |
michael@0 | 189 | template<> |
michael@0 | 190 | struct PrimitiveConversionTraits_Limits<int64_t> { |
michael@0 | 191 | static inline int64_t min() { |
michael@0 | 192 | return -(1LL << 53); |
michael@0 | 193 | } |
michael@0 | 194 | static inline int64_t max() { |
michael@0 | 195 | return (1LL << 53); |
michael@0 | 196 | } |
michael@0 | 197 | }; |
michael@0 | 198 | |
michael@0 | 199 | template<> |
michael@0 | 200 | struct PrimitiveConversionTraits_Limits<uint64_t> { |
michael@0 | 201 | static inline uint64_t min() { |
michael@0 | 202 | return 0; |
michael@0 | 203 | } |
michael@0 | 204 | static inline uint64_t max() { |
michael@0 | 205 | return (1LL << 53); |
michael@0 | 206 | } |
michael@0 | 207 | }; |
michael@0 | 208 | |
michael@0 | 209 | template<typename T, bool (*Enforce)(JSContext* cx, const double& d, T* retval)> |
michael@0 | 210 | struct PrimitiveConversionTraits_ToCheckedIntHelper { |
michael@0 | 211 | typedef T jstype; |
michael@0 | 212 | typedef T intermediateType; |
michael@0 | 213 | |
michael@0 | 214 | static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v, |
michael@0 | 215 | jstype* retval) { |
michael@0 | 216 | double intermediate; |
michael@0 | 217 | if (!JS::ToNumber(cx, v, &intermediate)) { |
michael@0 | 218 | return false; |
michael@0 | 219 | } |
michael@0 | 220 | |
michael@0 | 221 | return Enforce(cx, intermediate, retval); |
michael@0 | 222 | } |
michael@0 | 223 | }; |
michael@0 | 224 | |
michael@0 | 225 | template<typename T> |
michael@0 | 226 | inline bool |
michael@0 | 227 | PrimitiveConversionTraits_EnforceRange(JSContext* cx, const double& d, T* retval) |
michael@0 | 228 | { |
michael@0 | 229 | static_assert(std::numeric_limits<T>::is_integer, |
michael@0 | 230 | "This can only be applied to integers!"); |
michael@0 | 231 | |
michael@0 | 232 | if (!mozilla::IsFinite(d)) { |
michael@0 | 233 | return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_NON_FINITE, TypeName<T>::value()); |
michael@0 | 234 | } |
michael@0 | 235 | |
michael@0 | 236 | bool neg = (d < 0); |
michael@0 | 237 | double rounded = floor(neg ? -d : d); |
michael@0 | 238 | rounded = neg ? -rounded : rounded; |
michael@0 | 239 | if (rounded < PrimitiveConversionTraits_Limits<T>::min() || |
michael@0 | 240 | rounded > PrimitiveConversionTraits_Limits<T>::max()) { |
michael@0 | 241 | return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_OUT_OF_RANGE, TypeName<T>::value()); |
michael@0 | 242 | } |
michael@0 | 243 | |
michael@0 | 244 | *retval = static_cast<T>(rounded); |
michael@0 | 245 | return true; |
michael@0 | 246 | } |
michael@0 | 247 | |
michael@0 | 248 | template<typename T> |
michael@0 | 249 | struct PrimitiveConversionTraits<T, eEnforceRange> : |
michael@0 | 250 | public PrimitiveConversionTraits_ToCheckedIntHelper<T, PrimitiveConversionTraits_EnforceRange<T> > { |
michael@0 | 251 | }; |
michael@0 | 252 | |
michael@0 | 253 | template<typename T> |
michael@0 | 254 | inline bool |
michael@0 | 255 | PrimitiveConversionTraits_Clamp(JSContext* cx, const double& d, T* retval) |
michael@0 | 256 | { |
michael@0 | 257 | static_assert(std::numeric_limits<T>::is_integer, |
michael@0 | 258 | "This can only be applied to integers!"); |
michael@0 | 259 | |
michael@0 | 260 | if (mozilla::IsNaN(d)) { |
michael@0 | 261 | *retval = 0; |
michael@0 | 262 | return true; |
michael@0 | 263 | } |
michael@0 | 264 | if (d >= PrimitiveConversionTraits_Limits<T>::max()) { |
michael@0 | 265 | *retval = PrimitiveConversionTraits_Limits<T>::max(); |
michael@0 | 266 | return true; |
michael@0 | 267 | } |
michael@0 | 268 | if (d <= PrimitiveConversionTraits_Limits<T>::min()) { |
michael@0 | 269 | *retval = PrimitiveConversionTraits_Limits<T>::min(); |
michael@0 | 270 | return true; |
michael@0 | 271 | } |
michael@0 | 272 | |
michael@0 | 273 | MOZ_ASSERT(mozilla::IsFinite(d)); |
michael@0 | 274 | |
michael@0 | 275 | // Banker's rounding (round ties towards even). |
michael@0 | 276 | // We move away from 0 by 0.5f and then truncate. That gets us the right |
michael@0 | 277 | // answer for any starting value except plus or minus N.5. With a starting |
michael@0 | 278 | // value of that form, we now have plus or minus N+1. If N is odd, this is |
michael@0 | 279 | // the correct result. If N is even, plus or minus N is the correct result. |
michael@0 | 280 | double toTruncate = (d < 0) ? d - 0.5 : d + 0.5; |
michael@0 | 281 | |
michael@0 | 282 | T truncated = static_cast<T>(toTruncate); |
michael@0 | 283 | |
michael@0 | 284 | if (truncated == toTruncate) { |
michael@0 | 285 | /* |
michael@0 | 286 | * It was a tie (since moving away from 0 by 0.5 gave us the exact integer |
michael@0 | 287 | * we want). Since we rounded away from 0, we either already have an even |
michael@0 | 288 | * number or we have an odd number but the number we want is one closer to |
michael@0 | 289 | * 0. So just unconditionally masking out the ones bit should do the trick |
michael@0 | 290 | * to get us the value we want. |
michael@0 | 291 | */ |
michael@0 | 292 | truncated &= ~1; |
michael@0 | 293 | } |
michael@0 | 294 | |
michael@0 | 295 | *retval = truncated; |
michael@0 | 296 | return true; |
michael@0 | 297 | } |
michael@0 | 298 | |
michael@0 | 299 | template<typename T> |
michael@0 | 300 | struct PrimitiveConversionTraits<T, eClamp> : |
michael@0 | 301 | public PrimitiveConversionTraits_ToCheckedIntHelper<T, PrimitiveConversionTraits_Clamp<T> > { |
michael@0 | 302 | }; |
michael@0 | 303 | |
michael@0 | 304 | |
michael@0 | 305 | template<ConversionBehavior B> |
michael@0 | 306 | struct PrimitiveConversionTraits<bool, B> : public DisallowedConversion<bool> {}; |
michael@0 | 307 | |
michael@0 | 308 | template<> |
michael@0 | 309 | struct PrimitiveConversionTraits<bool, eDefault> { |
michael@0 | 310 | typedef bool jstype; |
michael@0 | 311 | typedef bool intermediateType; |
michael@0 | 312 | static inline bool converter(JSContext* /* unused */, JS::Handle<JS::Value> v, |
michael@0 | 313 | jstype* retval) { |
michael@0 | 314 | *retval = JS::ToBoolean(v); |
michael@0 | 315 | return true; |
michael@0 | 316 | } |
michael@0 | 317 | }; |
michael@0 | 318 | |
michael@0 | 319 | |
michael@0 | 320 | template<ConversionBehavior B> |
michael@0 | 321 | struct PrimitiveConversionTraits<float, B> : public DisallowedConversion<float> {}; |
michael@0 | 322 | |
michael@0 | 323 | template<ConversionBehavior B> |
michael@0 | 324 | struct PrimitiveConversionTraits<double, B> : public DisallowedConversion<double> {}; |
michael@0 | 325 | |
michael@0 | 326 | struct PrimitiveConversionTraits_float { |
michael@0 | 327 | typedef double jstype; |
michael@0 | 328 | typedef double intermediateType; |
michael@0 | 329 | static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v, |
michael@0 | 330 | jstype* retval) { |
michael@0 | 331 | return JS::ToNumber(cx, v, retval); |
michael@0 | 332 | } |
michael@0 | 333 | }; |
michael@0 | 334 | |
michael@0 | 335 | template<> |
michael@0 | 336 | struct PrimitiveConversionTraits<float, eDefault> : PrimitiveConversionTraits_float { |
michael@0 | 337 | }; |
michael@0 | 338 | template<> |
michael@0 | 339 | struct PrimitiveConversionTraits<double, eDefault> : PrimitiveConversionTraits_float { |
michael@0 | 340 | }; |
michael@0 | 341 | |
michael@0 | 342 | |
michael@0 | 343 | template<typename T, ConversionBehavior B> |
michael@0 | 344 | bool ValueToPrimitive(JSContext* cx, JS::Handle<JS::Value> v, T* retval) |
michael@0 | 345 | { |
michael@0 | 346 | typename PrimitiveConversionTraits<T, B>::jstype t; |
michael@0 | 347 | if (!PrimitiveConversionTraits<T, B>::converter(cx, v, &t)) |
michael@0 | 348 | return false; |
michael@0 | 349 | |
michael@0 | 350 | *retval = static_cast<T>( |
michael@0 | 351 | static_cast<typename PrimitiveConversionTraits<T, B>::intermediateType>(t)); |
michael@0 | 352 | return true; |
michael@0 | 353 | } |
michael@0 | 354 | |
michael@0 | 355 | } // namespace dom |
michael@0 | 356 | } // namespace mozilla |
michael@0 | 357 | |
michael@0 | 358 | #endif /* mozilla_dom_PrimitiveConversions_h */ |