Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/jsurl/nsJSProtocolHandler.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* vim: set ts=4 sw=4 et tw=78: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsCOMPtr.h"
8
#include "jsapi.h"
9
#include "js/Wrapper.h"
10
#include "nsCRT.h"
11
#include "nsError.h"
12
#include "nsString.h"
13
#include "nsGlobalWindowInner.h"
14
#include "nsReadableUtils.h"
15
#include "nsJSProtocolHandler.h"
16
#include "nsStringStream.h"
17
#include "nsNetUtil.h"
18
19
#include "nsIStreamListener.h"
20
#include "nsIComponentManager.h"
21
#include "nsIServiceManager.h"
22
#include "nsIURI.h"
23
#include "nsIScriptContext.h"
24
#include "nsIScriptGlobalObject.h"
25
#include "nsIPrincipal.h"
26
#include "nsIScriptSecurityManager.h"
27
#include "nsIInterfaceRequestor.h"
28
#include "nsIInterfaceRequestorUtils.h"
29
#include "nsIWindowMediator.h"
30
#include "nsPIDOMWindow.h"
31
#include "nsIConsoleService.h"
32
#include "nsEscape.h"
33
#include "nsIWebNavigation.h"
34
#include "nsIDocShell.h"
35
#include "nsIContentViewer.h"
36
#include "nsIXPConnect.h"
37
#include "nsContentUtils.h"
38
#include "nsJSUtils.h"
39
#include "nsThreadUtils.h"
40
#include "nsIScriptChannel.h"
41
#include "nsIDocument.h"
42
#include "nsILoadInfo.h"
43
#include "nsIObjectInputStream.h"
44
#include "nsIObjectOutputStream.h"
45
#include "nsIWritablePropertyBag2.h"
46
#include "nsIContentSecurityPolicy.h"
47
#include "nsSandboxFlags.h"
48
#include "mozilla/CycleCollectedJSContext.h"
49
#include "mozilla/dom/ScriptSettings.h"
50
#include "nsILoadInfo.h"
51
#include "nsContentSecurityManager.h"
52
53
#include "mozilla/ipc/URIUtils.h"
54
55
using mozilla::dom::AutoEntryScript;
56
57
static NS_DEFINE_CID(kJSURICID, NS_JSURI_CID);
58
59
class nsJSThunk : public nsIInputStream
60
{
61
public:
62
    nsJSThunk();
63
64
    NS_DECL_THREADSAFE_ISUPPORTS
65
    NS_FORWARD_SAFE_NSIINPUTSTREAM(mInnerStream)
66
67
    nsresult Init(nsIURI* uri);
68
    nsresult EvaluateScript(nsIChannel *aChannel,
69
                            PopupControlState aPopupState,
70
                            uint32_t aExecutionPolicy,
71
                            nsPIDOMWindowInner *aOriginalInnerWindow);
72
73
protected:
74
    virtual ~nsJSThunk();
75
76
    nsCOMPtr<nsIInputStream>    mInnerStream;
77
    nsCString                   mScript;
78
    nsCString                   mURL;
79
};
80
81
//
82
// nsISupports implementation...
83
//
84
NS_IMPL_ISUPPORTS(nsJSThunk, nsIInputStream)
85
86
87
nsJSThunk::nsJSThunk()
88
0
{
89
0
}
90
91
nsJSThunk::~nsJSThunk()
92
0
{
93
0
}
94
95
nsresult nsJSThunk::Init(nsIURI* uri)
96
0
{
97
0
    NS_ENSURE_ARG_POINTER(uri);
98
0
99
0
    // Get the script string to evaluate...
100
0
    nsresult rv = uri->GetPathQueryRef(mScript);
101
0
    if (NS_FAILED(rv)) return rv;
102
0
103
0
    // Get the url.
104
0
    rv = uri->GetSpec(mURL);
105
0
    if (NS_FAILED(rv)) return rv;
106
0
107
0
    return NS_OK;
108
0
}
109
110
static bool
111
IsISO88591(const nsString& aString)
112
0
{
113
0
    for (nsString::const_char_iterator c = aString.BeginReading(),
114
0
                                   c_end = aString.EndReading();
115
0
         c < c_end; ++c) {
116
0
        if (*c > 255)
117
0
            return false;
118
0
    }
119
0
    return true;
120
0
}
121
122
static
123
nsIScriptGlobalObject* GetGlobalObject(nsIChannel* aChannel)
124
0
{
125
0
    // Get the global object owner from the channel
126
0
    nsCOMPtr<nsIDocShell> docShell;
127
0
    NS_QueryNotificationCallbacks(aChannel, docShell);
128
0
    if (!docShell) {
129
0
        NS_WARNING("Unable to get a docShell from the channel!");
130
0
        return nullptr;
131
0
    }
132
0
133
0
    // So far so good: get the script global from its docshell
134
0
    nsIScriptGlobalObject* global = docShell->GetScriptGlobalObject();
135
0
136
0
    NS_ASSERTION(global,
137
0
                 "Unable to get an nsIScriptGlobalObject from the "
138
0
                 "docShell!");
139
0
    return global;
140
0
}
141
142
nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
143
                                   PopupControlState aPopupState,
144
                                   uint32_t aExecutionPolicy,
145
                                   nsPIDOMWindowInner *aOriginalInnerWindow)
146
0
{
147
0
    if (aExecutionPolicy == nsIScriptChannel::NO_EXECUTION) {
148
0
        // Nothing to do here.
149
0
        return NS_ERROR_DOM_RETVAL_UNDEFINED;
150
0
    }
151
0
152
0
    NS_ENSURE_ARG_POINTER(aChannel);
153
0
154
0
    // Get principal of code for execution
155
0
    nsCOMPtr<nsISupports> owner;
156
0
    aChannel->GetOwner(getter_AddRefs(owner));
157
0
    nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(owner);
158
0
    if (!principal) {
159
0
        nsCOMPtr<nsILoadInfo> loadInfo;
160
0
        aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
161
0
        if (loadInfo && loadInfo->GetForceInheritPrincipal()) {
162
0
            principal = loadInfo->FindPrincipalToInherit(aChannel);
163
0
        } else {
164
0
            // No execution without a principal!
165
0
            NS_ASSERTION(!owner, "Non-principal owner?");
166
0
            NS_WARNING("No principal to execute JS with");
167
0
            return NS_ERROR_DOM_RETVAL_UNDEFINED;
168
0
        }
169
0
    }
170
0
171
0
    nsresult rv;
172
0
173
0
    // CSP check: javascript: URIs disabled unless "inline" scripts are
174
0
    // allowed.
175
0
    nsCOMPtr<nsIContentSecurityPolicy> csp;
176
0
    rv = principal->GetCsp(getter_AddRefs(csp));
177
0
    NS_ENSURE_SUCCESS(rv, rv);
178
0
    if (csp) {
179
0
        bool allowsInlineScript = true;
180
0
        rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
181
0
                                  EmptyString(), // aNonce
182
0
                                  true,          // aParserCreated
183
0
                                  nullptr,       // aElement,
184
0
                                  EmptyString(), // aContent
185
0
                                  0,             // aLineNumber
186
0
                                  0,             // aColumnNumber
187
0
                                  &allowsInlineScript);
188
0
189
0
        //return early if inline scripts are not allowed
190
0
        if (!allowsInlineScript) {
191
0
          return NS_ERROR_DOM_RETVAL_UNDEFINED;
192
0
        }
193
0
    }
194
0
195
0
    // Get the global object we should be running on.
196
0
    nsIScriptGlobalObject* global = GetGlobalObject(aChannel);
