js/xpconnect/src/XPCThrower.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/xpconnect/src/XPCThrower.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,173 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=99: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* Code for throwing errors into JavaScript. */
    1.11 +
    1.12 +#include "xpcprivate.h"
    1.13 +#include "XPCWrapper.h"
    1.14 +#include "jsprf.h"
    1.15 +#include "mozilla/dom/BindingUtils.h"
    1.16 +#include "mozilla/dom/Exceptions.h"
    1.17 +
    1.18 +using namespace mozilla;
    1.19 +using namespace mozilla::dom;
    1.20 +
    1.21 +bool XPCThrower::sVerbose = true;
    1.22 +
    1.23 +// static
    1.24 +void
    1.25 +XPCThrower::Throw(nsresult rv, JSContext* cx)
    1.26 +{
    1.27 +    const char* format;
    1.28 +    if (JS_IsExceptionPending(cx))
    1.29 +        return;
    1.30 +    if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format))
    1.31 +        format = "";
    1.32 +    dom::Throw(cx, rv, format);
    1.33 +}
    1.34 +
    1.35 +namespace xpc {
    1.36 +
    1.37 +bool
    1.38 +Throw(JSContext *cx, nsresult rv)
    1.39 +{
    1.40 +    XPCThrower::Throw(rv, cx);
    1.41 +    return false;
    1.42 +}
    1.43 +
    1.44 +} // namespace xpc
    1.45 +
    1.46 +/*
    1.47 + * If there has already been an exception thrown, see if we're throwing the
    1.48 + * same sort of exception, and if we are, don't clobber the old one. ccx
    1.49 + * should be the current call context.
    1.50 + */
    1.51 +// static
    1.52 +bool
    1.53 +XPCThrower::CheckForPendingException(nsresult result, JSContext *cx)
    1.54 +{
    1.55 +    nsCOMPtr<nsIException> e = XPCJSRuntime::Get()->GetPendingException();
    1.56 +    if (!e)
    1.57 +        return false;
    1.58 +    XPCJSRuntime::Get()->SetPendingException(nullptr);
    1.59 +
    1.60 +    nsresult e_result;
    1.61 +    if (NS_FAILED(e->GetResult(&e_result)) || e_result != result)
    1.62 +        return false;
    1.63 +
    1.64 +    if (!ThrowExceptionObject(cx, e))
    1.65 +        JS_ReportOutOfMemory(cx);
    1.66 +    return true;
    1.67 +}
    1.68 +
    1.69 +// static
    1.70 +void
    1.71 +XPCThrower::Throw(nsresult rv, XPCCallContext& ccx)
    1.72 +{
    1.73 +    char* sz;
    1.74 +    const char* format;
    1.75 +
    1.76 +    if (CheckForPendingException(rv, ccx))
    1.77 +        return;
    1.78 +
    1.79 +    if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format))
    1.80 +        format = "";
    1.81 +
    1.82 +    sz = (char*) format;
    1.83 +
    1.84 +    if (sz && sVerbose)
    1.85 +        Verbosify(ccx, &sz, false);
    1.86 +
    1.87 +    dom::Throw(ccx, rv, sz);
    1.88 +
    1.89 +    if (sz && sz != format)
    1.90 +        JS_smprintf_free(sz);
    1.91 +}
    1.92 +
    1.93 +
    1.94 +// static
    1.95 +void
    1.96 +XPCThrower::ThrowBadResult(nsresult rv, nsresult result, XPCCallContext& ccx)
    1.97 +{
    1.98 +    char* sz;
    1.99 +    const char* format;
   1.100 +    const char* name;
   1.101 +
   1.102 +    /*
   1.103 +    *  If there is a pending exception when the native call returns and
   1.104 +    *  it has the same error result as returned by the native call, then
   1.105 +    *  the native call may be passing through an error from a previous JS
   1.106 +    *  call. So we'll just throw that exception into our JS.
   1.107 +    */
   1.108 +
   1.109 +    if (CheckForPendingException(result, ccx))
   1.110 +        return;
   1.111 +
   1.112 +    // else...
   1.113 +
   1.114 +    if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format) || !format)
   1.115 +        format = "";
   1.116 +
   1.117 +    if (nsXPCException::NameAndFormatForNSResult(result, &name, nullptr) && name)
   1.118 +        sz = JS_smprintf("%s 0x%x (%s)", format, result, name);
   1.119 +    else
   1.120 +        sz = JS_smprintf("%s 0x%x", format, result);
   1.121 +
   1.122 +    if (sz && sVerbose)
   1.123 +        Verbosify(ccx, &sz, true);
   1.124 +
   1.125 +    dom::Throw(ccx, result, sz);
   1.126 +
   1.127 +    if (sz)
   1.128 +        JS_smprintf_free(sz);
   1.129 +}
   1.130 +
   1.131 +// static
   1.132 +void
   1.133 +XPCThrower::ThrowBadParam(nsresult rv, unsigned paramNum, XPCCallContext& ccx)
   1.134 +{
   1.135 +    char* sz;
   1.136 +    const char* format;
   1.137 +
   1.138 +    if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format))
   1.139 +        format = "";
   1.140 +
   1.141 +    sz = JS_smprintf("%s arg %d", format, paramNum);
   1.142 +
   1.143 +    if (sz && sVerbose)
   1.144 +        Verbosify(ccx, &sz, true);
   1.145 +
   1.146 +    dom::Throw(ccx, rv, sz);
   1.147 +
   1.148 +    if (sz)
   1.149 +        JS_smprintf_free(sz);
   1.150 +}
   1.151 +
   1.152 +
   1.153 +// static
   1.154 +void
   1.155 +XPCThrower::Verbosify(XPCCallContext& ccx,
   1.156 +                      char** psz, bool own)
   1.157 +{
   1.158 +    char* sz = nullptr;
   1.159 +
   1.160 +    if (ccx.HasInterfaceAndMember()) {
   1.161 +        XPCNativeInterface* iface = ccx.GetInterface();
   1.162 +        jsid id = ccx.GetMember()->GetName();
   1.163 +        JSAutoByteString bytes;
   1.164 +        const char *name = JSID_IS_VOID(id) ? "Unknown" : bytes.encodeLatin1(ccx, JSID_TO_STRING(id));
   1.165 +        if (!name) {
   1.166 +            name = "";
   1.167 +        }
   1.168 +        sz = JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name);
   1.169 +    }
   1.170 +
   1.171 +    if (sz) {
   1.172 +        if (own)
   1.173 +            JS_smprintf_free(*psz);
   1.174 +        *psz = sz;
   1.175 +    }
   1.176 +}

mercurial