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 (fddffdeab170)

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
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "xpcprivate.h"
#include "nsString.h"
#include "nsIObjectOutputStream.h"
#include "nsIObjectInputStream.h"
#include "nsJSPrincipals.h"
#include "plstr.h"
#include "nsXPIDLString.h"
#include "nsCOMPtr.h"
#include "nsIServiceManager.h"
#include "nsMemory.h"
#include "nsStringBuffer.h"

#include "mozilla/dom/StructuredCloneTags.h"
// for mozilla::dom::workers::kJSPrincipalsDebugToken
#include "mozilla/dom/workers/Workers.h"
#include "mozilla/ipc/BackgroundUtils.h"

using namespace mozilla;
using namespace mozilla::ipc;

NS_IMETHODIMP_(MozExternalRefCountType)
nsJSPrincipals::AddRef()
{
  MOZ_ASSERT(NS_IsMainThread());
  NS_PRECONDITION(int32_t(refcount) >= 0, "illegal refcnt");
  nsrefcnt count = ++refcount;
  NS_LOG_ADDREF(this, count, "nsJSPrincipals", sizeof(*this));
  return count;
}

NS_IMETHODIMP_(MozExternalRefCountType)
nsJSPrincipals::Release()
{
  MOZ_ASSERT(NS_IsMainThread());
  NS_PRECONDITION(0 != refcount, "dup release");
  nsrefcnt count = --refcount;
  NS_LOG_RELEASE(this, count, "nsJSPrincipals");
  if (count == 0) {
    delete this;
  }

  return count;
}

/* static */ bool
nsJSPrincipals::Subsume(JSPrincipals *jsprin, JSPrincipals *other)
{
    bool result;
    nsresult rv = nsJSPrincipals::get(jsprin)->Subsumes(nsJSPrincipals::get(other), &result);
    return NS_SUCCEEDED(rv) && result;
}

/* static */ void
nsJSPrincipals::Destroy(JSPrincipals *jsprin)
{
    // The JS runtime can call this method during the last GC when
    // nsScriptSecurityManager is destroyed. So we must not assume here that
    // the security manager still exists.

    nsJSPrincipals *nsjsprin = nsJSPrincipals::get(jsprin);

    // We need to destroy the nsIPrincipal. We'll do this by adding
    // to the refcount and calling release

#ifdef NS_BUILD_REFCNT_LOGGING
    // The refcount logging considers AddRef-to-1 to indicate creation,
    // so trick it into thinking it's otherwise, but balance the
    // Release() we do below.
    nsjsprin->refcount++;
    nsjsprin->AddRef();
    nsjsprin->refcount--;
#else
    nsjsprin->refcount++;
#endif
    nsjsprin->Release();
}

#ifdef DEBUG

// Defined here so one can do principals->dump() in the debugger
JS_EXPORT_API(void)
JSPrincipals::dump()
{
    if (debugToken == nsJSPrincipals::DEBUG_TOKEN) {
      nsAutoCString str;
      static_cast<nsJSPrincipals *>(this)->GetScriptLocation(str);
      fprintf(stderr, "nsIPrincipal (%p) = %s\n", static_cast<void*>(this), str.get());
    } else if (debugToken == dom::workers::kJSPrincipalsDebugToken) {
        fprintf(stderr, "Web Worker principal singleton (%p)\n", this);
    } else {
        fprintf(stderr,
                "!!! JSPrincipals (%p) is not nsJSPrincipals instance - bad token: "
                "actual=0x%x expected=0x%x\n",
                this, unsigned(debugToken), unsigned(nsJSPrincipals::DEBUG_TOKEN));
    }
}

#endif

/* static */ bool
nsJSPrincipals::ReadPrincipals(JSContext* aCx, JSStructuredCloneReader* aReader,
                               JSPrincipals** aOutPrincipals)
{
    uint32_t tag;
    uint32_t unused;
    if (!JS_ReadUint32Pair(aReader, &tag, &unused)) {
        return false;
    }

    if (!(tag == SCTAG_DOM_NULL_PRINCIPAL ||
          tag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
          tag == SCTAG_DOM_CONTENT_PRINCIPAL)) {
        xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
        return false;
    }

    return ReadKnownPrincipalType(aCx, aReader, tag, aOutPrincipals);
}

/* static */ bool
nsJSPrincipals::ReadKnownPrincipalType(JSContext* aCx,
                                       JSStructuredCloneReader* aReader,
                                       uint32_t aTag,
                                       JSPrincipals** aOutPrincipals)
{
    MOZ_ASSERT(aTag == SCTAG_DOM_NULL_PRINCIPAL ||
               aTag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
               aTag == SCTAG_DOM_CONTENT_PRINCIPAL);

    if (NS_WARN_IF(!NS_IsMainThread())) {
        xpc::Throw(aCx, NS_ERROR_UNCATCHABLE_EXCEPTION);
        return false;
    }

    PrincipalInfo info;
    if (aTag == SCTAG_DOM_SYSTEM_PRINCIPAL) {
        info = SystemPrincipalInfo();
    } else if (aTag == SCTAG_DOM_NULL_PRINCIPAL) {
        info = NullPrincipalInfo();
    } else {
        uint32_t suffixLength, specLength;
        if (!JS_ReadUint32Pair(aReader, &suffixLength, &specLength)) {
            return false;
        }

        nsAutoCString suffix;
        suffix.SetLength(suffixLength);
        if (!JS_ReadBytes(aReader, suffix.BeginWriting(), suffixLength)) {
            return false;
        }

        nsAutoCString spec;
        spec.SetLength(specLength);
        if (!JS_ReadBytes(aReader, spec.BeginWriting(), specLength)) {
            return false;
        }

        OriginAttributes attrs;
        attrs.PopulateFromSuffix(suffix);
        info = ContentPrincipalInfo(attrs, spec);
    }

    nsresult rv;
    nsCOMPtr<nsIPrincipal> prin = PrincipalInfoToPrincipal(info, &rv);
    if (NS_WARN_IF(NS_FAILED(rv))) {
        xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
        return false;
    }

    *aOutPrincipals = get(prin.forget().take());
    return true;
}

bool
nsJSPrincipals::write(JSContext* aCx, JSStructuredCloneWriter* aWriter)
{
    PrincipalInfo info;
    if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(this, &info)))) {
        xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
        return false;
    }

    if (info.type() == PrincipalInfo::TNullPrincipalInfo) {
        return JS_WriteUint32Pair(aWriter, SCTAG_DOM_NULL_PRINCIPAL, 0);
    }
    if (info.type() == PrincipalInfo::TSystemPrincipalInfo) {
        return JS_WriteUint32Pair(aWriter, SCTAG_DOM_SYSTEM_PRINCIPAL, 0);
    }

    MOZ_ASSERT(info.type() == PrincipalInfo::TContentPrincipalInfo);
    const ContentPrincipalInfo& cInfo = info;
    nsAutoCString suffix;
    cInfo.attrs().CreateSuffix(suffix);
    return JS_WriteUint32Pair(aWriter, SCTAG_DOM_CONTENT_PRINCIPAL, 0) &&
           JS_WriteUint32Pair(aWriter, suffix.Length(), cInfo.spec().Length()) &&
           JS_WriteBytes(aWriter, suffix.get(), suffix.Length()) &&
           JS_WriteBytes(aWriter, cInfo.spec().get(), cInfo.spec().Length());
}