197
0
    if (!global) {
198
0
        return NS_ERROR_FAILURE;
199
0
    }
200
0
201
0
    // Sandboxed document check: javascript: URI's are disabled
202
0
    // in a sandboxed document unless 'allow-scripts' was specified.
203
0
    nsIDocument* doc = aOriginalInnerWindow->GetExtantDoc();
204
0
    if (doc && doc->HasScriptsBlockedBySandbox()) {
205
0
        return NS_ERROR_DOM_RETVAL_UNDEFINED;
206
0
    }
207
0
208
0
    // Push our popup control state
209
0
    nsAutoPopupStatePusher popupStatePusher(aPopupState);
210
0
211
0
    // Make sure we still have the same inner window as we used to.
212
0
    nsCOMPtr<nsPIDOMWindowOuter> win = do_QueryInterface(global);
213
0
    nsPIDOMWindowInner *innerWin = win->GetCurrentInnerWindow();
214
0
215
0
    if (innerWin != aOriginalInnerWindow) {
216
0
        return NS_ERROR_UNEXPECTED;
217
0
    }
218
0
219
0
    nsCOMPtr<nsIScriptGlobalObject> innerGlobal = do_QueryInterface(innerWin);
220
0
221
0
    mozilla::DebugOnly<nsCOMPtr<nsIDOMWindow>> domWindow(do_QueryInterface(global, &rv));
222
0
    if (NS_FAILED(rv)) {
223
0
        return NS_ERROR_FAILURE;
224
0
    }
225
0
226
0
    // So far so good: get the script context from its owner.
227
0
    nsCOMPtr<nsIScriptContext> scriptContext = global->GetContext();
228
0
    if (!scriptContext)
229
0
        return NS_ERROR_FAILURE;
230
0
231
0
    nsAutoCString script(mScript);
232
0
    // Unescape the script
233
0
    NS_UnescapeURL(script);
234
0
235
0
236
0
    // New script entry point required, due to the "Create a script" step of
237
0
    // http://www.whatwg.org/specs/web-apps/current-work/#javascript-protocol
238
0
    mozilla::nsAutoMicroTask mt;
239
0
    AutoEntryScript aes(innerGlobal, "javascript: URI", true);
240
0
    JSContext* cx = aes.cx();
241
0
    JS::Rooted<JSObject*> globalJSObject(cx, innerGlobal->GetGlobalJSObject());
242
0
    NS_ENSURE_TRUE(globalJSObject, NS_ERROR_UNEXPECTED);
243
0
244
0
    //-- Don't execute unless the script principal subsumes the
245
0
    //   principal of the context.
246
0
    nsIPrincipal* objectPrincipal = nsContentUtils::ObjectPrincipal(globalJSObject);
247
0
248
0
    bool subsumes;
249
0
    rv = principal->Subsumes(objectPrincipal, &subsumes);
250
0
    if (NS_FAILED(rv))
251
0
        return rv;
252
0
253
0
    if (!subsumes) {
254
0
        return NS_ERROR_DOM_RETVAL_UNDEFINED;
255
0
    }
256
0
257
0
    // Fail if someone tries to execute in a global with system principal.
258
0
    if (nsContentUtils::IsSystemPrincipal(objectPrincipal)) {
259
0
        return NS_ERROR_DOM_SECURITY_ERR;
260
0
    }
261
0
262
0
    JS::Rooted<JS::Value> v (cx, JS::UndefinedValue());
263
0
    // Finally, we have everything needed to evaluate the expression.
264
0
    JS::CompileOptions options(cx);
265
0
    options.setFileAndLine(mURL.get(), 1);
266
0
    {
267
0
        nsJSUtils::ExecutionContext exec(cx, globalJSObject);
268
0
        exec.SetCoerceToString(true);
269
0
        exec.CompileAndExec(options, NS_ConvertUTF8toUTF16(script));
270
0
        rv = exec.ExtractReturnValue(&v);
271
0
    }
272
0
273
0
    js::AssertSameCompartment(cx, v);
274
0
275
0
    if (NS_FAILED(rv) || !(v.isString() || v.isUndefined())) {
276
0
        return NS_ERROR_MALFORMED_URI;
277
0
    } else if (v.isUndefined()) {
278
0
        return NS_ERROR_DOM_RETVAL_UNDEFINED;
279
0
    } else {
280
0
        MOZ_ASSERT(rv != NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW,
281
0
                   "How did we get a non-undefined return value?");
282
0
        nsAutoJSString result;
283
0
        if (!result.init(cx, v)) {
284
0
            return NS_ERROR_OUT_OF_MEMORY;
285
0
        }
286
0
287
0
        char *bytes;
288
0
        uint32_t bytesLen;
289
0
        NS_NAMED_LITERAL_CSTRING(isoCharset, "windows-1252");
290
0
        NS_NAMED_LITERAL_CSTRING(utf8Charset, "UTF-8");
291
0
        const nsLiteralCString *charset;
292
0
        if (IsISO88591(result)) {
293
0
            // For compatibility, if the result is ISO-8859-1, we use
294
0
            // windows-1252, so that people can compatibly create images
295
0
            // using javascript: URLs.
296
0
            bytes = ToNewCString(result);
297
0
            bytesLen = result.Length();
298
0
            charset = &isoCharset;
299
0
        }
300
0
        else {
301
0
            bytes = ToNewUTF8String(result, &bytesLen);
302
0
            charset = &utf8Charset;
303
0
        }
304
0
        aChannel->SetContentCharset(*charset);
305
0
        if (bytes)
306
0
            rv = NS_NewByteInputStream(getter_AddRefs(mInnerStream),
307
0
                                       bytes, bytesLen,
308
0
                                       NS_ASSIGNMENT_ADOPT);
309
0
        else
310
0
            rv = NS_ERROR_OUT_OF_MEMORY;
311
0
    }
312
0
313
0
    return rv;
314
0
}
315
316
////////////////////////////////////////////////////////////////////////////////
317
318
class nsJSChannel : public nsIChannel,
319
                    public nsIStreamListener,
320
                    public nsIScriptChannel,
321
                    public nsIPropertyBag2
322
{
323
public:
324
    nsJSChannel();
325
326
    NS_DECL_ISUPPORTS
327
    NS_DECL_NSIREQUEST
328
    NS_DECL_NSICHANNEL
329
    NS_DECL_NSIREQUESTOBSERVER
330
    NS_DECL_NSISTREAMLISTENER
331
    NS_DECL_NSISCRIPTCHANNEL
332
    NS_FORWARD_SAFE_NSIPROPERTYBAG(mPropertyBag)
333
    NS_FORWARD_SAFE_NSIPROPERTYBAG2(mPropertyBag)
334
335
    nsresult Init(nsIURI *aURI, nsILoadInfo* aLoadInfo);
336
337
    // Actually evaluate the script.
338
    void EvaluateScript();
339
340
protected:
341
    virtual ~nsJSChannel();
342
343
    nsresult StopAll();
344
345
    void NotifyListener();
346
347
    void CleanupStrongRefs();
348
349
protected:
350
    nsCOMPtr<nsIChannel>    mStreamChannel;
351
    nsCOMPtr<nsIPropertyBag2> mPropertyBag;
352
    nsCOMPtr<nsIStreamListener> mListener;  // Our final listener
353
    nsCOMPtr<nsPIDOMWindowInner> mOriginalInnerWindow;  // The inner window our load
354
                                                        // started against.
355
    // If we blocked onload on a document in AsyncOpen2, this is the document we
356
    // did it on.
357
    nsCOMPtr<nsIDocument>   mDocumentOnloadBlockedOn;
358
359
    nsresult mStatus; // Our status
360
361
    nsLoadFlags             mLoadFlags;
362
    nsLoadFlags             mActualLoadFlags; // See AsyncOpen2
363
364
    RefPtr<nsJSThunk>     mIOThunk;
365
    PopupControlState       mPopupState;
366
    uint32_t                mExecutionPolicy;
367
    bool                    mIsAsync;
368
    bool                    mIsActive;
369
    bool                    mOpenedStreamChannel;
370
};
371
372
nsJSChannel::nsJSChannel() :
373
    mStatus(NS_OK),
