1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/src/jsurl/nsJSProtocolHandler.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1384 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim: set ts=4 sw=4 et tw=78: */ 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 +#include "nsCOMPtr.h" 1.11 +#include "nsAutoPtr.h" 1.12 +#include "jsapi.h" 1.13 +#include "jswrapper.h" 1.14 +#include "nsCRT.h" 1.15 +#include "nsError.h" 1.16 +#include "nsXPIDLString.h" 1.17 +#include "nsReadableUtils.h" 1.18 +#include "nsJSProtocolHandler.h" 1.19 +#include "nsStringStream.h" 1.20 +#include "nsNetUtil.h" 1.21 + 1.22 +#include "nsIComponentManager.h" 1.23 +#include "nsIServiceManager.h" 1.24 +#include "nsIURI.h" 1.25 +#include "nsIScriptContext.h" 1.26 +#include "nsIScriptGlobalObject.h" 1.27 +#include "nsIPrincipal.h" 1.28 +#include "nsIScriptSecurityManager.h" 1.29 +#include "nsIInterfaceRequestor.h" 1.30 +#include "nsIInterfaceRequestorUtils.h" 1.31 +#include "nsIWindowMediator.h" 1.32 +#include "nsPIDOMWindow.h" 1.33 +#include "nsIConsoleService.h" 1.34 +#include "nsXPIDLString.h" 1.35 +#include "prprf.h" 1.36 +#include "nsEscape.h" 1.37 +#include "nsIWebNavigation.h" 1.38 +#include "nsIDocShell.h" 1.39 +#include "nsIContentViewer.h" 1.40 +#include "nsIXPConnect.h" 1.41 +#include "nsContentUtils.h" 1.42 +#include "nsCxPusher.h" 1.43 +#include "nsJSUtils.h" 1.44 +#include "nsThreadUtils.h" 1.45 +#include "nsIScriptChannel.h" 1.46 +#include "nsIDocument.h" 1.47 +#include "nsIObjectInputStream.h" 1.48 +#include "nsIObjectOutputStream.h" 1.49 +#include "nsIWritablePropertyBag2.h" 1.50 +#include "nsIContentSecurityPolicy.h" 1.51 +#include "nsSandboxFlags.h" 1.52 +#include "mozilla/dom/ScriptSettings.h" 1.53 + 1.54 +using mozilla::dom::AutoEntryScript; 1.55 + 1.56 +static NS_DEFINE_CID(kJSURICID, NS_JSURI_CID); 1.57 + 1.58 +class nsJSThunk : public nsIInputStream 1.59 +{ 1.60 +public: 1.61 + nsJSThunk(); 1.62 + 1.63 + NS_DECL_THREADSAFE_ISUPPORTS 1.64 + NS_FORWARD_SAFE_NSIINPUTSTREAM(mInnerStream) 1.65 + 1.66 + nsresult Init(nsIURI* uri); 1.67 + nsresult EvaluateScript(nsIChannel *aChannel, 1.68 + PopupControlState aPopupState, 1.69 + uint32_t aExecutionPolicy, 1.70 + nsPIDOMWindow *aOriginalInnerWindow); 1.71 + 1.72 +protected: 1.73 + virtual ~nsJSThunk(); 1.74 + 1.75 + nsCOMPtr<nsIInputStream> mInnerStream; 1.76 + nsCString mScript; 1.77 + nsCString mURL; 1.78 +}; 1.79 + 1.80 +// 1.81 +// nsISupports implementation... 1.82 +// 1.83 +NS_IMPL_ISUPPORTS(nsJSThunk, nsIInputStream) 1.84 + 1.85 + 1.86 +nsJSThunk::nsJSThunk() 1.87 +{ 1.88 +} 1.89 + 1.90 +nsJSThunk::~nsJSThunk() 1.91 +{ 1.92 +} 1.93 + 1.94 +nsresult nsJSThunk::Init(nsIURI* uri) 1.95 +{ 1.96 + NS_ENSURE_ARG_POINTER(uri); 1.97 + 1.98 + // Get the script string to evaluate... 1.99 + nsresult rv = uri->GetPath(mScript); 1.100 + if (NS_FAILED(rv)) return rv; 1.101 + 1.102 + // Get the url. 1.103 + rv = uri->GetSpec(mURL); 1.104 + if (NS_FAILED(rv)) return rv; 1.105 + 1.106 + return NS_OK; 1.107 +} 1.108 + 1.109 +static bool 1.110 +IsISO88591(const nsString& aString) 1.111 +{ 1.112 + for (nsString::const_char_iterator c = aString.BeginReading(), 1.113 + c_end = aString.EndReading(); 1.114 + c < c_end; ++c) { 1.115 + if (*c > 255) 1.116 + return false; 1.117 + } 1.118 + return true; 1.119 +} 1.120 + 1.121 +static 1.122 +nsIScriptGlobalObject* GetGlobalObject(nsIChannel* aChannel) 1.123 +{ 1.124 + // Get the global object owner from the channel 1.125 + nsCOMPtr<nsIDocShell> docShell; 1.126 + NS_QueryNotificationCallbacks(aChannel, docShell); 1.127 + if (!docShell) { 1.128 + NS_WARNING("Unable to get a docShell from the channel!"); 1.129 + return nullptr; 1.130 + } 1.131 + 1.132 + // So far so good: get the script global from its docshell 1.133 + nsIScriptGlobalObject* global = docShell->GetScriptGlobalObject(); 1.134 + 1.135 + NS_ASSERTION(global, 1.136 + "Unable to get an nsIScriptGlobalObject from the " 1.137 + "docShell!"); 1.138 + return global; 1.139 +} 1.140 + 1.141 +nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel, 1.142 + PopupControlState aPopupState, 1.143 + uint32_t aExecutionPolicy, 1.144 + nsPIDOMWindow *aOriginalInnerWindow) 1.145 +{ 1.146 + if (aExecutionPolicy == nsIScriptChannel::NO_EXECUTION) { 1.147 + // Nothing to do here. 1.148 + return NS_ERROR_DOM_RETVAL_UNDEFINED; 1.149 + } 1.150 + 1.151 + NS_ENSURE_ARG_POINTER(aChannel); 1.152 + 1.153 + // Get principal of code for execution 1.154 + nsCOMPtr<nsISupports> owner; 1.155 + aChannel->GetOwner(getter_AddRefs(owner)); 1.156 + nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(owner); 1.157 + if (!principal) { 1.158 + // No execution without a principal! 1.159 + NS_ASSERTION(!owner, "Non-principal owner?"); 1.160 + NS_WARNING("No principal to execute JS with"); 1.161 + return NS_ERROR_DOM_RETVAL_UNDEFINED; 1.162 + } 1.163 + 1.164 + nsresult rv; 1.165 + 1.166 + // CSP check: javascript: URIs disabled unless "inline" scripts are 1.167 + // allowed. 1.168 + nsCOMPtr<nsIContentSecurityPolicy> csp; 1.169 + rv = principal->GetCsp(getter_AddRefs(csp)); 1.170 + NS_ENSURE_SUCCESS(rv, rv); 1.171 + if (csp) { 1.172 + bool allowsInline = true; 1.173 + bool reportViolations = false; 1.174 + rv = csp->GetAllowsInlineScript(&reportViolations, &allowsInline); 1.175 + NS_ENSURE_SUCCESS(rv, rv); 1.176 + 1.177 + if (reportViolations) { 1.178 + // gather information to log with violation report 1.179 + nsCOMPtr<nsIURI> uri; 1.180 + principal->GetURI(getter_AddRefs(uri)); 1.181 + nsAutoCString asciiSpec; 1.182 + uri->GetAsciiSpec(asciiSpec); 1.183 + csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT, 1.184 + NS_ConvertUTF8toUTF16(asciiSpec), 1.185 + NS_ConvertUTF8toUTF16(mURL), 1.186 + 0, 1.187 + EmptyString(), 1.188 + EmptyString()); 1.189 + } 1.190 + 1.191 + //return early if inline scripts are not allowed 1.192 + if (!allowsInline) { 1.193 + return NS_ERROR_DOM_RETVAL_UNDEFINED; 1.194 + } 1.195 + } 1.196 + 1.197 + // Get the global object we should be running on. 1.198 + nsIScriptGlobalObject* global = GetGlobalObject(aChannel); 1.199 + if (!global) { 1.200 + return NS_ERROR_FAILURE; 1.201 + } 1.202 + 1.203 + // Sandboxed document check: javascript: URI's are disabled 1.204 + // in a sandboxed document unless 'allow-scripts' was specified. 1.205 + nsIDocument* doc = aOriginalInnerWindow->GetExtantDoc(); 1.206 + if (doc && (doc->GetSandboxFlags() & SANDBOXED_SCRIPTS)) { 1.207 + return NS_ERROR_DOM_RETVAL_UNDEFINED; 1.208 + } 1.209 + 1.210 + // Push our popup control state 1.211 + nsAutoPopupStatePusher popupStatePusher(aPopupState); 1.212 + 1.213 + // Make sure we still have the same inner window as we used to. 1.214 + nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(global); 1.215 + nsPIDOMWindow *innerWin = win->GetCurrentInnerWindow(); 1.216 + 1.217 + if (innerWin != aOriginalInnerWindow) { 1.218 + return NS_ERROR_UNEXPECTED; 1.219 + } 1.220 + 1.221 + nsCOMPtr<nsIScriptGlobalObject> innerGlobal = do_QueryInterface(innerWin); 1.222 + 1.223 + nsCOMPtr<nsIDOMWindow> domWindow(do_QueryInterface(global, &rv)); 1.224 + if (NS_FAILED(rv)) { 1.225 + return NS_ERROR_FAILURE; 1.226 + } 1.227 + 1.228 + // So far so good: get the script context from its owner. 1.229 + nsCOMPtr<nsIScriptContext> scriptContext = global->GetContext(); 1.230 + if (!scriptContext) 1.231 + return NS_ERROR_FAILURE; 1.232 + 1.233 + nsAutoCString script(mScript); 1.234 + // Unescape the script 1.235 + NS_UnescapeURL(script); 1.236 + 1.237 + 1.238 + nsCOMPtr<nsIScriptSecurityManager> securityManager; 1.239 + securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); 1.240 + if (NS_FAILED(rv)) 1.241 + return rv; 1.242 + 1.243 + bool useSandbox = 1.244 + (aExecutionPolicy == nsIScriptChannel::EXECUTE_IN_SANDBOX); 1.245 + 1.246 + // New script entry point required, due to the "Create a script" step of 1.247 + // http://www.whatwg.org/specs/web-apps/current-work/#javascript-protocol 1.248 + AutoEntryScript entryScript(innerGlobal, true, 1.249 + scriptContext->GetNativeContext()); 1.250 + JSContext* cx = entryScript.cx(); 1.251 + JS::Rooted<JSObject*> globalJSObject(cx, innerGlobal->GetGlobalJSObject()); 1.252 + NS_ENSURE_TRUE(globalJSObject, NS_ERROR_UNEXPECTED); 1.253 + 1.254 + if (!useSandbox) { 1.255 + //-- Don't outside a sandbox unless the script principal subsumes the 1.256 + // principal of the context. 1.257 + nsIPrincipal* objectPrincipal = nsContentUtils::GetObjectPrincipal(globalJSObject); 1.258 + 1.259 + bool subsumes; 1.260 + rv = principal->Subsumes(objectPrincipal, &subsumes); 1.261 + if (NS_FAILED(rv)) 1.262 + return rv; 1.263 + 1.264 + useSandbox = !subsumes; 1.265 + } 1.266 + 1.267 + JS::Rooted<JS::Value> v (cx, JS::UndefinedValue()); 1.268 + // Finally, we have everything needed to evaluate the expression. 1.269 + if (useSandbox) { 1.270 + // We were asked to use a sandbox, or the channel owner isn't allowed 1.271 + // to execute in this context. Evaluate the javascript URL in a 1.272 + // sandbox to prevent it from accessing data it doesn't have 1.273 + // permissions to access. 1.274 + 1.275 + // First check to make sure it's OK to evaluate this script to 1.276 + // start with. For example, script could be disabled. 1.277 + if (!securityManager->ScriptAllowed(globalJSObject)) { 1.278 + // Treat this as returning undefined from the script. That's what 1.279 + // nsJSContext does. 1.280 + return NS_ERROR_DOM_RETVAL_UNDEFINED; 1.281 + } 1.282 + 1.283 + nsIXPConnect *xpc = nsContentUtils::XPConnect(); 1.284 + 1.285 + nsCOMPtr<nsIXPConnectJSObjectHolder> sandbox; 1.286 + // Important: Use a null principal here 1.287 + rv = xpc->CreateSandbox(cx, nullptr, getter_AddRefs(sandbox)); 1.288 + NS_ENSURE_SUCCESS(rv, rv); 1.289 + 1.290 + // The nsXPConnect sandbox API gives us a wrapper to the sandbox for 1.291 + // our current compartment. Because our current context doesn't necessarily 1.292 + // subsume that of the sandbox, we want to unwrap and enter the sandbox's 1.293 + // compartment. It's a shame that the APIs here are so clunkly. :-( 1.294 + JS::Rooted<JSObject*> sandboxObj(cx, sandbox->GetJSObject()); 1.295 + NS_ENSURE_STATE(sandboxObj); 1.296 + sandboxObj = js::UncheckedUnwrap(sandboxObj); 1.297 + JSAutoCompartment ac(cx, sandboxObj); 1.298 + 1.299 + // Push our JSContext on the context stack so the EvalInSandboxObject call (and 1.300 + // JS_ReportPendingException, if relevant) will use the principal of cx. 1.301 + nsCxPusher pusher; 1.302 + pusher.Push(cx); 1.303 + rv = xpc->EvalInSandboxObject(NS_ConvertUTF8toUTF16(script), 1.304 + /* filename = */ nullptr, cx, 1.305 + sandboxObj, true, &v); 1.306 + 1.307 + // Propagate and report exceptions that happened in the 1.308 + // sandbox. 1.309 + if (JS_IsExceptionPending(cx)) { 1.310 + JS_ReportPendingException(cx); 1.311 + } 1.312 + } else { 1.313 + // No need to use the sandbox, evaluate the script directly in 1.314 + // the given scope. 1.315 + JS::CompileOptions options(cx); 1.316 + options.setFileAndLine(mURL.get(), 1) 1.317 + .setVersion(JSVERSION_DEFAULT); 1.318 + nsJSUtils::EvaluateOptions evalOptions; 1.319 + evalOptions.setCoerceToString(true); 1.320 + rv = nsJSUtils::EvaluateString(cx, NS_ConvertUTF8toUTF16(script), 1.321 + globalJSObject, options, evalOptions, &v); 1.322 + 1.323 + // If there's an error on cx as a result of that call, report 1.324 + // it now -- either we're just running under the event loop, 1.325 + // so we shouldn't propagate JS exceptions out of here, or we 1.326 + // can't be sure that our caller is JS (and if it's not we'll 1.327 + // lose the error), or it might be JS that then proceeds to 1.328 + // cause an error of its own (which will also make us lose 1.329 + // this error). 1.330 + ::JS_ReportPendingException(cx); 1.331 + } 1.332 + 1.333 + // If we took the sandbox path above, v might be in the sandbox 1.334 + // compartment. 1.335 + if (!JS_WrapValue(cx, &v)) { 1.336 + return NS_ERROR_OUT_OF_MEMORY; 1.337 + } 1.338 + 1.339 + if (NS_FAILED(rv) || !(v.isString() || v.isUndefined())) { 1.340 + return NS_ERROR_MALFORMED_URI; 1.341 + } else if (v.isUndefined()) { 1.342 + return NS_ERROR_DOM_RETVAL_UNDEFINED; 1.343 + } else { 1.344 + nsDependentJSString result; 1.345 + if (!result.init(cx, v)) { 1.346 + return NS_ERROR_OUT_OF_MEMORY; 1.347 + } 1.348 + 1.349 + char *bytes; 1.350 + uint32_t bytesLen; 1.351 + NS_NAMED_LITERAL_CSTRING(isoCharset, "ISO-8859-1"); 1.352 + NS_NAMED_LITERAL_CSTRING(utf8Charset, "UTF-8"); 1.353 + const nsCString *charset; 1.354 + if (IsISO88591(result)) { 1.355 + // For compatibility, if the result is ISO-8859-1, we use 1.356 + // ISO-8859-1, so that people can compatibly create images 1.357 + // using javascript: URLs. 1.358 + bytes = ToNewCString(result); 1.359 + bytesLen = result.Length(); 1.360 + charset = &isoCharset; 1.361 + } 1.362 + else { 1.363 + bytes = ToNewUTF8String(result, &bytesLen); 1.364 + charset = &utf8Charset; 1.365 + } 1.366 + aChannel->SetContentCharset(*charset); 1.367 + if (bytes) 1.368 + rv = NS_NewByteInputStream(getter_AddRefs(mInnerStream), 1.369 + bytes, bytesLen, 1.370 + NS_ASSIGNMENT_ADOPT); 1.371 + else 1.372 + rv = NS_ERROR_OUT_OF_MEMORY; 1.373 + } 1.374 + 1.375 + return rv; 1.376 +} 1.377 + 1.378 +//////////////////////////////////////////////////////////////////////////////// 1.379 + 1.380 +class nsJSChannel : public nsIChannel, 1.381 + public nsIStreamListener, 1.382 + public nsIScriptChannel, 1.383 + public nsIPropertyBag2 1.384 +{ 1.385 +public: 1.386 + nsJSChannel(); 1.387 + 1.388 + NS_DECL_ISUPPORTS 1.389 + NS_DECL_NSIREQUEST 1.390 + NS_DECL_NSICHANNEL 1.391 + NS_DECL_NSIREQUESTOBSERVER 1.392 + NS_DECL_NSISTREAMLISTENER 1.393 + NS_DECL_NSISCRIPTCHANNEL 1.394 + NS_FORWARD_SAFE_NSIPROPERTYBAG(mPropertyBag) 1.395 + NS_FORWARD_SAFE_NSIPROPERTYBAG2(mPropertyBag) 1.396 + 1.397 + nsresult Init(nsIURI *aURI); 1.398 + 1.399 + // Actually evaluate the script. 1.400 + void EvaluateScript(); 1.401 + 1.402 +protected: 1.403 + virtual ~nsJSChannel(); 1.404 + 1.405 + nsresult StopAll(); 1.406 + 1.407 + void NotifyListener(); 1.408 + 1.409 + void CleanupStrongRefs(); 1.410 + 1.411 +protected: 1.412 + nsCOMPtr<nsIChannel> mStreamChannel; 1.413 + nsCOMPtr<nsIPropertyBag2> mPropertyBag; 1.414 + nsCOMPtr<nsIStreamListener> mListener; // Our final listener 1.415 + nsCOMPtr<nsISupports> mContext; // The context passed to AsyncOpen 1.416 + nsCOMPtr<nsPIDOMWindow> mOriginalInnerWindow; // The inner window our load 1.417 + // started against. 1.418 + // If we blocked onload on a document in AsyncOpen, this is the document we 1.419 + // did it on. 1.420 + nsCOMPtr<nsIDocument> mDocumentOnloadBlockedOn; 1.421 + 1.422 + nsresult mStatus; // Our status 1.423 + 1.424 + nsLoadFlags mLoadFlags; 1.425 + nsLoadFlags mActualLoadFlags; // See AsyncOpen 1.426 + 1.427 + nsRefPtr<nsJSThunk> mIOThunk; 1.428 + PopupControlState mPopupState; 1.429 + uint32_t mExecutionPolicy; 1.430 + bool mIsAsync; 1.431 + bool mIsActive; 1.432 + bool mOpenedStreamChannel; 1.433 +}; 1.434 + 1.435 +nsJSChannel::nsJSChannel() : 1.436 + mStatus(NS_OK), 1.437 + mLoadFlags(LOAD_NORMAL), 1.438 + mActualLoadFlags(LOAD_NORMAL), 1.439 + mPopupState(openOverridden), 1.440 + mExecutionPolicy(EXECUTE_IN_SANDBOX), 1.441 + mIsAsync(true), 1.442 + mIsActive(false), 1.443 + mOpenedStreamChannel(false) 1.444 +{ 1.445 +} 1.446 + 1.447 +nsJSChannel::~nsJSChannel() 1.448 +{ 1.449 +} 1.450 + 1.451 +nsresult nsJSChannel::StopAll() 1.452 +{ 1.453 + nsresult rv = NS_ERROR_UNEXPECTED; 1.454 + nsCOMPtr<nsIWebNavigation> webNav; 1.455 + NS_QueryNotificationCallbacks(mStreamChannel, webNav); 1.456 + 1.457 + NS_ASSERTION(webNav, "Can't get nsIWebNavigation from channel!"); 1.458 + if (webNav) { 1.459 + rv = webNav->Stop(nsIWebNavigation::STOP_ALL); 1.460 + } 1.461 + 1.462 + return rv; 1.463 +} 1.464 + 1.465 +nsresult nsJSChannel::Init(nsIURI *aURI) 1.466 +{ 1.467 + nsRefPtr<nsJSURI> jsURI; 1.468 + nsresult rv = aURI->QueryInterface(kJSURICID, 1.469 + getter_AddRefs(jsURI)); 1.470 + NS_ENSURE_SUCCESS(rv, rv); 1.471 + 1.472 + // Create the nsIStreamIO layer used by the nsIStreamIOChannel. 1.473 + mIOThunk = new nsJSThunk(); 1.474 + if (!mIOThunk) 1.475 + return NS_ERROR_OUT_OF_MEMORY; 1.476 + 1.477 + // Create a stock input stream channel... 1.478 + // Remember, until AsyncOpen is called, the script will not be evaluated 1.479 + // and the underlying Input Stream will not be created... 1.480 + nsCOMPtr<nsIChannel> channel; 1.481 + 1.482 + // If the resultant script evaluation actually does return a value, we 1.483 + // treat it as html. 1.484 + rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, mIOThunk, 1.485 + NS_LITERAL_CSTRING("text/html")); 1.486 + if (NS_FAILED(rv)) return rv; 1.487 + 1.488 + rv = mIOThunk->Init(aURI); 1.489 + if (NS_SUCCEEDED(rv)) { 1.490 + mStreamChannel = channel; 1.491 + mPropertyBag = do_QueryInterface(channel); 1.492 + nsCOMPtr<nsIWritablePropertyBag2> writableBag = 1.493 + do_QueryInterface(channel); 1.494 + if (writableBag && jsURI->GetBaseURI()) { 1.495 + writableBag->SetPropertyAsInterface(NS_LITERAL_STRING("baseURI"), 1.496 + jsURI->GetBaseURI()); 1.497 + } 1.498 + } 1.499 + 1.500 + return rv; 1.501 +} 1.502 + 1.503 +// 1.504 +// nsISupports implementation... 1.505 +// 1.506 + 1.507 +NS_IMPL_ISUPPORTS(nsJSChannel, nsIChannel, nsIRequest, nsIRequestObserver, 1.508 + nsIStreamListener, nsIScriptChannel, nsIPropertyBag, 1.509 + nsIPropertyBag2) 1.510 + 1.511 +// 1.512 +// nsIRequest implementation... 1.513 +// 1.514 + 1.515 +NS_IMETHODIMP 1.516 +nsJSChannel::GetName(nsACString &aResult) 1.517 +{ 1.518 + return mStreamChannel->GetName(aResult); 1.519 +} 1.520 + 1.521 +NS_IMETHODIMP 1.522 +nsJSChannel::IsPending(bool *aResult) 1.523 +{ 1.524 + *aResult = mIsActive; 1.525 + return NS_OK; 1.526 +} 1.527 + 1.528 +NS_IMETHODIMP 1.529 +nsJSChannel::GetStatus(nsresult *aResult) 1.530 +{ 1.531 + if (NS_SUCCEEDED(mStatus) && mOpenedStreamChannel) { 1.532 + return mStreamChannel->GetStatus(aResult); 1.533 + } 1.534 + 1.535 + *aResult = mStatus; 1.536 + 1.537 + return NS_OK; 1.538 +} 1.539 + 1.540 +NS_IMETHODIMP 1.541 +nsJSChannel::Cancel(nsresult aStatus) 1.542 +{ 1.543 + mStatus = aStatus; 1.544 + 1.545 + if (mOpenedStreamChannel) { 1.546 + mStreamChannel->Cancel(aStatus); 1.547 + } 1.548 + 1.549 + return NS_OK; 1.550 +} 1.551 + 1.552 +NS_IMETHODIMP 1.553 +nsJSChannel::Suspend() 1.554 +{ 1.555 + return mStreamChannel->Suspend(); 1.556 +} 1.557 + 1.558 +NS_IMETHODIMP 1.559 +nsJSChannel::Resume() 1.560 +{ 1.561 + return mStreamChannel->Resume(); 1.562 +} 1.563 + 1.564 +// 1.565 +// nsIChannel implementation 1.566 +// 1.567 + 1.568 +NS_IMETHODIMP 1.569 +nsJSChannel::GetOriginalURI(nsIURI * *aURI) 1.570 +{ 1.571 + return mStreamChannel->GetOriginalURI(aURI); 1.572 +} 1.573 + 1.574 +NS_IMETHODIMP 1.575 +nsJSChannel::SetOriginalURI(nsIURI *aURI) 1.576 +{ 1.577 + return mStreamChannel->SetOriginalURI(aURI); 1.578 +} 1.579 + 1.580 +NS_IMETHODIMP 1.581 +nsJSChannel::GetURI(nsIURI * *aURI) 1.582 +{ 1.583 + return mStreamChannel->GetURI(aURI); 1.584 +} 1.585 + 1.586 +NS_IMETHODIMP 1.587 +nsJSChannel::Open(nsIInputStream **aResult) 1.588 +{ 1.589 + nsresult rv = mIOThunk->EvaluateScript(mStreamChannel, mPopupState, 1.590 + mExecutionPolicy, 1.591 + mOriginalInnerWindow); 1.592 + NS_ENSURE_SUCCESS(rv, rv); 1.593 + 1.594 + return mStreamChannel->Open(aResult); 1.595 +} 1.596 + 1.597 +NS_IMETHODIMP 1.598 +nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext) 1.599 +{ 1.600 + NS_ENSURE_ARG(aListener); 1.601 + 1.602 + // First make sure that we have a usable inner window; we'll want to make 1.603 + // sure that we execute against that inner and no other. 1.604 + nsIScriptGlobalObject* global = GetGlobalObject(this); 1.605 + if (!global) { 1.606 + return NS_ERROR_NOT_AVAILABLE; 1.607 + } 1.608 + 1.609 + nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(global)); 1.610 + NS_ASSERTION(win, "Our global is not a window??"); 1.611 + 1.612 + // Make sure we create a new inner window if one doesn't already exist (see 1.613 + // bug 306630). 1.614 + mOriginalInnerWindow = win->EnsureInnerWindow(); 1.615 + if (!mOriginalInnerWindow) { 1.616 + return NS_ERROR_NOT_AVAILABLE; 1.617 + } 1.618 + 1.619 + mListener = aListener; 1.620 + mContext = aContext; 1.621 + 1.622 + mIsActive = true; 1.623 + 1.624 + // Temporarily set the LOAD_BACKGROUND flag to suppress load group observer 1.625 + // notifications (and hence nsIWebProgressListener notifications) from 1.626 + // being dispatched. This is required since we suppress LOAD_DOCUMENT_URI, 1.627 + // which means that the DocLoader would not generate document start and 1.628 + // stop notifications (see bug 257875). 1.629 + mActualLoadFlags = mLoadFlags; 1.630 + mLoadFlags |= LOAD_BACKGROUND; 1.631 + 1.632 + // Add the javascript channel to its loadgroup so that we know if 1.633 + // network loads were canceled or not... 1.634 + nsCOMPtr<nsILoadGroup> loadGroup; 1.635 + mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup)); 1.636 + if (loadGroup) { 1.637 + nsresult rv = loadGroup->AddRequest(this, nullptr); 1.638 + if (NS_FAILED(rv)) { 1.639 + mIsActive = false; 1.640 + CleanupStrongRefs(); 1.641 + return rv; 1.642 + } 1.643 + } 1.644 + 1.645 + mDocumentOnloadBlockedOn = mOriginalInnerWindow->GetExtantDoc(); 1.646 + if (mDocumentOnloadBlockedOn) { 1.647 + // If we're a document channel, we need to actually block onload on our 1.648 + // _parent_ document. This is because we don't actually set our 1.649 + // LOAD_DOCUMENT_URI flag, so a docloader we're loading in as the 1.650 + // document channel will claim to not be busy, and our parent's onload 1.651 + // could fire too early. 1.652 + nsLoadFlags loadFlags; 1.653 + mStreamChannel->GetLoadFlags(&loadFlags); 1.654 + if (loadFlags & LOAD_DOCUMENT_URI) { 1.655 + mDocumentOnloadBlockedOn = 1.656 + mDocumentOnloadBlockedOn->GetParentDocument(); 1.657 + } 1.658 + } 1.659 + if (mDocumentOnloadBlockedOn) { 1.660 + mDocumentOnloadBlockedOn->BlockOnload(); 1.661 + } 1.662 + 1.663 + 1.664 + mPopupState = win->GetPopupControlState(); 1.665 + 1.666 + void (nsJSChannel::*method)(); 1.667 + if (mIsAsync) { 1.668 + // post an event to do the rest 1.669 + method = &nsJSChannel::EvaluateScript; 1.670 + } else { 1.671 + EvaluateScript(); 1.672 + if (mOpenedStreamChannel) { 1.673 + // That will handle notifying things 1.674 + return NS_OK; 1.675 + } 1.676 + 1.677 + NS_ASSERTION(NS_FAILED(mStatus), "We should have failed _somehow_"); 1.678 + 1.679 + // mStatus is going to be NS_ERROR_DOM_RETVAL_UNDEFINED if we didn't 1.680 + // have any content resulting from the execution and NS_BINDING_ABORTED 1.681 + // if something we did causes our own load to be stopped. Return 1.682 + // success in those cases, and error out in all others. 1.683 + if (mStatus != NS_ERROR_DOM_RETVAL_UNDEFINED && 1.684 + mStatus != NS_BINDING_ABORTED) { 1.685 + // Note that calling EvaluateScript() handled removing us from the 1.686 + // loadgroup and marking us as not active anymore. 1.687 + CleanupStrongRefs(); 1.688 + return mStatus; 1.689 + } 1.690 + 1.691 + // We're returning success from asyncOpen(), but we didn't open a 1.692 + // stream channel. We'll have to notify ourselves, but make sure to do 1.693 + // it asynchronously. 1.694 + method = &nsJSChannel::NotifyListener; 1.695 + } 1.696 + 1.697 + nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this, method); 1.698 + nsresult rv = NS_DispatchToCurrentThread(ev); 1.699 + 1.700 + if (NS_FAILED(rv)) { 1.701 + loadGroup->RemoveRequest(this, nullptr, rv); 1.702 + mIsActive = false; 1.703 + CleanupStrongRefs(); 1.704 + } 1.705 + return rv; 1.706 +} 1.707 + 1.708 +void 1.709 +nsJSChannel::EvaluateScript() 1.710 +{ 1.711 + // Synchronously execute the script... 1.712 + // mIsActive is used to indicate the the request is 'busy' during the 1.713 + // the script evaluation phase. This means that IsPending() will 1.714 + // indicate the the request is busy while the script is executing... 1.715 + 1.716 + // Note that we want to be in the loadgroup and pending while we evaluate 1.717 + // the script, so that we find out if the loadgroup gets canceled by the 1.718 + // script execution (in which case we shouldn't pump out data even if the 1.719 + // script returns it). 1.720 + 1.721 + if (NS_SUCCEEDED(mStatus)) { 1.722 + nsresult rv = mIOThunk->EvaluateScript(mStreamChannel, mPopupState, 1.723 + mExecutionPolicy, 1.724 + mOriginalInnerWindow); 1.725 + 1.726 + // Note that evaluation may have canceled us, so recheck mStatus again 1.727 + if (NS_FAILED(rv) && NS_SUCCEEDED(mStatus)) { 1.728 + mStatus = rv; 1.729 + } 1.730 + } 1.731 + 1.732 + // Remove the javascript channel from its loadgroup... 1.733 + nsCOMPtr<nsILoadGroup> loadGroup; 1.734 + mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup)); 1.735 + if (loadGroup) { 1.736 + loadGroup->RemoveRequest(this, nullptr, mStatus); 1.737 + } 1.738 + 1.739 + // Reset load flags to their original value... 1.740 + mLoadFlags = mActualLoadFlags; 1.741 + 1.742 + // We're no longer active, it's now up to the stream channel to do 1.743 + // the loading, if needed. 1.744 + mIsActive = false; 1.745 + 1.746 + if (NS_FAILED(mStatus)) { 1.747 + if (mIsAsync) { 1.748 + NotifyListener(); 1.749 + } 1.750 + return; 1.751 + } 1.752 + 1.753 + // EvaluateScript() succeeded, and we were not canceled, that 1.754 + // means there's data to parse as a result of evaluating the 1.755 + // script. 1.756 + 1.757 + // Get the stream channels load flags (!= mLoadFlags). 1.758 + nsLoadFlags loadFlags; 1.759 + mStreamChannel->GetLoadFlags(&loadFlags); 1.760 + 1.761 + uint32_t disposition; 1.762 + if (NS_FAILED(mStreamChannel->GetContentDisposition(&disposition))) 1.763 + disposition = nsIChannel::DISPOSITION_INLINE; 1.764 + if (loadFlags & LOAD_DOCUMENT_URI && disposition != nsIChannel::DISPOSITION_ATTACHMENT) { 1.765 + // We're loaded as the document channel and not expecting to download 1.766 + // the result. If we go on, we'll blow away the current document. Make 1.767 + // sure that's ok. If so, stop all pending network loads. 1.768 + 1.769 + nsCOMPtr<nsIDocShell> docShell; 1.770 + NS_QueryNotificationCallbacks(mStreamChannel, docShell); 1.771 + if (docShell) { 1.772 + nsCOMPtr<nsIContentViewer> cv; 1.773 + docShell->GetContentViewer(getter_AddRefs(cv)); 1.774 + 1.775 + if (cv) { 1.776 + bool okToUnload; 1.777 + 1.778 + if (NS_SUCCEEDED(cv->PermitUnload(false, &okToUnload)) && 1.779 + !okToUnload) { 1.780 + // The user didn't want to unload the current 1.781 + // page, translate this into an undefined 1.782 + // return from the javascript: URL... 1.783 + mStatus = NS_ERROR_DOM_RETVAL_UNDEFINED; 1.784 + } 1.785 + } 1.786 + } 1.787 + 1.788 + if (NS_SUCCEEDED(mStatus)) { 1.789 + mStatus = StopAll(); 1.790 + } 1.791 + } 1.792 + 1.793 + if (NS_FAILED(mStatus)) { 1.794 + if (mIsAsync) { 1.795 + NotifyListener(); 1.796 + } 1.797 + return; 1.798 + } 1.799 + 1.800 + mStatus = mStreamChannel->AsyncOpen(this, mContext); 1.801 + if (NS_SUCCEEDED(mStatus)) { 1.802 + // mStreamChannel will call OnStartRequest and OnStopRequest on 1.803 + // us, so we'll be sure to call them on our listener. 1.804 + mOpenedStreamChannel = true; 1.805 + 1.806 + // Now readd ourselves to the loadgroup so we can receive 1.807 + // cancellation notifications. 1.808 + mIsActive = true; 1.809 + if (loadGroup) { 1.810 + mStatus = loadGroup->AddRequest(this, nullptr); 1.811 + 1.812 + // If AddRequest failed, that's OK. The key is to make sure we get 1.813 + // cancelled if needed, and that call just canceled us if it 1.814 + // failed. We'll still get notified by the stream channel when it 1.815 + // finishes. 1.816 + } 1.817 + 1.818 + } else if (mIsAsync) { 1.819 + NotifyListener(); 1.820 + } 1.821 + 1.822 + return; 1.823 +} 1.824 + 1.825 +void 1.826 +nsJSChannel::NotifyListener() 1.827 +{ 1.828 + mListener->OnStartRequest(this, mContext); 1.829 + mListener->OnStopRequest(this, mContext, mStatus); 1.830 + 1.831 + CleanupStrongRefs(); 1.832 +} 1.833 + 1.834 +void 1.835 +nsJSChannel::CleanupStrongRefs() 1.836 +{ 1.837 + mListener = nullptr; 1.838 + mContext = nullptr; 1.839 + mOriginalInnerWindow = nullptr; 1.840 + if (mDocumentOnloadBlockedOn) { 1.841 + mDocumentOnloadBlockedOn->UnblockOnload(false); 1.842 + mDocumentOnloadBlockedOn = nullptr; 1.843 + } 1.844 +} 1.845 + 1.846 +NS_IMETHODIMP 1.847 +nsJSChannel::GetLoadFlags(nsLoadFlags *aLoadFlags) 1.848 +{ 1.849 + *aLoadFlags = mLoadFlags; 1.850 + 1.851 + return NS_OK; 1.852 +} 1.853 + 1.854 +NS_IMETHODIMP 1.855 +nsJSChannel::SetLoadFlags(nsLoadFlags aLoadFlags) 1.856 +{ 1.857 + // Figure out whether the LOAD_BACKGROUND bit in aLoadFlags is 1.858 + // actually right. 1.859 + bool bogusLoadBackground = false; 1.860 + if (mIsActive && !(mActualLoadFlags & LOAD_BACKGROUND) && 1.861 + (aLoadFlags & LOAD_BACKGROUND)) { 1.862 + // We're getting a LOAD_BACKGROUND, but it's probably just our own fake 1.863 + // flag being mirrored to us. The one exception is if our loadgroup is 1.864 + // LOAD_BACKGROUND. 1.865 + bool loadGroupIsBackground = false; 1.866 + nsCOMPtr<nsILoadGroup> loadGroup; 1.867 + mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup)); 1.868 + if (loadGroup) { 1.869 + nsLoadFlags loadGroupFlags; 1.870 + loadGroup->GetLoadFlags(&loadGroupFlags); 1.871 + loadGroupIsBackground = ((loadGroupFlags & LOAD_BACKGROUND) != 0); 1.872 + } 1.873 + bogusLoadBackground = !loadGroupIsBackground; 1.874 + } 1.875 + 1.876 + // Classifying a javascript: URI doesn't help us, and requires 1.877 + // NSS to boot, which we don't have in content processes. See 1.878 + // https://bugzilla.mozilla.org/show_bug.cgi?id=617838. 1.879 + aLoadFlags &= ~LOAD_CLASSIFY_URI; 1.880 + 1.881 + // Since the javascript channel is never the actual channel that 1.882 + // any data is loaded through, don't ever set the 1.883 + // LOAD_DOCUMENT_URI flag on it, since that could lead to two 1.884 + // 'document channels' in the loadgroup if a javascript: URL is 1.885 + // loaded while a document is being loaded in the same window. 1.886 + 1.887 + // XXXbz this, and a whole lot of other hackery, could go away if we'd just 1.888 + // cancel the current document load on javascript: load start like IE does. 1.889 + 1.890 + mLoadFlags = aLoadFlags & ~LOAD_DOCUMENT_URI; 1.891 + 1.892 + if (bogusLoadBackground) { 1.893 + aLoadFlags = aLoadFlags & ~LOAD_BACKGROUND; 1.894 + } 1.895 + 1.896 + mActualLoadFlags = aLoadFlags; 1.897 + 1.898 + // ... but the underlying stream channel should get this bit, if 1.899 + // set, since that'll be the real document channel if the 1.900 + // javascript: URL generated data. 1.901 + 1.902 + return mStreamChannel->SetLoadFlags(aLoadFlags); 1.903 +} 1.904 + 1.905 +NS_IMETHODIMP 1.906 +nsJSChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) 1.907 +{ 1.908 + return mStreamChannel->GetLoadGroup(aLoadGroup); 1.909 +} 1.910 + 1.911 +NS_IMETHODIMP 1.912 +nsJSChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) 1.913 +{ 1.914 + if (aLoadGroup) { 1.915 + bool streamPending; 1.916 + nsresult rv = mStreamChannel->IsPending(&streamPending); 1.917 + NS_ENSURE_SUCCESS(rv, rv); 1.918 + 1.919 + if (streamPending) { 1.920 + nsCOMPtr<nsILoadGroup> curLoadGroup; 1.921 + mStreamChannel->GetLoadGroup(getter_AddRefs(curLoadGroup)); 1.922 + 1.923 + if (aLoadGroup != curLoadGroup) { 1.924 + // Move the stream channel to our new loadgroup. Make sure to 1.925 + // add it before removing it, so that we don't trigger onload 1.926 + // by accident. 1.927 + aLoadGroup->AddRequest(mStreamChannel, nullptr); 1.928 + if (curLoadGroup) { 1.929 + curLoadGroup->RemoveRequest(mStreamChannel, nullptr, 1.930 + NS_BINDING_RETARGETED); 1.931 + } 1.932 + } 1.933 + } 1.934 + } 1.935 + 1.936 + return mStreamChannel->SetLoadGroup(aLoadGroup); 1.937 +} 1.938 + 1.939 +NS_IMETHODIMP 1.940 +nsJSChannel::GetOwner(nsISupports* *aOwner) 1.941 +{ 1.942 + return mStreamChannel->GetOwner(aOwner); 1.943 +} 1.944 + 1.945 +NS_IMETHODIMP 1.946 +nsJSChannel::SetOwner(nsISupports* aOwner) 1.947 +{ 1.948 + return mStreamChannel->SetOwner(aOwner); 1.949 +} 1.950 + 1.951 +NS_IMETHODIMP 1.952 +nsJSChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks) 1.953 +{ 1.954 + return mStreamChannel->GetNotificationCallbacks(aCallbacks); 1.955 +} 1.956 + 1.957 +NS_IMETHODIMP 1.958 +nsJSChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) 1.959 +{ 1.960 + return mStreamChannel->SetNotificationCallbacks(aCallbacks); 1.961 +} 1.962 + 1.963 +NS_IMETHODIMP 1.964 +nsJSChannel::GetSecurityInfo(nsISupports * *aSecurityInfo) 1.965 +{ 1.966 + return mStreamChannel->GetSecurityInfo(aSecurityInfo); 1.967 +} 1.968 + 1.969 +NS_IMETHODIMP 1.970 +nsJSChannel::GetContentType(nsACString &aContentType) 1.971 +{ 1.972 + return mStreamChannel->GetContentType(aContentType); 1.973 +} 1.974 + 1.975 +NS_IMETHODIMP 1.976 +nsJSChannel::SetContentType(const nsACString &aContentType) 1.977 +{ 1.978 + return mStreamChannel->SetContentType(aContentType); 1.979 +} 1.980 + 1.981 +NS_IMETHODIMP 1.982 +nsJSChannel::GetContentCharset(nsACString &aContentCharset) 1.983 +{ 1.984 + return mStreamChannel->GetContentCharset(aContentCharset); 1.985 +} 1.986 + 1.987 +NS_IMETHODIMP 1.988 +nsJSChannel::SetContentCharset(const nsACString &aContentCharset) 1.989 +{ 1.990 + return mStreamChannel->SetContentCharset(aContentCharset); 1.991 +} 1.992 + 1.993 +NS_IMETHODIMP 1.994 +nsJSChannel::GetContentDisposition(uint32_t *aContentDisposition) 1.995 +{ 1.996 + return mStreamChannel->GetContentDisposition(aContentDisposition); 1.997 +} 1.998 + 1.999 +NS_IMETHODIMP 1.1000 +nsJSChannel::SetContentDisposition(uint32_t aContentDisposition) 1.1001 +{ 1.1002 + return mStreamChannel->SetContentDisposition(aContentDisposition); 1.1003 +} 1.1004 + 1.1005 +NS_IMETHODIMP 1.1006 +nsJSChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename) 1.1007 +{ 1.1008 + return mStreamChannel->GetContentDispositionFilename(aContentDispositionFilename); 1.1009 +} 1.1010 + 1.1011 +NS_IMETHODIMP 1.1012 +nsJSChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename) 1.1013 +{ 1.1014 + return mStreamChannel->SetContentDispositionFilename(aContentDispositionFilename); 1.1015 +} 1.1016 + 1.1017 +NS_IMETHODIMP 1.1018 +nsJSChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader) 1.1019 +{ 1.1020 + return mStreamChannel->GetContentDispositionHeader(aContentDispositionHeader); 1.1021 +} 1.1022 + 1.1023 +NS_IMETHODIMP 1.1024 +nsJSChannel::GetContentLength(int64_t *aContentLength) 1.1025 +{ 1.1026 + return mStreamChannel->GetContentLength(aContentLength); 1.1027 +} 1.1028 + 1.1029 +NS_IMETHODIMP 1.1030 +nsJSChannel::SetContentLength(int64_t aContentLength) 1.1031 +{ 1.1032 + return mStreamChannel->SetContentLength(aContentLength); 1.1033 +} 1.1034 + 1.1035 +NS_IMETHODIMP 1.1036 +nsJSChannel::OnStartRequest(nsIRequest* aRequest, 1.1037 + nsISupports* aContext) 1.1038 +{ 1.1039 + NS_ENSURE_TRUE(aRequest == mStreamChannel, NS_ERROR_UNEXPECTED); 1.1040 + 1.1041 + return mListener->OnStartRequest(this, aContext); 1.1042 +} 1.1043 + 1.1044 +NS_IMETHODIMP 1.1045 +nsJSChannel::OnDataAvailable(nsIRequest* aRequest, 1.1046 + nsISupports* aContext, 1.1047 + nsIInputStream* aInputStream, 1.1048 + uint64_t aOffset, 1.1049 + uint32_t aCount) 1.1050 +{ 1.1051 + NS_ENSURE_TRUE(aRequest == mStreamChannel, NS_ERROR_UNEXPECTED); 1.1052 + 1.1053 + return mListener->OnDataAvailable(this, aContext, aInputStream, aOffset, 1.1054 + aCount); 1.1055 +} 1.1056 + 1.1057 +NS_IMETHODIMP 1.1058 +nsJSChannel::OnStopRequest(nsIRequest* aRequest, 1.1059 + nsISupports* aContext, 1.1060 + nsresult aStatus) 1.1061 +{ 1.1062 + NS_ENSURE_TRUE(aRequest == mStreamChannel, NS_ERROR_UNEXPECTED); 1.1063 + 1.1064 + nsCOMPtr<nsIStreamListener> listener = mListener; 1.1065 + 1.1066 + CleanupStrongRefs(); 1.1067 + 1.1068 + // Make sure aStatus matches what GetStatus() returns 1.1069 + if (NS_FAILED(mStatus)) { 1.1070 + aStatus = mStatus; 1.1071 + } 1.1072 + 1.1073 + nsresult rv = listener->OnStopRequest(this, aContext, aStatus); 1.1074 + 1.1075 + nsCOMPtr<nsILoadGroup> loadGroup; 1.1076 + mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup)); 1.1077 + if (loadGroup) { 1.1078 + loadGroup->RemoveRequest(this, nullptr, mStatus); 1.1079 + } 1.1080 + 1.1081 + mIsActive = false; 1.1082 + 1.1083 + return rv; 1.1084 +} 1.1085 + 1.1086 +NS_IMETHODIMP 1.1087 +nsJSChannel::SetExecutionPolicy(uint32_t aPolicy) 1.1088 +{ 1.1089 + NS_ENSURE_ARG(aPolicy <= EXECUTE_NORMAL); 1.1090 + 1.1091 + mExecutionPolicy = aPolicy; 1.1092 + return NS_OK; 1.1093 +} 1.1094 + 1.1095 +NS_IMETHODIMP 1.1096 +nsJSChannel::GetExecutionPolicy(uint32_t* aPolicy) 1.1097 +{ 1.1098 + *aPolicy = mExecutionPolicy; 1.1099 + return NS_OK; 1.1100 +} 1.1101 + 1.1102 +NS_IMETHODIMP 1.1103 +nsJSChannel::SetExecuteAsync(bool aIsAsync) 1.1104 +{ 1.1105 + if (!mIsActive) { 1.1106 + mIsAsync = aIsAsync; 1.1107 + } 1.1108 + // else ignore this call 1.1109 + NS_WARN_IF_FALSE(!mIsActive, "Calling SetExecuteAsync on active channel?"); 1.1110 + 1.1111 + return NS_OK; 1.1112 +} 1.1113 + 1.1114 +NS_IMETHODIMP 1.1115 +nsJSChannel::GetExecuteAsync(bool* aIsAsync) 1.1116 +{ 1.1117 + *aIsAsync = mIsAsync; 1.1118 + return NS_OK; 1.1119 +} 1.1120 + 1.1121 +//////////////////////////////////////////////////////////////////////////////// 1.1122 + 1.1123 +nsJSProtocolHandler::nsJSProtocolHandler() 1.1124 +{ 1.1125 +} 1.1126 + 1.1127 +nsresult 1.1128 +nsJSProtocolHandler::Init() 1.1129 +{ 1.1130 + return NS_OK; 1.1131 +} 1.1132 + 1.1133 +nsJSProtocolHandler::~nsJSProtocolHandler() 1.1134 +{ 1.1135 +} 1.1136 + 1.1137 +NS_IMPL_ISUPPORTS(nsJSProtocolHandler, nsIProtocolHandler) 1.1138 + 1.1139 +nsresult 1.1140 +nsJSProtocolHandler::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) 1.1141 +{ 1.1142 + if (aOuter) 1.1143 + return NS_ERROR_NO_AGGREGATION; 1.1144 + 1.1145 + nsJSProtocolHandler* ph = new nsJSProtocolHandler(); 1.1146 + if (!ph) 1.1147 + return NS_ERROR_OUT_OF_MEMORY; 1.1148 + NS_ADDREF(ph); 1.1149 + nsresult rv = ph->Init(); 1.1150 + if (NS_SUCCEEDED(rv)) { 1.1151 + rv = ph->QueryInterface(aIID, aResult); 1.1152 + } 1.1153 + NS_RELEASE(ph); 1.1154 + return rv; 1.1155 +} 1.1156 + 1.1157 +nsresult 1.1158 +nsJSProtocolHandler::EnsureUTF8Spec(const nsAFlatCString &aSpec, const char *aCharset, 1.1159 + nsACString &aUTF8Spec) 1.1160 +{ 1.1161 + aUTF8Spec.Truncate(); 1.1162 + 1.1163 + nsresult rv; 1.1164 + 1.1165 + if (!mTextToSubURI) { 1.1166 + mTextToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); 1.1167 + NS_ENSURE_SUCCESS(rv, rv); 1.1168 + } 1.1169 + nsAutoString uStr; 1.1170 + rv = mTextToSubURI->UnEscapeNonAsciiURI(nsDependentCString(aCharset), aSpec, uStr); 1.1171 + NS_ENSURE_SUCCESS(rv, rv); 1.1172 + 1.1173 + if (!IsASCII(uStr)) 1.1174 + NS_EscapeURL(NS_ConvertUTF16toUTF8(uStr), esc_AlwaysCopy | esc_OnlyNonASCII, aUTF8Spec); 1.1175 + 1.1176 + return NS_OK; 1.1177 +} 1.1178 + 1.1179 +//////////////////////////////////////////////////////////////////////////////// 1.1180 +// nsIProtocolHandler methods: 1.1181 + 1.1182 +NS_IMETHODIMP 1.1183 +nsJSProtocolHandler::GetScheme(nsACString &result) 1.1184 +{ 1.1185 + result = "javascript"; 1.1186 + return NS_OK; 1.1187 +} 1.1188 + 1.1189 +NS_IMETHODIMP 1.1190 +nsJSProtocolHandler::GetDefaultPort(int32_t *result) 1.1191 +{ 1.1192 + *result = -1; // no port for javascript: URLs 1.1193 + return NS_OK; 1.1194 +} 1.1195 + 1.1196 +NS_IMETHODIMP 1.1197 +nsJSProtocolHandler::GetProtocolFlags(uint32_t *result) 1.1198 +{ 1.1199 + *result = URI_NORELATIVE | URI_NOAUTH | URI_INHERITS_SECURITY_CONTEXT | 1.1200 + URI_LOADABLE_BY_ANYONE | URI_NON_PERSISTABLE | URI_OPENING_EXECUTES_SCRIPT; 1.1201 + return NS_OK; 1.1202 +} 1.1203 + 1.1204 +NS_IMETHODIMP 1.1205 +nsJSProtocolHandler::NewURI(const nsACString &aSpec, 1.1206 + const char *aCharset, 1.1207 + nsIURI *aBaseURI, 1.1208 + nsIURI **result) 1.1209 +{ 1.1210 + nsresult rv; 1.1211 + 1.1212 + // javascript: URLs (currently) have no additional structure beyond that 1.1213 + // provided by standard URLs, so there is no "outer" object given to 1.1214 + // CreateInstance. 1.1215 + 1.1216 + nsCOMPtr<nsIURI> url = new nsJSURI(aBaseURI); 1.1217 + 1.1218 + if (!aCharset || !nsCRT::strcasecmp("UTF-8", aCharset)) 1.1219 + rv = url->SetSpec(aSpec); 1.1220 + else { 1.1221 + nsAutoCString utf8Spec; 1.1222 + rv = EnsureUTF8Spec(PromiseFlatCString(aSpec), aCharset, utf8Spec); 1.1223 + if (NS_SUCCEEDED(rv)) { 1.1224 + if (utf8Spec.IsEmpty()) 1.1225 + rv = url->SetSpec(aSpec); 1.1226 + else 1.1227 + rv = url->SetSpec(utf8Spec); 1.1228 + } 1.1229 + } 1.1230 + 1.1231 + if (NS_FAILED(rv)) { 1.1232 + return rv; 1.1233 + } 1.1234 + 1.1235 + url.forget(result); 1.1236 + return rv; 1.1237 +} 1.1238 + 1.1239 +NS_IMETHODIMP 1.1240 +nsJSProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) 1.1241 +{ 1.1242 + nsresult rv; 1.1243 + nsJSChannel * channel; 1.1244 + 1.1245 + NS_ENSURE_ARG_POINTER(uri); 1.1246 + 1.1247 + channel = new nsJSChannel(); 1.1248 + if (!channel) { 1.1249 + return NS_ERROR_OUT_OF_MEMORY; 1.1250 + } 1.1251 + NS_ADDREF(channel); 1.1252 + 1.1253 + rv = channel->Init(uri); 1.1254 + if (NS_SUCCEEDED(rv)) { 1.1255 + *result = channel; 1.1256 + NS_ADDREF(*result); 1.1257 + } 1.1258 + NS_RELEASE(channel); 1.1259 + return rv; 1.1260 +} 1.1261 + 1.1262 +NS_IMETHODIMP 1.1263 +nsJSProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval) 1.1264 +{ 1.1265 + // don't override anything. 1.1266 + *_retval = false; 1.1267 + return NS_OK; 1.1268 +} 1.1269 + 1.1270 +//////////////////////////////////////////////////////////// 1.1271 +// nsJSURI implementation 1.1272 +static NS_DEFINE_CID(kThisSimpleURIImplementationCID, 1.1273 + NS_THIS_SIMPLEURI_IMPLEMENTATION_CID); 1.1274 + 1.1275 + 1.1276 +NS_IMPL_ADDREF_INHERITED(nsJSURI, nsSimpleURI) 1.1277 +NS_IMPL_RELEASE_INHERITED(nsJSURI, nsSimpleURI) 1.1278 + 1.1279 +NS_INTERFACE_MAP_BEGIN(nsJSURI) 1.1280 + if (aIID.Equals(kJSURICID)) 1.1281 + foundInterface = static_cast<nsIURI*>(this); 1.1282 + else if (aIID.Equals(kThisSimpleURIImplementationCID)) { 1.1283 + // Need to return explicitly here, because if we just set foundInterface 1.1284 + // to null the NS_INTERFACE_MAP_END_INHERITING will end up calling into 1.1285 + // nsSimplURI::QueryInterface and finding something for this CID. 1.1286 + *aInstancePtr = nullptr; 1.1287 + return NS_NOINTERFACE; 1.1288 + } 1.1289 + else 1.1290 +NS_INTERFACE_MAP_END_INHERITING(nsSimpleURI) 1.1291 + 1.1292 +// nsISerializable methods: 1.1293 + 1.1294 +NS_IMETHODIMP 1.1295 +nsJSURI::Read(nsIObjectInputStream* aStream) 1.1296 +{ 1.1297 + nsresult rv = nsSimpleURI::Read(aStream); 1.1298 + if (NS_FAILED(rv)) return rv; 1.1299 + 1.1300 + bool haveBase; 1.1301 + rv = aStream->ReadBoolean(&haveBase); 1.1302 + if (NS_FAILED(rv)) return rv; 1.1303 + 1.1304 + if (haveBase) { 1.1305 + nsCOMPtr<nsISupports> supports; 1.1306 + rv = aStream->ReadObject(true, getter_AddRefs(supports)); 1.1307 + if (NS_FAILED(rv)) return rv; 1.1308 + mBaseURI = do_QueryInterface(supports); 1.1309 + } 1.1310 + 1.1311 + return NS_OK; 1.1312 +} 1.1313 + 1.1314 +NS_IMETHODIMP 1.1315 +nsJSURI::Write(nsIObjectOutputStream* aStream) 1.1316 +{ 1.1317 + nsresult rv = nsSimpleURI::Write(aStream); 1.1318 + if (NS_FAILED(rv)) return rv; 1.1319 + 1.1320 + rv = aStream->WriteBoolean(mBaseURI != nullptr); 1.1321 + if (NS_FAILED(rv)) return rv; 1.1322 + 1.1323 + if (mBaseURI) { 1.1324 + rv = aStream->WriteObject(mBaseURI, true); 1.1325 + if (NS_FAILED(rv)) return rv; 1.1326 + } 1.1327 + 1.1328 + return NS_OK; 1.1329 +} 1.1330 + 1.1331 +// nsSimpleURI methods: 1.1332 +/* virtual */ nsSimpleURI* 1.1333 +nsJSURI::StartClone(nsSimpleURI::RefHandlingEnum /* ignored */) 1.1334 +{ 1.1335 + nsCOMPtr<nsIURI> baseClone; 1.1336 + if (mBaseURI) { 1.1337 + // Note: We preserve ref on *base* URI, regardless of ref handling mode. 1.1338 + nsresult rv = mBaseURI->Clone(getter_AddRefs(baseClone)); 1.1339 + if (NS_FAILED(rv)) { 1.1340 + return nullptr; 1.1341 + } 1.1342 + } 1.1343 + 1.1344 + return new nsJSURI(baseClone); 1.1345 +} 1.1346 + 1.1347 +/* virtual */ nsresult 1.1348 +nsJSURI::EqualsInternal(nsIURI* aOther, 1.1349 + nsSimpleURI::RefHandlingEnum aRefHandlingMode, 1.1350 + bool* aResult) 1.1351 +{ 1.1352 + NS_ENSURE_ARG_POINTER(aOther); 1.1353 + NS_PRECONDITION(aResult, "null pointer for outparam"); 1.1354 + 1.1355 + nsRefPtr<nsJSURI> otherJSURI; 1.1356 + nsresult rv = aOther->QueryInterface(kJSURICID, 1.1357 + getter_AddRefs(otherJSURI)); 1.1358 + if (NS_FAILED(rv)) { 1.1359 + *aResult = false; // aOther is not a nsJSURI --> not equal. 1.1360 + return NS_OK; 1.1361 + } 1.1362 + 1.1363 + // Compare the member data that our base class knows about. 1.1364 + if (!nsSimpleURI::EqualsInternal(otherJSURI, aRefHandlingMode)) { 1.1365 + *aResult = false; 1.1366 + return NS_OK; 1.1367 + } 1.1368 + 1.1369 + // Compare the piece of additional member data that we add to base class. 1.1370 + nsIURI* otherBaseURI = otherJSURI->GetBaseURI(); 1.1371 + 1.1372 + if (mBaseURI) { 1.1373 + // (As noted in StartClone, we always honor refs on mBaseURI) 1.1374 + return mBaseURI->Equals(otherBaseURI, aResult); 1.1375 + } 1.1376 + 1.1377 + *aResult = !otherBaseURI; 1.1378 + return NS_OK; 1.1379 +} 1.1380 + 1.1381 +NS_IMETHODIMP 1.1382 +nsJSURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) 1.1383 +{ 1.1384 + *aClassIDNoAlloc = kJSURICID; 1.1385 + return NS_OK; 1.1386 +} 1.1387 +