DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (a25f12b76a38)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/Encoding.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/StaticPrefs_network.h"
#include "nsAutoPtr.h"
#include "nsCookie.h"
#include "nsIURLParser.h"
#include "nsURLHelper.h"
#include <stdlib.h>

/******************************************************************************
 * nsCookie:
 * creation helper
 ******************************************************************************/

// This is a counter that keeps track of the last used creation time, each time
// we create a new nsCookie. This is nominally the time (in microseconds) the
// cookie was created, but is guaranteed to be monotonically increasing for
// cookies added at runtime after the database has been read in. This is
// necessary to enforce ordering among cookies whose creation times would
// otherwise overlap, since it's possible two cookies may be created at the same
// time, or that the system clock isn't monotonic.
static int64_t gLastCreationTime;

int64_t nsCookie::GenerateUniqueCreationTime(int64_t aCreationTime) {
  // Check if the creation time given to us is greater than the running maximum
  // (it should always be monotonically increasing).
  if (aCreationTime > gLastCreationTime) {
    gLastCreationTime = aCreationTime;
    return aCreationTime;
  }

  // Make up our own.
  return ++gLastCreationTime;
}

// static
already_AddRefed<nsCookie> nsCookie::Create(
    const nsACString& aName, const nsACString& aValue, const nsACString& aHost,
    const nsACString& aPath, int64_t aExpiry, int64_t aLastAccessed,
    int64_t aCreationTime, bool aIsSession, bool aIsSecure, bool aIsHttpOnly,
    const OriginAttributes& aOriginAttributes, int32_t aSameSite,
    int32_t aRawSameSite) {
  mozilla::net::CookieStruct cookieData(
      nsCString(aName), nsCString(aValue), nsCString(aHost), nsCString(aPath),
      aExpiry, aLastAccessed, aCreationTime, aIsHttpOnly, aIsSession, aIsSecure,
      aSameSite, aRawSameSite);

  return Create(cookieData, aOriginAttributes);
}

already_AddRefed<nsCookie> nsCookie::Create(
    const mozilla::net::CookieStruct& aCookieData,
    const OriginAttributes& aOriginAttributes) {
  RefPtr<nsCookie> cookie = new nsCookie(aCookieData, aOriginAttributes);

  // Ensure mValue contains a valid UTF-8 sequence. Otherwise XPConnect will
  // truncate the string after the first invalid octet.
  UTF_8_ENCODING->DecodeWithoutBOMHandling(aCookieData.value(),
                                           cookie->mData.value());

  // If the creationTime given to us is higher than the running maximum,
  // update our maximum.
  if (cookie->mData.creationTime() > gLastCreationTime) {
    gLastCreationTime = cookie->mData.creationTime();
  }

  // If sameSite is not a sensible value, assume strict
  if (cookie->mData.sameSite() < 0 ||
      cookie->mData.sameSite() > nsICookie::SAMESITE_STRICT) {
    cookie->mData.sameSite() = nsICookie::SAMESITE_STRICT;
  }

  // If rawSameSite is not a sensible value, assume equal to sameSite.
  if (!nsCookie::ValidateRawSame(cookie->mData)) {
    cookie->mData.rawSameSite() = nsICookie::SAMESITE_NONE;
  }

  return cookie.forget();
}

size_t nsCookie::SizeOfIncludingThis(
    mozilla::MallocSizeOf aMallocSizeOf) const {
  return aMallocSizeOf(this) +
         mData.name().SizeOfExcludingThisIfUnshared(MallocSizeOf) +
         mData.value().SizeOfExcludingThisIfUnshared(MallocSizeOf) +
         mData.host().SizeOfExcludingThisIfUnshared(MallocSizeOf) +
         mData.path().SizeOfExcludingThisIfUnshared(MallocSizeOf) +
         mFilePathCache.SizeOfExcludingThisIfUnshared(MallocSizeOf);
}

bool nsCookie::IsStale() const {
  int64_t currentTimeInUsec = PR_Now();

  return currentTimeInUsec - LastAccessed() >
         mozilla::StaticPrefs::network_cookie_staleThreshold() *
             PR_USEC_PER_SEC;
}

/******************************************************************************
 * nsCookie:
 * xpcom impl
 ******************************************************************************/