374
    mLoadFlags(LOAD_NORMAL),
375
    mActualLoadFlags(LOAD_NORMAL),
376
    mPopupState(openOverridden),
377
    mExecutionPolicy(NO_EXECUTION),
378
    mIsAsync(true),
379
    mIsActive(false),
380
    mOpenedStreamChannel(false)
381
0
{
382
0
}
383
384
nsJSChannel::~nsJSChannel()
385
0
{
386
0
}
387
388
nsresult nsJSChannel::StopAll()
389
0
{
390
0
    nsresult rv = NS_ERROR_UNEXPECTED;
391
0
    nsCOMPtr<nsIWebNavigation> webNav;
392
0
    NS_QueryNotificationCallbacks(mStreamChannel, webNav);
393
0
394
0
    NS_ASSERTION(webNav, "Can't get nsIWebNavigation from channel!");
395
0
    if (webNav) {
396
0
        rv = webNav->Stop(nsIWebNavigation::STOP_ALL);
397
0
    }
398
0
399
0
    return rv;
400
0
}
401
402
nsresult nsJSChannel::Init(nsIURI* aURI, nsILoadInfo* aLoadInfo)
403
0
{
404
0
    RefPtr<nsJSURI> jsURI;
405
0
    nsresult rv = aURI->QueryInterface(kJSURICID,
406
0
                                       getter_AddRefs(jsURI));
407
0
    NS_ENSURE_SUCCESS(rv, rv);
408
0
409
0
    // Create the nsIStreamIO layer used by the nsIStreamIOChannel.
410
0
    mIOThunk = new nsJSThunk();
411
0
412
0
    // Create a stock input stream channel...
413
0
    // Remember, until AsyncOpen is called, the script will not be evaluated
414
0
    // and the underlying Input Stream will not be created...
415
0
    nsCOMPtr<nsIChannel> channel;
416
0
    RefPtr<nsJSThunk> thunk = mIOThunk;
417
0
    rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
418
0
                                          aURI,
419
0
                                          thunk.forget(),
420
0
                                          NS_LITERAL_CSTRING("text/html"),
421
0
                                          EmptyCString(),
422
0
                                          aLoadInfo);
423
0
    NS_ENSURE_SUCCESS(rv, rv);
424
0
425
0
    rv = mIOThunk->Init(aURI);
426
0
    if (NS_SUCCEEDED(rv)) {
427
0
        mStreamChannel = channel;
428
0
        mPropertyBag = do_QueryInterface(channel);
429
0
        nsCOMPtr<nsIWritablePropertyBag2> writableBag =
430
0
            do_QueryInterface(channel);
431
0
        if (writableBag && jsURI->GetBaseURI()) {
432
0
            writableBag->SetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
433
0
                                                jsURI->GetBaseURI());
434
0
        }
435
0
    }
436
0
437
0
    return rv;
438
0
}
439
440
NS_IMETHODIMP
441
nsJSChannel::GetIsDocument(bool *aIsDocument)
442
0
{
443
0
  return NS_GetIsDocumentChannel(this, aIsDocument);
444
0
}
445
446
//
447
// nsISupports implementation...
448
//
449
450
NS_IMPL_ISUPPORTS(nsJSChannel, nsIChannel, nsIRequest, nsIRequestObserver,
451
                  nsIStreamListener, nsIScriptChannel, nsIPropertyBag,
452
                  nsIPropertyBag2)
453
454
//
455
// nsIRequest implementation...
456
//
457
458
NS_IMETHODIMP
459
nsJSChannel::GetName(nsACString &aResult)
460
0
{
461
0
    return mStreamChannel->GetName(aResult);
462
0
}
463
464
NS_IMETHODIMP
465
nsJSChannel::IsPending(bool *aResult)
466
0
{
467
0
    *aResult = mIsActive;
468
0
    return NS_OK;
469
0
}
470
471
NS_IMETHODIMP
472
nsJSChannel::GetStatus(nsresult *aResult)
473
0
{
474
0
    if (NS_SUCCEEDED(mStatus) && mOpenedStreamChannel) {
475
0
        return mStreamChannel->GetStatus(aResult);
476
0
    }
477
0
478
0
    *aResult = mStatus;
479
0
480
0
    return NS_OK;
481
0
}
482
483
NS_IMETHODIMP
484
nsJSChannel::Cancel(nsresult aStatus)
485
0
{
486
0
    mStatus = aStatus;
487
0
488
0
    if (mOpenedStreamChannel) {
489
0
        mStreamChannel->Cancel(aStatus);
490
0
    }
491
0
492
0
    return NS_OK;
493
0
}
494
495
NS_IMETHODIMP
496
nsJSChannel::Suspend()
497
0
{
498
0
    return mStreamChannel->Suspend();
499
0
}
500
501
NS_IMETHODIMP
502
nsJSChannel::Resume()
503
0
{
504
0
    return mStreamChannel->Resume();
505
0
}
506
507
//
508
// nsIChannel implementation
509
//
510
511
NS_IMETHODIMP
512
nsJSChannel::GetOriginalURI(nsIURI * *aURI)
513
0
{
514
0
    return mStreamChannel->GetOriginalURI(aURI);
515
0
}
516
517
NS_IMETHODIMP
518
nsJSChannel::SetOriginalURI(nsIURI *aURI)
519
0
{
520
0
    return mStreamChannel->SetOriginalURI(aURI);
521
0
}
522
523
NS_IMETHODIMP
524
nsJSChannel::GetURI(nsIURI * *aURI)
525
0
{
526
0
    return mStreamChannel->GetURI(aURI);
527
0
}
528
529
NS_IMETHODIMP
530
nsJSChannel::Open(nsIInputStream **aResult)
531
0
{
532
0
    nsresult rv = mIOThunk->EvaluateScript(mStreamChannel, mPopupState,
533
0
                                           mExecutionPolicy,
534
0
                                           mOriginalInnerWindow);
535
0
    NS_ENSURE_SUCCESS(rv, rv);
536
0
537
0
    return mStreamChannel->Open(aResult);
538
0
}
539
540
NS_IMETHODIMP
541
nsJSChannel::Open2(nsIInputStream** aStream)
542
0
{
543
0
    nsCOMPtr<nsIStreamListener> listener;
544
0
    nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
545
0
    NS_ENSURE_SUCCESS(rv, rv);
546
0
    return Open(aStream);
547
0
}
548
549
NS_IMETHODIMP
550
nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
551
0
{
552
#ifdef DEBUG
553
    {
554
    nsCOMPtr<nsILoadInfo> loadInfo = nsIChannel::GetLoadInfo();
555
    MOZ_ASSERT(!loadInfo || loadInfo->GetSecurityMode() == 0 ||
556
               loadInfo->GetInitialSecurityCheckDone(),
557
               "security flags in loadInfo but asyncOpen2() not called");
558
    }
559
#endif
560
0
    MOZ_RELEASE_ASSERT(!aContext, "please call AsyncOpen2()");
561
0
562
0
    NS_ENSURE_ARG(aListener);
563
0
564
0
    // First make sure that we have a usable inner window; we'll want to make
565
0
    // sure that we execute against that inner and no other.
566
0
    nsIScriptGlobalObject* global = GetGlobalObject(this);
567
0
    if (!global) {
568
0
        return NS_ERROR_NOT_AVAILABLE;
569
0
    }
570
0
571
0
    nsCOMPtr<nsPIDOMWindowOuter> win(do_QueryInterface(global));
572
0
    NS_ASSERTION(win, "Our global is not a window??");
573
0
574
0
    // Make sure we create a new inner window if one doesn't already exist (see
575
0
    // bug 306630).
576
0
    mOriginalInnerWindow = win->EnsureInnerWindow();
577
0
    if (!mOriginalInnerWindow) {
578
0
        return NS_ERROR_NOT_AVAILABLE;
579
0
    }
580
0
581
0
    mListener = aListener;
582
0
583
0
    mIsActive = true;
584
0
585
0
    // Temporarily set the LOAD_BACKGROUND flag to suppress load group observer
586
0
    // notifications (and hence nsIWebProgressListener notifications) from
587
0
    // being dispatched.  This is required since we suppress LOAD_DOCUMENT_URI,
588
0
    // which means that the DocLoader would not generate document start and
589
0
    // stop notifications (see bug 257875).
590
0
    mActualLoadFlags = mLoadFlags;
591
0
    mLoadFlags |= LOAD_BACKGROUND;
592
0
593
0
    // Add the javascript channel to its loadgroup so that we know if
594
0
    // network loads were canceled or not...
595
0
    nsCOMPtr<nsILoadGroup> loadGroup;
596
0
    mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup));
597
0
    if (loadGroup) {
598
0
        nsresult rv = loadGroup->AddRequest(this, nullptr);
599
0
        if (NS_FAILED(rv)) {
600
0
            mIsActive = false;
601
0
            CleanupStrongRefs();
602
0
            return rv;
603
0
        }
604
0
    }
605
0
606
0
    mDocumentOnloadBlockedOn = mOriginalInnerWindow->GetExtantDoc();
607
0
    if (mDocumentOnloadBlockedOn) {
608
0
        // If we're a document channel, we need to actually block onload on our
609
0
        // _parent_ document.  This is because we don't actually set our
610
0
        // LOAD_DOCUMENT_URI flag, so a docloader we're loading in as the
611
0
        // document channel will claim to not be busy, and our parent's onload
612
0
        // could fire too early.
613
0
        nsLoadFlags loadFlags;
614
0
        mStreamChannel->GetLoadFlags(&loadFlags);
615
0
        if (loadFlags & LOAD_DOCUMENT_URI) {
616
0
            mDocumentOnloadBlockedOn =
617
0
                mDocumentOnloadBlockedOn->GetParentDocument();
618
0
        }
619
0
    }
620
0
    if (mDocumentOnloadBlockedOn) {
621
0
        mDocumentOnloadBlockedOn->BlockOnload();
622
0
    }
623
0
624
0
625
0
    mPopupState = win->GetPopupControlState();
626
0
627
0
    void (nsJSChannel::*method)();
628
0
    const char* name;
629
0
    if (mIsAsync) {
630
0
        // post an event to do the rest
631
0
        method = &nsJSChannel::EvaluateScript;
632
0
        name = "nsJSChannel::EvaluateScript";
633
0
    } else {
634
0
        EvaluateScript();
635
0
        if (mOpenedStreamChannel) {
636
0
            // That will handle notifying things
637
0
            return NS_OK;
638
0
        }
639
0
640
0
        NS_ASSERTION(NS_FAILED(mStatus), "We should have failed _somehow_");
641
0
642
0
        // mStatus is going to be NS_ERROR_DOM_RETVAL_UNDEFINED if we didn't
643
0
        // have any content resulting from the execution and NS_BINDING_ABORTED
644
0
        // if something we did causes our own load to be stopped.  Return
645
0
        // success in those cases, and error out in all others.
646
0
        if (mStatus != NS_ERROR_DOM_RETVAL_UNDEFINED &&
647
0
            mStatus != NS_BINDING_ABORTED) {
648
0
            // Note that calling EvaluateScript() handled removing us from the
649
0
            // loadgroup and marking us as not active anymore.
650
0
            CleanupStrongRefs();
651
0
            return mStatus;
652
0
        }
653
0
654
0
        // We're returning success from asyncOpen2(), but we didn't open a
655
0
        // stream channel.  We'll have to notify ourselves, but make sure to do
656
0
        // it asynchronously.
657
0
        method = &nsJSChannel::NotifyListener;
658
0
        name = "nsJSChannel::NotifyListener";
659
0
    }
660
0
661
0
    nsCOMPtr<nsIRunnable> runnable = mozilla::NewRunnableMethod(name, this, method);
662
0
    nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(mOriginalInnerWindow);
663
0
    nsresult rv = window->Dispatch(mozilla::TaskCategory::Other, runnable.forget());
664
0
665
0
    if (NS_FAILED(rv)) {
666
0
        loadGroup->RemoveRequest(this, nullptr, rv);
667
0
        mIsActive = false;
668
0
        CleanupStrongRefs();
669
0
    }
670
0
    return rv;
671
0
}
672
673
NS_IMETHODIMP
674
nsJSChannel::AsyncOpen2(nsIStreamListener *aListener)
675
0
{
676
0
  nsCOMPtr<nsIStreamListener> listener = aListener;
677
0
  nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
678
0
  NS_ENSURE_SUCCESS(rv, rv);
679
0
  return AsyncOpen(listener, nullptr);
680
0
}
681
682
void
683
nsJSChannel::EvaluateScript()
684
0
{
685
0
    // Synchronously execute the script...
686
0
    // mIsActive is used to indicate the the request is 'busy' during the
687
0
    // the script evaluation phase.  This means that IsPending() will
688
0
    // indicate the the request is busy while the script is executing...
689
0
690
0
    // Note that we want to be in the loadgroup and pending while we evaluate
691
0
    // the script, so that we find out if the loadgroup gets canceled by the
692
0
    // script execution (in which case we shouldn't pump out data even if the
693
0
    // script returns it).
694
0
695
0
    if (NS_SUCCEEDED(mStatus)) {
696
0
        nsresult rv = mIOThunk->EvaluateScript(mStreamChannel, mPopupState,
697
0
                                               mExecutionPolicy,
698
0
                                               mOriginalInnerWindow);
699
0
700
0
        // Note that evaluation may have canceled us, so recheck mStatus again
701
0
        if (NS_FAILED(rv) && NS_SUCCEEDED(mStatus)) {
702
0
            mStatus = rv;
703
0
        }
704
0
    }
705
0
706
0
    // Remove the javascript channel from its loadgroup...
707
0
    nsCOMPtr<nsILoadGroup> loadGroup;
708
0
    mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup));
709
0
    if (loadGroup) {
710
0
        loadGroup->RemoveRequest(this, nullptr, mStatus);
711
0
    }
712
0
713
0
    // Reset load flags to their original value...
714
0
    mLoadFlags = mActualLoadFlags;
715
0
716
0
    // We're no longer active, it's now up to the stream channel to do
717
0
    // the loading, if needed.
718
0
    mIsActive = false;
719
0
720
0
    if (NS_FAILED(mStatus)) {
721
0
        if (mIsAsync) {
722
0
            NotifyListener();
723
0
        }
724
0
        return;
725
0
    }