// xpcom getters
NS_IMETHODIMP nsCookie::GetName(nsACString& aName) {
  aName = Name();
  return NS_OK;
}
NS_IMETHODIMP nsCookie::GetValue(nsACString& aValue) {
  aValue = Value();
  return NS_OK;
}
NS_IMETHODIMP nsCookie::GetHost(nsACString& aHost) {
  aHost = Host();
  return NS_OK;
}
NS_IMETHODIMP nsCookie::GetRawHost(nsACString& aHost) {
  aHost = RawHost();
  return NS_OK;
}
NS_IMETHODIMP nsCookie::GetPath(nsACString& aPath) {
  aPath = Path();
  return NS_OK;
}
NS_IMETHODIMP nsCookie::GetExpiry(int64_t* aExpiry) {
  *aExpiry = Expiry();
  return NS_OK;
}
NS_IMETHODIMP nsCookie::GetIsSession(bool* aIsSession) {
  *aIsSession = IsSession();
  return NS_OK;
}
NS_IMETHODIMP nsCookie::GetIsDomain(bool* aIsDomain) {
  *aIsDomain = IsDomain();
  return NS_OK;
}
NS_IMETHODIMP nsCookie::GetIsSecure(bool* aIsSecure) {
  *aIsSecure = IsSecure();
  return NS_OK;
}
NS_IMETHODIMP nsCookie::GetIsHttpOnly(bool* aHttpOnly) {
  *aHttpOnly = IsHttpOnly();
  return NS_OK;
}
NS_IMETHODIMP nsCookie::GetCreationTime(int64_t* aCreation) {
  *aCreation = CreationTime();
  return NS_OK;
}
NS_IMETHODIMP nsCookie::GetLastAccessed(int64_t* aTime) {
  *aTime = LastAccessed();
  return NS_OK;
}
NS_IMETHODIMP nsCookie::GetSameSite(int32_t* aSameSite) {
  if (mozilla::StaticPrefs::network_cookie_sameSite_laxByDefault()) {
    *aSameSite = SameSite();
  } else {
    *aSameSite = RawSameSite();
  }
  return NS_OK;
}

NS_IMETHODIMP
nsCookie::GetOriginAttributes(JSContext* aCx,
                              JS::MutableHandle<JS::Value> aVal) {
  if (NS_WARN_IF(!ToJSValue(aCx, mOriginAttributes, aVal))) {
    return NS_ERROR_FAILURE;
  }
  return NS_OK;
}

const nsCString& nsCookie::GetFilePath() {
  MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());

  if (Path().IsEmpty()) {
    // If we don't have a path, just return the (empty) file path cache.
    return mFilePathCache;
  }
  if (!mFilePathCache.IsEmpty()) {
    // If we've computed the answer before, just return it.
    return mFilePathCache;
  }

  nsIURLParser* parser = net_GetStdURLParser();
  NS_ENSURE_TRUE(parser, mFilePathCache);

  int32_t pathLen = Path().Length(), filepathLen = 0;
  uint32_t filepathPos = 0;

  nsresult rv = parser->ParsePath(PromiseFlatCString(Path()).get(), pathLen,
                                  &filepathPos, &filepathLen, nullptr,
                                  nullptr,            // don't care about query
                                  nullptr, nullptr);  // don't care about ref
  NS_ENSURE_SUCCESS(rv, mFilePathCache);

  mFilePathCache = Substring(Path(), filepathPos, filepathLen);

  return mFilePathCache;
}

// compatibility method, for use with the legacy nsICookie interface.
// here, expires == 0 denotes a session cookie.
NS_IMETHODIMP
nsCookie::GetExpires(uint64_t* aExpires) {
  if (IsSession()) {
    *aExpires = 0;
  } else {
    *aExpires = Expiry() > 0 ? Expiry() : 1;
  }
  return NS_OK;
}

// static
bool nsCookie::ValidateRawSame(const mozilla::net::CookieStruct& aCookieData) {
  return aCookieData.rawSameSite() == aCookieData.sameSite() ||
         aCookieData.rawSameSite() == nsICookie::SAMESITE_NONE;
}

NS_IMPL_ISUPPORTS(nsCookie, nsICookie)