726
0
727
0
    // EvaluateScript() succeeded, and we were not canceled, that
728
0
    // means there's data to parse as a result of evaluating the
729
0
    // script.
730
0
731
0
    // Get the stream channels load flags (!= mLoadFlags).
732
0
    nsLoadFlags loadFlags;
733
0
    mStreamChannel->GetLoadFlags(&loadFlags);
734
0
735
0
    uint32_t disposition;
736
0
    if (NS_FAILED(mStreamChannel->GetContentDisposition(&disposition)))
737
0
        disposition = nsIChannel::DISPOSITION_INLINE;
738
0
    if (loadFlags & LOAD_DOCUMENT_URI && disposition != nsIChannel::DISPOSITION_ATTACHMENT) {
739
0
        // We're loaded as the document channel and not expecting to download
740
0
        // the result. If we go on, we'll blow away the current document. Make
741
0
        // sure that's ok. If so, stop all pending network loads.
742
0
743
0
        nsCOMPtr<nsIDocShell> docShell;
744
0
        NS_QueryNotificationCallbacks(mStreamChannel, docShell);
745
0
        if (docShell) {
746
0
            nsCOMPtr<nsIContentViewer> cv;
747
0
            docShell->GetContentViewer(getter_AddRefs(cv));
748
0
749
0
            if (cv) {
750
0
                bool okToUnload;
751
0
752
0
                if (NS_SUCCEEDED(cv->PermitUnload(&okToUnload)) &&
753
0
                    !okToUnload) {
754
0
                    // The user didn't want to unload the current
755
0
                    // page, translate this into an undefined
756
0
                    // return from the javascript: URL...
757
0
                    mStatus = NS_ERROR_DOM_RETVAL_UNDEFINED;
758
0
                }
759
0
            }
760
0
        }
761
0
762
0
        if (NS_SUCCEEDED(mStatus)) {
763
0
            mStatus = StopAll();
764
0
        }
765
0
    }
766
0
767
0
    if (NS_FAILED(mStatus)) {
768
0
        if (mIsAsync) {
769
0
            NotifyListener();
770
0
        }
771
0
        return;
772
0
    }
773
0
774
0
    mStatus = mStreamChannel->AsyncOpen2(this);
775
0
    if (NS_SUCCEEDED(mStatus)) {
776
0
        // mStreamChannel will call OnStartRequest and OnStopRequest on
777
0
        // us, so we'll be sure to call them on our listener.
778
0
        mOpenedStreamChannel = true;
779
0
780
0
        // Now readd ourselves to the loadgroup so we can receive
781
0
        // cancellation notifications.
782
0
        mIsActive = true;
783
0
        if (loadGroup) {
784
0
            mStatus = loadGroup->AddRequest(this, nullptr);
785
0
786
0
            // If AddRequest failed, that's OK.  The key is to make sure we get
787
0
            // cancelled if needed, and that call just canceled us if it
788
0
            // failed.  We'll still get notified by the stream channel when it
789
0
            // finishes.
790
0
        }
791
0
792
0
    } else if (mIsAsync) {
793
0
        NotifyListener();
794
0
    }
795
0
}
796
797
void
798
nsJSChannel::NotifyListener()
799
0
{
800
0
    mListener->OnStartRequest(this, nullptr);
801
0
    mListener->OnStopRequest(this, nullptr, mStatus);
802
0
803
0
    CleanupStrongRefs();
804
0
}
805
806
void
807
nsJSChannel::CleanupStrongRefs()
808
0
{
809
0
    mListener = nullptr;
810
0
    mOriginalInnerWindow = nullptr;
811
0
    if (mDocumentOnloadBlockedOn) {
812
0
        mDocumentOnloadBlockedOn->UnblockOnload(false);
813
0
        mDocumentOnloadBlockedOn = nullptr;
814
0
    }
815
0
}
816
817
NS_IMETHODIMP
818
nsJSChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
819
0
{
820
0
    *aLoadFlags = mLoadFlags;
821
0
822
0
    return NS_OK;
823
0
}
824
825
NS_IMETHODIMP
826
nsJSChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
827
0
{
828
0
    // Figure out whether the LOAD_BACKGROUND bit in aLoadFlags is
829
0
    // actually right.
830
0
    bool bogusLoadBackground = false;
831
0
    if (mIsActive && !(mActualLoadFlags & LOAD_BACKGROUND) &&
832
0
        (aLoadFlags & LOAD_BACKGROUND)) {
833
0
        // We're getting a LOAD_BACKGROUND, but it's probably just our own fake
834
0
        // flag being mirrored to us.  The one exception is if our loadgroup is
835
0
        // LOAD_BACKGROUND.
836
0
        bool loadGroupIsBackground = false;
837
0
        nsCOMPtr<nsILoadGroup> loadGroup;
838
0
        mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup));
839
0
        if (loadGroup) {
840
0
            nsLoadFlags loadGroupFlags;
841
0
            loadGroup->GetLoadFlags(&loadGroupFlags);
842
0
            loadGroupIsBackground = ((loadGroupFlags & LOAD_BACKGROUND) != 0);
843
0
        }
844
0
        bogusLoadBackground = !loadGroupIsBackground;
845
0
    }
846
0
847
0
    // Classifying a javascript: URI doesn't help us, and requires
848
0
    // NSS to boot, which we don't have in content processes.  See
849
0
    // https://bugzilla.mozilla.org/show_bug.cgi?id=617838.
850
0
    aLoadFlags &= ~LOAD_CLASSIFY_URI;
851
0
852
0
    // Since the javascript channel is never the actual channel that
853
0
    // any data is loaded through, don't ever set the
854
0
    // LOAD_DOCUMENT_URI flag on it, since that could lead to two
855
0
    // 'document channels' in the loadgroup if a javascript: URL is
856
0
    // loaded while a document is being loaded in the same window.
857
0
858
0
    // XXXbz this, and a whole lot of other hackery, could go away if we'd just
859
0
    // cancel the current document load on javascript: load start like IE does.
860
0
861
0
    mLoadFlags = aLoadFlags & ~LOAD_DOCUMENT_URI;
862
0
863
0
    if (bogusLoadBackground) {
864
0
        aLoadFlags = aLoadFlags & ~LOAD_BACKGROUND;
865
0
    }
866
0
867
0
    mActualLoadFlags = aLoadFlags;
868
0
869
0
    // ... but the underlying stream channel should get this bit, if
870
0
    // set, since that'll be the real document channel if the
871
0
    // javascript: URL generated data.
872
0
873
0
    return mStreamChannel->SetLoadFlags(aLoadFlags);
874
0
}
875
876
NS_IMETHODIMP
877
nsJSChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
878
0
{
879
0
    return mStreamChannel->GetLoadGroup(aLoadGroup);
880
0
}
881
882
NS_IMETHODIMP
883
nsJSChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
884
0
{
885
0
    if (aLoadGroup) {
886
0
        bool streamPending;
887
0
        nsresult rv = mStreamChannel->IsPending(&streamPending);
888
0
        NS_ENSURE_SUCCESS(rv, rv);
889
0
890
0
        if (streamPending) {
891
0
            nsCOMPtr<nsILoadGroup> curLoadGroup;
892
0
            mStreamChannel->GetLoadGroup(getter_AddRefs(curLoadGroup));
893
0
894
0
            if (aLoadGroup != curLoadGroup) {
895
0
                // Move the stream channel to our new loadgroup.  Make sure to
896
0
                // add it before removing it, so that we don't trigger onload
897
0
                // by accident.
898
0
                aLoadGroup->AddRequest(mStreamChannel, nullptr);
899
0
                if (curLoadGroup) {
900
0
                    curLoadGroup->RemoveRequest(mStreamChannel, nullptr,
901
0
                                                NS_BINDING_RETARGETED);
902
0
                }
903
0
            }
904
0
        }
905
0
    }
906
0
907
0
    return mStreamChannel->SetLoadGroup(aLoadGroup);
908
0
}
909
910
NS_IMETHODIMP
911
nsJSChannel::GetOwner(nsISupports* *aOwner)
912
0
{
913
0
    return mStreamChannel->GetOwner(aOwner);
914
0
}
915
916
NS_IMETHODIMP
917
nsJSChannel::SetOwner(nsISupports* aOwner)
918
0
{
919
0
    return mStreamChannel->SetOwner(aOwner);
920
0
}
921
922
NS_IMETHODIMP
923
nsJSChannel::GetLoadInfo(nsILoadInfo* *aLoadInfo)
924
0
{
925
0
    return mStreamChannel->GetLoadInfo(aLoadInfo);
926
0
}
927
928
NS_IMETHODIMP
929
nsJSChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
930
0
{
931
0
    return mStreamChannel->SetLoadInfo(aLoadInfo);
932
0
}
933
934
NS_IMETHODIMP
935
nsJSChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
936
0
{
937
0
    return mStreamChannel->GetNotificationCallbacks(aCallbacks);
938
0
}
939
940
NS_IMETHODIMP
941
nsJSChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
942
0
{
943
0
    return mStreamChannel->SetNotificationCallbacks(aCallbacks);
944
0
}
945
946
NS_IMETHODIMP
947
nsJSChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
948
0
{
949
0
    return mStreamChannel->GetSecurityInfo(aSecurityInfo);
950
0
}
951
952
NS_IMETHODIMP
953
nsJSChannel::GetContentType(nsACString &aContentType)
954
0
{
955
0
    return mStreamChannel->GetContentType(aContentType);
956
0
}
957
958
NS_IMETHODIMP
959
nsJSChannel::SetContentType(const nsACString &aContentType)
960
0
{
961
0
    return mStreamChannel->SetContentType(aContentType);
962
0
}
963
964
NS_IMETHODIMP
965
nsJSChannel::GetContentCharset(nsACString &aContentCharset)
966
0
{
967
0
    return mStreamChannel->GetContentCharset(aContentCharset);
968
0
}
969
970
NS_IMETHODIMP
971
nsJSChannel::SetContentCharset(const nsACString &aContentCharset)
972
0
{
973
0
    return mStreamChannel->SetContentCharset(aContentCharset);
974
0
}
975
976
NS_IMETHODIMP
977
nsJSChannel::GetContentDisposition(uint32_t *aContentDisposition)
978
0
{
979
0
    return mStreamChannel->GetContentDisposition(aContentDisposition);
980
0
}
981
982
NS_IMETHODIMP
983
nsJSChannel::SetContentDisposition(uint32_t aContentDisposition)
984
0
{
985
0
    return mStreamChannel->SetContentDisposition(aContentDisposition);
986
0
}
987
988
NS_IMETHODIMP
989
nsJSChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
990
0
{
991
0
    return mStreamChannel->GetContentDispositionFilename(aContentDispositionFilename);
992
0
}
993
994
NS_IMETHODIMP
995
nsJSChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
996
0
{
997
0
    return mStreamChannel->SetContentDispositionFilename(aContentDispositionFilename);
998
0
}
999
1000
NS_IMETHODIMP
1001
nsJSChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
1002
0
{
1003
0
    return mStreamChannel->GetContentDispositionHeader(aContentDispositionHeader);
1004
0
}
1005
1006
NS_IMETHODIMP
1007
nsJSChannel::GetContentLength(int64_t *aContentLength)
1008
0
{
1009
0
    return mStreamChannel->GetContentLength(aContentLength);
1010
0
}
1011
1012
NS_IMETHODIMP
1013
nsJSChannel::SetContentLength(int64_t aContentLength)
1014
0
{
1015
0
    return mStreamChannel->SetContentLength(aContentLength);
1016
0
}
1017
1018
NS_IMETHODIMP
1019
nsJSChannel::OnStartRequest(nsIRequest* aRequest,
1020
                            nsISupports* aContext)
1021
0
{
1022
0
    NS_ENSURE_TRUE(aRequest == mStreamChannel, NS_ERROR_UNEXPECTED);
1023
0
1024
0
    return mListener->OnStartRequest(this, aContext);
1025
0
}
1026
1027
NS_IMETHODIMP
1028
nsJSChannel::OnDataAvailable(nsIRequest* aRequest,
1029
                             nsISupports* aContext,
1030
                             nsIInputStream* aInputStream,
1031
                             uint64_t aOffset,
1032
                             uint32_t aCount)
1033
0
{
1034
0
    NS_ENSURE_TRUE(aRequest == mStreamChannel, NS_ERROR_UNEXPECTED);
1035
0
1036
0
    return mListener->OnDataAvailable(this, aContext, aInputStream, aOffset,
1037
0
                                      aCount);
1038
0
}
1039
1040
NS_IMETHODIMP
1041
nsJSChannel::OnStopRequest(nsIRequest* aRequest,
1042
                           nsISupports* aContext,
1043
                           nsresult aStatus)
1044
0
{
1045
0
    NS_ENSURE_TRUE(aRequest == mStreamChannel, NS_ERROR_UNEXPECTED);
1046
0
1047
0
    nsCOMPtr<nsIStreamListener> listener = mListener;
1048
0
1049
0
    CleanupStrongRefs();
1050
0
1051
0
    // Make sure aStatus matches what GetStatus() returns
1052
0
    if (NS_FAILED(mStatus)) {
1053
0
        aStatus = mStatus;
1054
0
    }
1055
0
1056
0
    nsresult rv = listener->OnStopRequest(this, aContext, aStatus);
1057
0
1058
0
    nsCOMPtr<nsILoadGroup> loadGroup;
1059
0
    mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup));
1060
0
    if (loadGroup) {
1061
0
        loadGroup->RemoveRequest(this, nullptr, mStatus);
1062
0
    }
1063
0
1064
0
    mIsActive = false;
1065
0
1066
0
    return rv;
1067
0
}
1068
1069
NS_IMETHODIMP
1070
nsJSChannel::SetExecutionPolicy(uint32_t aPolicy)
1071
0
{
1072
0
    NS_ENSURE_ARG(aPolicy <= EXECUTE_NORMAL);
1073
0
1074
0
    mExecutionPolicy = aPolicy;
1075
0
    return NS_OK;
1076
0
}
1077
1078
NS_IMETHODIMP
1079
nsJSChannel::GetExecutionPolicy(uint32_t* aPolicy)
1080
0
{
1081
0
    *aPolicy = mExecutionPolicy;
1082
0
    return NS_OK;
1083
0
}
1084
1085
NS_IMETHODIMP
1086
nsJSChannel::SetExecuteAsync(bool aIsAsync)
1087
0
{
1088
0
    if (!mIsActive) {
1089
0
        mIsAsync = aIsAsync;
1090
0
    }
1091
0
    // else ignore this call
1092
0
    NS_WARNING_ASSERTION(!mIsActive,
1093
0
                         "Calling SetExecuteAsync on active channel?");
1094
0
1095
0
    return NS_OK;
1096
0
}
1097
1098
NS_IMETHODIMP
1099
nsJSChannel::GetExecuteAsync(bool* aIsAsync)
1100
0
{
1101
0
    *aIsAsync = mIsAsync;
1102
0
    return NS_OK;
1103
0
}
1104
1105
////////////////////////////////////////////////////////////////////////////////
1106
1107
nsJSProtocolHandler::nsJSProtocolHandler()
1108
1
{
1109
1
}
1110
1111
nsresult
1112
nsJSProtocolHandler::Init()
1113
1
{
1114
1
    return NS_OK;
1115
1
}
1116
1117
nsJSProtocolHandler::~nsJSProtocolHandler()
1118
0
{
1119
0
}
1120
1121
NS_IMPL_ISUPPORTS(nsJSProtocolHandler, nsIProtocolHandler)
1122
1123
nsresult
1124
nsJSProtocolHandler::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
1125
1
{
1126
1
    if (aOuter)
1127
0
        return NS_ERROR_NO_AGGREGATION;
1128
1
1129
1
    nsJSProtocolHandler* ph = new nsJSProtocolHandler();
1130
1
    NS_ADDREF(ph);
1131
1
    nsresult rv = ph->Init();
1132
1
    if (NS_SUCCEEDED(rv)) {
1133
1
        rv = ph->QueryInterface(aIID, aResult);
1134
1
    }
1135
1
    NS_RELEASE(ph);
1136
1
    return rv;
1137
1
}
1138
1139
nsresult
1140
nsJSProtocolHandler::EnsureUTF8Spec(const nsCString& aSpec, const char *aCharset,
1141
                                    nsACString &aUTF8Spec)
1142
1.79k
{
1143
1.79k
  aUTF8Spec.Truncate();
1144
1.79k
1145
1.79k
  nsresult rv;
1146
1.79k
1147
1.79k
  if (!mTextToSubURI) {
1148
1
    mTextToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
1149
1
    NS_ENSURE_SUCCESS(rv, rv);
1150
1
  }
1151
1.79k
  nsAutoString uStr;
1152
1.79k
  rv = mTextToSubURI->UnEscapeNonAsciiURI(nsDependentCString(aCharset), aSpec, uStr);
1153
1.79k
  NS_ENSURE_SUCCESS(rv, rv);
1154
1.79k
1155
1.79k
  if (!IsASCII(uStr)) {
1156
272
    rv = NS_EscapeURL(NS_ConvertUTF16toUTF8(uStr),
1157
272
                      esc_AlwaysCopy | esc_OnlyNonASCII, aUTF8Spec,
1158
272
                      mozilla::fallible);
1159
272
    NS_ENSURE_SUCCESS(rv, rv);
1160
272
  }
1161
768
1162
768
  return NS_OK;
1163
768
}
1164
1165
////////////////////////////////////////////////////////////////////////////////
1166
// nsIProtocolHandler methods:
1167
1168
NS_IMETHODIMP
1169
nsJSProtocolHandler::GetScheme(nsACString &result)
1170
0
{
1171
0
    result = "javascript";
1172
0
    return NS_OK;
1173
0
}
1174
1175
NS_IMETHODIMP
1176
nsJSProtocolHandler::GetDefaultPort(int32_t *result)
1177
0
{
1178
0
    *result = -1;        // no port for javascript: URLs
1179
0
    return NS_OK;
1180
0
}
1181
1182
NS_IMETHODIMP
1183
nsJSProtocolHandler::GetProtocolFlags(uint32_t *result)
1184
0
{
1185
0
    *result = URI_NORELATIVE | URI_NOAUTH | URI_INHERITS_SECURITY_CONTEXT |
1186
0
        URI_LOADABLE_BY_ANYONE | URI_NON_PERSISTABLE | URI_OPENING_EXECUTES_SCRIPT;
1187
0
    return NS_OK;
1188
0
}
1189
1190
NS_IMETHODIMP
1191
nsJSProtocolHandler::NewURI(const nsACString &aSpec,
1192
                            const char *aCharset,
1193
                            nsIURI *aBaseURI,
1194
                            nsIURI **result)
1195
1.79k
{
1196
1.79k
    nsresult rv = NS_OK;
1197
1.79k
1198
1.79k
    // javascript: URLs (currently) have no additional structure beyond that
1199
1.79k
    // provided by standard URLs, so there is no "outer" object given to
1200
1.79k
    // CreateInstance.
1201
1.79k
1202
1.79k
    NS_MutateURI mutator(new nsJSURI::Mutator());
1203
1.79k
    nsCOMPtr<nsIURI> base(aBaseURI);
1204
1.79k
    mutator.Apply(NS_MutatorMethod(&nsIJSURIMutator::SetBase, base));
1205
1.79k
    if (!aCharset || !nsCRT::strcasecmp("UTF-8", aCharset)) {
1206
0
        mutator.SetSpec(aSpec);
1207
1.79k
    } else {
1208
1.79k
        nsAutoCString utf8Spec;
1209
1.79k
        rv = EnsureUTF8Spec(PromiseFlatCString(aSpec), aCharset, utf8Spec);
1210
1.79k
        if (NS_FAILED(rv)) {
1211
1.03k
            return rv;
1212
1.03k
        }
1213
768
        if (utf8Spec.IsEmpty()) {
1214
496
            mutator.SetSpec(aSpec);
1215
496
        } else {
1216
272
            mutator.SetSpec(utf8Spec);
1217
272
        }
1218
768
    }
1219
1.79k
1220
1.79k
    nsCOMPtr<nsIURI> url;
1221
768
    rv = mutator.Finalize(url);
1222
768
    if (NS_FAILED(rv)) {
1223
91
        return rv;
1224
91
    }
1225
677
1226
677
    url.forget(result);
1227
677
    return rv;
1228
677
}
1229
1230
NS_IMETHODIMP
1231
nsJSProtocolHandler::NewChannel2(nsIURI* uri,
1232
                                 nsILoadInfo* aLoadInfo,
1233
                                 nsIChannel** result)
1234
0
{
1235
0
    nsresult rv;
1236
0
1237
0
    NS_ENSURE_ARG_POINTER(uri);
1238
0
    RefPtr<nsJSChannel> channel = new nsJSChannel();
1239
0
    if (!channel) {
1240
0
        return NS_ERROR_OUT_OF_MEMORY;
1241
0
    }
1242
0
1243
0
    rv = channel->Init(uri, aLoadInfo);
1244
0
    NS_ENSURE_SUCCESS(rv, rv);
1245
0
1246
0
    if (NS_SUCCEEDED(rv)) {
1247
0
        channel.forget(result);
1248
0
    }
1249
0
    return rv;
1250
0
}
1251
1252
NS_IMETHODIMP
1253
nsJSProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
1254
0
{
1255
0
    return NewChannel2(uri, nullptr, result);
1256
0
}
1257
1258
NS_IMETHODIMP
1259
nsJSProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
1260
0
{
1261
0
    // don't override anything.
1262
0
    *_retval = false;
1263
0
    return NS_OK;
1264
0
}
1265
1266
////////////////////////////////////////////////////////////
1267
// nsJSURI implementation
1268
static NS_DEFINE_CID(kThisSimpleURIImplementationCID,
1269
                     NS_THIS_SIMPLEURI_IMPLEMENTATION_CID);
1270
1271
1272
NS_IMPL_ADDREF_INHERITED(nsJSURI, mozilla::net::nsSimpleURI)
1273
NS_IMPL_RELEASE_INHERITED(nsJSURI, mozilla::net::nsSimpleURI)
1274
1275
0
NS_INTERFACE_MAP_BEGIN(nsJSURI)
1276
0
  if (aIID.Equals(kJSURICID))
1277
0
      foundInterface = static_cast<nsIURI*>(this);
1278
0
  else if (aIID.Equals(kThisSimpleURIImplementationCID)) {
1279
0
      // Need to return explicitly here, because if we just set foundInterface
1280
0
      // to null the NS_INTERFACE_MAP_END_INHERITING will end up calling into
1281
0
      // nsSimplURI::QueryInterface and finding something for this CID.
1282
0
      *aInstancePtr = nullptr;
1283
0
      return NS_NOINTERFACE;
1284
0
  }
1285
0
  else
1286
0
NS_INTERFACE_MAP_END_INHERITING(mozilla::net::nsSimpleURI)
1287
1288
// nsISerializable methods:
1289
1290
NS_IMETHODIMP
1291
nsJSURI::Read(nsIObjectInputStream *aStream)
1292
0
{
1293
0
    MOZ_ASSERT_UNREACHABLE("Use nsIURIMutator.read() instead");
1294
0
    return NS_ERROR_NOT_IMPLEMENTED;
1295
0
}
1296
1297
nsresult
1298
nsJSURI::ReadPrivate(nsIObjectInputStream *aStream)
1299
0
{
1300
0
    nsresult rv = mozilla::net::nsSimpleURI::ReadPrivate(aStream);
1301
0
    if (NS_FAILED(rv)) return rv;
1302
0
1303
0
    bool haveBase;
1304
0
    rv = aStream->ReadBoolean(&haveBase);
1305
0
    if (NS_FAILED(rv)) return rv;
1306
0
1307
0
    if (haveBase) {
1308
0
        nsCOMPtr<nsISupports> supports;
1309
0
        rv = aStream->ReadObject(true, getter_AddRefs(supports));
1310
0
        if (NS_FAILED(rv)) return rv;
1311
0
        mBaseURI = do_QueryInterface(supports);
1312
0
    }
1313
0
1314
0
    return NS_OK;
1315
0
}
1316
1317
NS_IMETHODIMP
1318
nsJSURI::Write(nsIObjectOutputStream* aStream)
1319
0
{
1320
0
    nsresult rv = mozilla::net::nsSimpleURI::Write(aStream);
1321
0
    if (NS_FAILED(rv)) return rv;
1322
0
1323
0
    rv = aStream->WriteBoolean(mBaseURI != nullptr);
1324
0
    if (NS_FAILED(rv)) return rv;
1325
0
1326
0
    if (mBaseURI) {
1327
0
        rv = aStream->WriteObject(mBaseURI, true);
1328
0
        if (NS_FAILED(rv)) return rv;
1329
0
    }
1330
0
1331
0
    return NS_OK;
1332
0
}
1333
1334
// nsIIPCSerializableURI
1335
void
1336
nsJSURI::Serialize(mozilla::ipc::URIParams& aParams)
1337
0
{
1338
0
    using namespace mozilla::ipc;
1339
0
1340
0
    JSURIParams jsParams;
1341
0
    URIParams simpleParams;
1342
0
1343
0
    mozilla::net::nsSimpleURI::Serialize(simpleParams);
1344
0
1345
0
    jsParams.simpleParams() = simpleParams;
1346
0
    if (mBaseURI) {
1347
0
        SerializeURI(mBaseURI, jsParams.baseURI());
1348
0
    } else {
1349
0
        jsParams.baseURI() = mozilla::void_t();
1350
0
    }
1351
0
1352
0
    aParams = jsParams;
1353
0
}
1354
1355
bool
1356
nsJSURI::Deserialize(const mozilla::ipc::URIParams& aParams)
1357
0
{
1358
0
    using namespace mozilla::ipc;
1359
0
1360
0
    if (aParams.type() != URIParams::TJSURIParams) {
1361
0
        NS_ERROR("Received unknown parameters from the other process!");
1362
0
        return false;
1363
0
    }
1364
0
1365
0
    const JSURIParams& jsParams = aParams.get_JSURIParams();
1366
0
    mozilla::net::nsSimpleURI::Deserialize(jsParams.simpleParams());
1367
0
1368
0
    if (jsParams.baseURI().type() != OptionalURIParams::Tvoid_t) {
1369
0
        mBaseURI = DeserializeURI(jsParams.baseURI().get_URIParams());
1370
0
    } else {
1371
0
        mBaseURI = nullptr;
1372
0
    }
1373
0
    return true;
1374
0
}
1375
1376
// nsSimpleURI methods:
1377
/* virtual */ mozilla::net::nsSimpleURI*
1378
nsJSURI::StartClone(mozilla::net::nsSimpleURI::RefHandlingEnum refHandlingMode,
1379
                    const nsACString& newRef)
1380
0
{
1381
0
    nsJSURI* url = new nsJSURI(mBaseURI);
1382
0
    SetRefOnClone(url, refHandlingMode, newRef);
1383
0
    return url;
1384
0
}
1385
1386
// Queries this list of interfaces. If none match, it queries mURI.
1387
NS_IMPL_NSIURIMUTATOR_ISUPPORTS(nsJSURI::Mutator,
1388
                                nsIURISetters,
1389
                                nsIURIMutator,
1390
                                nsISerializable,
1391
                                nsIJSURIMutator)
1392
1393
NS_IMETHODIMP
1394
nsJSURI::Mutate(nsIURIMutator** aMutator)
1395
0
{
1396
0
    RefPtr<nsJSURI::Mutator> mutator = new nsJSURI::Mutator();
1397
0
    nsresult rv = mutator->InitFromURI(this);
1398
0
    if (NS_FAILED(rv)) {
1399
0
        return rv;
1400
0
    }
1401
0
    mutator.forget(aMutator);
1402
0
    return NS_OK;
1403
0
}
1404
1405
/* virtual */ nsresult
1406
nsJSURI::EqualsInternal(nsIURI* aOther,
1407
                        mozilla::net::nsSimpleURI::RefHandlingEnum aRefHandlingMode,
1408
                        bool* aResult)
1409
0
{
1410
0
    NS_ENSURE_ARG_POINTER(aOther);
1411
0
    MOZ_ASSERT(aResult, "null pointer for outparam");
1412
0
1413
0
    RefPtr<nsJSURI> otherJSURI;
1414
0
    nsresult rv = aOther->QueryInterface(kJSURICID,
1415
0
                                         getter_AddRefs(otherJSURI));
1416
0
    if (NS_FAILED(rv)) {
1417
0
        *aResult = false; // aOther is not a nsJSURI --> not equal.
1418
0
        return NS_OK;
1419
0
    }
1420
0
1421
0
    // Compare the member data that our base class knows about.
1422
0
    if (!mozilla::net::nsSimpleURI::EqualsInternal(otherJSURI, aRefHandlingMode)) {
1423
0
        *aResult = false;
1424
0
        return NS_OK;
1425
0
    }
1426
0
1427
0
    // Compare the piece of additional member data that we add to base class.
1428
0
    nsIURI* otherBaseURI = otherJSURI->GetBaseURI();
1429
0
1430
0
    if (mBaseURI) {
1431
0
        // (As noted in StartClone, we always honor refs on mBaseURI)
1432
0
        return mBaseURI->Equals(otherBaseURI, aResult);
1433
0
    }
1434
0
1435
0
    *aResult = !otherBaseURI;
1436
0
    return NS_OK;
1437
0
}
1438
1439
NS_IMETHODIMP
1440
nsJSURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
1441
0
{
1442
0
    *aClassIDNoAlloc = kJSURICID;
1443
0
    return NS_OK;
1444
0
}
1445