Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
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
* A base class implementing nsIObjectLoadingContent for use by
8
* various content nodes that want to provide plugin/document/image
9
* loading functionality (eg <embed>, <object>, etc).
10
*/
11
12
// Interface headers
13
#include "imgLoader.h"
14
#include "nsIClassOfService.h"
15
#include "nsIConsoleService.h"
16
#include "nsIContent.h"
17
#include "nsIContentInlines.h"
18
#include "nsIDocShell.h"
19
#include "mozilla/dom/BindContext.h"
20
#include "mozilla/dom/Document.h"
21
#include "nsIExternalProtocolHandler.h"
22
#include "nsIInterfaceRequestorUtils.h"
23
#include "nsIObjectFrame.h"
24
#include "nsIOService.h"
25
#include "nsIPermissionManager.h"
26
#include "nsPluginHost.h"
27
#include "nsPluginInstanceOwner.h"
28
#include "nsJSNPRuntime.h"
29
#include "nsINestedURI.h"
30
#include "nsScriptSecurityManager.h"
31
#include "nsIScriptSecurityManager.h"
32
#include "nsIStreamConverterService.h"
33
#include "nsIURILoader.h"
34
#include "nsIURL.h"
35
#include "nsIWebNavigation.h"
36
#include "nsIWebNavigationInfo.h"
37
#include "nsIScriptChannel.h"
38
#include "nsIBlocklistService.h"
39
#include "nsIAsyncVerifyRedirectCallback.h"
40
#include "nsIAppShell.h"
41
#include "nsIXULRuntime.h"
42
#include "nsIScriptError.h"
43
44
#include "nsError.h"
45
46
// Util headers
47
#include "prenv.h"
48
#include "mozilla/Logging.h"
49
50
#include "nsCURILoader.h"
51
#include "nsContentPolicyUtils.h"
52
#include "nsContentUtils.h"
53
#include "nsDocShellCID.h"
54
#include "nsGkAtoms.h"
55
#include "nsThreadUtils.h"
56
#include "nsNetUtil.h"
57
#include "nsMimeTypes.h"
58
#include "nsStyleUtil.h"
59
#include "nsUnicharUtils.h"
60
#include "mozilla/Preferences.h"
61
#include "nsSandboxFlags.h"
62
63
// Concrete classes
64
#include "nsFrameLoader.h"
65
66
#include "nsObjectLoadingContent.h"
67
#include "mozAutoDocUpdate.h"
68
#include "nsIContentSecurityPolicy.h"
69
#include "GeckoProfiler.h"
70
#include "nsPluginFrame.h"
71
#include "nsWrapperCacheInlines.h"
72
#include "nsDOMJSUtils.h"
73
74
#include "nsWidgetsCID.h"
75
#include "nsContentCID.h"
76
#include "mozilla/BasicEvents.h"
77
#include "mozilla/Components.h"
78
#include "mozilla/dom/BindingUtils.h"
79
#include "mozilla/dom/Element.h"
80
#include "mozilla/dom/Event.h"
81
#include "mozilla/dom/ScriptSettings.h"
82
#include "mozilla/dom/PluginCrashedEvent.h"
83
#include "mozilla/AsyncEventDispatcher.h"
84
#include "mozilla/EventDispatcher.h"
85
#include "mozilla/EventStateManager.h"
86
#include "mozilla/EventStates.h"
87
#include "mozilla/IMEStateManager.h"
88
#include "mozilla/widget/IMEData.h"
89
#include "mozilla/IntegerPrintfMacros.h"
90
#include "mozilla/dom/HTMLObjectElementBinding.h"
91
#include "mozilla/dom/HTMLEmbedElement.h"
92
#include "mozilla/dom/HTMLObjectElement.h"
93
#include "mozilla/net/UrlClassifierFeatureFactory.h"
94
#include "mozilla/LoadInfo.h"
95
#include "mozilla/PresShell.h"
96
#include "nsChannelClassifier.h"
97
#include "nsFocusManager.h"
98
#include "ReferrerInfo.h"
99
100
#ifdef XP_WIN
101
// Thanks so much, Microsoft! :(
102
# ifdef CreateEvent
103
# undef CreateEvent
104
# endif
105
#endif // XP_WIN
106
107
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
108
109
static const char kPrefYoutubeRewrite[] = "plugins.rewrite_youtube_embeds";
110
static const char kPrefBlockURIs[] = "browser.safebrowsing.blockedURIs.enabled";
111
static const char kPrefFavorFallbackMode[] = "plugins.favorfallback.mode";
112
static const char kPrefFavorFallbackRules[] = "plugins.favorfallback.rules";
113
114
using namespace mozilla;
115
using namespace mozilla::dom;
116
using namespace mozilla::net;
117
118
static LogModule* GetObjectLog() {
119
static LazyLogModule sLog("objlc");
120
return sLog;
121
}
122
123
#define LOG(args) MOZ_LOG(GetObjectLog(), mozilla::LogLevel::Debug, args)
124
#define LOG_ENABLED() MOZ_LOG_TEST(GetObjectLog(), mozilla::LogLevel::Debug)
125
126
static bool IsFlashMIME(const nsACString& aMIMEType) {
127
return nsPluginHost::GetSpecialType(aMIMEType) ==
128
nsPluginHost::eSpecialType_Flash;
129
}
130
131
static bool InActiveDocument(nsIContent* aContent) {
132
if (!aContent->IsInComposedDoc()) {
133
return false;
134
}
135
Document* doc = aContent->OwnerDoc();
136
return (doc && doc->IsActive());
137
}
138
139
static bool IsPluginType(nsObjectLoadingContent::ObjectType type) {
140
return type == nsObjectLoadingContent::eType_Plugin ||
141
type == nsObjectLoadingContent::eType_FakePlugin;
142
}
143
144
///
145
/// Runnables and helper classes
146
///
147
148
class nsAsyncInstantiateEvent : public Runnable {
149
public:
150
explicit nsAsyncInstantiateEvent(nsObjectLoadingContent* aContent)
151
: Runnable("nsAsyncInstantiateEvent"), mContent(aContent) {}
152
153
~nsAsyncInstantiateEvent() override = default;
154
155
NS_IMETHOD Run() override;
156
157
private:
158
nsCOMPtr<nsIObjectLoadingContent> mContent;
159
};
160
161
NS_IMETHODIMP
162
nsAsyncInstantiateEvent::Run() {
163
nsObjectLoadingContent* objLC =
164
static_cast<nsObjectLoadingContent*>(mContent.get());
165
166
// If objLC is no longer tracking this event, we've been canceled or
167
// superseded
168
if (objLC->mPendingInstantiateEvent != this) {
169
return NS_OK;
170
}
171
objLC->mPendingInstantiateEvent = nullptr;
172
173
return objLC->SyncStartPluginInstance();
174
}
175
176
// Checks to see if the content for a plugin instance should be unloaded
177
// (outside an active document) or stopped (in a document but unrendered). This
178
// is used to allow scripts to move a plugin around the document hierarchy
179
// without re-instantiating it.
180
class CheckPluginStopEvent : public Runnable {
181
public:
182
explicit CheckPluginStopEvent(nsObjectLoadingContent* aContent)
183
: Runnable("CheckPluginStopEvent"), mContent(aContent) {}
184
185
~CheckPluginStopEvent() override = default;
186
187
NS_IMETHOD Run() override;
188
189
private:
190
nsCOMPtr<nsIObjectLoadingContent> mContent;
191
};
192
193
NS_IMETHODIMP
194
CheckPluginStopEvent::Run() {
195
nsObjectLoadingContent* objLC =
196
static_cast<nsObjectLoadingContent*>(mContent.get());
197
198
// If objLC is no longer tracking this event, we've been canceled or
199
// superseded. We clear this before we finish - either by calling
200
// UnloadObject/StopPluginInstance, or directly if we took no action.
201
if (objLC->mPendingCheckPluginStopEvent != this) {
202
return NS_OK;
203
}
204
205
// CheckPluginStopEvent is queued when we either lose our frame, are removed
206
// from the document, or the document goes inactive. To avoid stopping the
207
// plugin when script is reparenting us or layout is rebuilding, we wait until
208
// this event to decide to stop.
209
210
nsCOMPtr<nsIContent> content =
211
do_QueryInterface(static_cast<nsIImageLoadingContent*>(objLC));
212
if (!InActiveDocument(content)) {
213
LOG(("OBJLC [%p]: Unloading plugin outside of document", this));
214
objLC->StopPluginInstance();
215
return NS_OK;
216
}
217
218
if (content->GetPrimaryFrame()) {
219
LOG(
220
("OBJLC [%p]: CheckPluginStopEvent - in active document with frame"
221
", no action",
222
this));
223
objLC->mPendingCheckPluginStopEvent = nullptr;
224
return NS_OK;
225
}
226
227
// In an active document, but still no frame. Flush layout to see if we can
228
// regain a frame now.
229
LOG(("OBJLC [%p]: CheckPluginStopEvent - No frame, flushing layout", this));
230
Document* composedDoc = content->GetComposedDoc();
231
if (composedDoc) {
232
composedDoc->FlushPendingNotifications(FlushType::Layout);
233
if (objLC->mPendingCheckPluginStopEvent != this) {
234
LOG(("OBJLC [%p]: CheckPluginStopEvent - superseded in layout flush",
235
this));
236
return NS_OK;
237
}
238
if (content->GetPrimaryFrame()) {
239
LOG(("OBJLC [%p]: CheckPluginStopEvent - frame gained in layout flush",
240
this));
241
objLC->mPendingCheckPluginStopEvent = nullptr;
242
return NS_OK;
243
}
244
}
245
246
// Still no frame, suspend plugin. HasNewFrame will restart us when we
247
// become rendered again
248
LOG(("OBJLC [%p]: Stopping plugin that lost frame", this));
249
objLC->StopPluginInstance();
250
251
return NS_OK;
252
}
253
254
/**
255
* Helper task for firing simple events
256
*/
257
class nsSimplePluginEvent : public Runnable {
258
public:
259
nsSimplePluginEvent(nsIContent* aTarget, const nsAString& aEvent)
260
: Runnable("nsSimplePluginEvent"),
261
mTarget(aTarget),
262
mDocument(aTarget->GetComposedDoc()),
263
mEvent(aEvent) {
264
MOZ_ASSERT(aTarget && mDocument);
265
}
266
267
nsSimplePluginEvent(Document* aTarget, const nsAString& aEvent)
268
: mozilla::Runnable("nsSimplePluginEvent"),
269
mTarget(ToSupports(aTarget)),
270
mDocument(aTarget),
271
mEvent(aEvent) {
272
MOZ_ASSERT(aTarget);
273
}
274
275
nsSimplePluginEvent(nsIContent* aTarget, Document* aDocument,
276
const nsAString& aEvent)
277
: mozilla::Runnable("nsSimplePluginEvent"),
278
mTarget(aTarget),
279
mDocument(aDocument),
280
mEvent(aEvent) {
281
MOZ_ASSERT(aTarget && aDocument);
282
}
283
284
~nsSimplePluginEvent() override = default;
285
286
NS_IMETHOD Run() override;
287
288
private:
289
nsCOMPtr<nsISupports> mTarget;
290
nsCOMPtr<Document> mDocument;
291
nsString mEvent;
292
};
293
294
NS_IMETHODIMP
295
nsSimplePluginEvent::Run() {
296
if (mDocument && mDocument->IsActive()) {
297
LOG(("OBJLC [%p]: nsSimplePluginEvent firing event \"%s\"", mTarget.get(),
298
NS_ConvertUTF16toUTF8(mEvent).get()));
299
nsContentUtils::DispatchTrustedEvent(mDocument, mTarget, mEvent,
300
CanBubble::eYes, Cancelable::eYes);
301
}
302
return NS_OK;
303
}
304
305
/**
306
* A task for firing PluginCrashed DOM Events.
307
*/
308
class nsPluginCrashedEvent : public Runnable {
309
public:
310
nsCOMPtr<nsIContent> mContent;
311
nsString mPluginDumpID;
312
nsString mBrowserDumpID;
313
nsString mPluginName;
314
nsString mPluginFilename;
315
bool mSubmittedCrashReport;
316
317
nsPluginCrashedEvent(nsIContent* aContent, const nsAString& aPluginDumpID,
318
const nsAString& aBrowserDumpID,
319
const nsAString& aPluginName,
320
const nsAString& aPluginFilename,
321
bool submittedCrashReport)
322
: Runnable("nsPluginCrashedEvent"),
323
mContent(aContent),
324
mPluginDumpID(aPluginDumpID),
325
mBrowserDumpID(aBrowserDumpID),
326
mPluginName(aPluginName),
327
mPluginFilename(aPluginFilename),
328
mSubmittedCrashReport(submittedCrashReport) {}
329
330
~nsPluginCrashedEvent() override = default;
331
332
NS_IMETHOD Run() override;
333
};
334
335
NS_IMETHODIMP
336
nsPluginCrashedEvent::Run() {
337
LOG(("OBJLC [%p]: Firing plugin crashed event\n", mContent.get()));
338
339
nsCOMPtr<Document> doc = mContent->GetComposedDoc();
340
if (!doc) {
341
NS_WARNING("Couldn't get document for PluginCrashed event!");
342
return NS_OK;
343
}
344
345
PluginCrashedEventInit init;
346
init.mPluginDumpID = mPluginDumpID;
347
init.mBrowserDumpID = mBrowserDumpID;
348
init.mPluginName = mPluginName;
349
init.mPluginFilename = mPluginFilename;
350
init.mSubmittedCrashReport = mSubmittedCrashReport;
351
init.mBubbles = true;
352
init.mCancelable = true;
353
354
RefPtr<PluginCrashedEvent> event = PluginCrashedEvent::Constructor(
355
doc, NS_LITERAL_STRING("PluginCrashed"), init);
356
357
event->SetTrusted(true);
358
event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
359
360
EventDispatcher::DispatchDOMEvent(mContent, nullptr, event, nullptr, nullptr);
361
return NS_OK;
362
}
363
364
// You can't take the address of bitfield members, so we have two separate
365
// classes for these :-/
366
367
// Sets a object's mInstantiating bit to false when destroyed
368
class AutoSetInstantiatingToFalse {
369
public:
370
explicit AutoSetInstantiatingToFalse(nsObjectLoadingContent* aContent)
371
: mContent(aContent) {}
372
~AutoSetInstantiatingToFalse() { mContent->mInstantiating = false; }
373
374
private:
375
nsObjectLoadingContent* mContent;
376
};
377
378
// Sets a object's mInstantiating bit to false when destroyed
379
class AutoSetLoadingToFalse {
380
public:
381
explicit AutoSetLoadingToFalse(nsObjectLoadingContent* aContent)
382
: mContent(aContent) {}
383
~AutoSetLoadingToFalse() { mContent->mIsLoading = false; }
384
385
private:
386
nsObjectLoadingContent* mContent;
387
};
388
389
///
390
/// Helper functions
391
///
392
393
static bool IsSuccessfulRequest(nsIRequest* aRequest, nsresult* aStatus) {
394
nsresult rv = aRequest->GetStatus(aStatus);
395
if (NS_FAILED(rv) || NS_FAILED(*aStatus)) {
396
return false;
397
}
398
399
// This may still be an error page or somesuch
400
nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(aRequest));
401
if (httpChan) {
402
bool success;
403
rv = httpChan->GetRequestSucceeded(&success);
404
if (NS_FAILED(rv) || !success) {
405
return false;
406
}
407
}
408
409
// Otherwise, the request is successful
410
return true;
411
}
412
413
static bool CanHandleURI(nsIURI* aURI) {
414
nsAutoCString scheme;
415
if (NS_FAILED(aURI->GetScheme(scheme))) {
416
return false;
417
}
418
419
nsIIOService* ios = nsContentUtils::GetIOService();
420
if (!ios) return false;
421
422
nsCOMPtr<nsIProtocolHandler> handler;
423
ios->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
424
if (!handler) {
425
return false;
426
}
427
428
nsCOMPtr<nsIExternalProtocolHandler> extHandler = do_QueryInterface(handler);
429
// We can handle this URI if its protocol handler is not the external one
430
return extHandler == nullptr;
431
}
432
433
// Helper for tedious URI equality syntax when one or both arguments may be
434
// null and URIEquals(null, null) should be true
435
static bool inline URIEquals(nsIURI* a, nsIURI* b) {
436
bool equal;
437
return (!a && !b) || (a && b && NS_SUCCEEDED(a->Equals(b, &equal)) && equal);
438
}
439
440
static void GetExtensionFromURI(nsIURI* uri, nsCString& ext) {
441
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
442
if (url) {
443
url->GetFileExtension(ext);
444
} else {
445
nsCString spec;
446
nsresult rv = uri->GetSpec(spec);
447
if (NS_FAILED(rv)) {
448
// This means we could incorrectly think a plugin is not enabled for
449
// the URI when it is, but that's not so bad.
450
ext.Truncate();
451
return;
452
}
453
454
int32_t offset = spec.RFindChar('.');
455
if (offset != kNotFound) {
456
ext = Substring(spec, offset + 1, spec.Length());
457
}
458
}
459
}
460
461
/**
462
* Checks whether a plugin exists and is enabled for the extension
463
* in the given URI. The MIME type is returned in the mimeType out parameter.
464
*/
465
bool IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType) {
466
nsAutoCString ext;
467
GetExtensionFromURI(uri, ext);
468
469
if (ext.IsEmpty()) {
470
return false;
471
}
472
473
// Disables any native PDF plugins, when internal PDF viewer is enabled.
474
if (ext.EqualsIgnoreCase("pdf") && nsContentUtils::IsPDFJSEnabled()) {
475
return false;
476
}
477
478
RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
479
480
if (!pluginHost) {
481
MOZ_ASSERT_UNREACHABLE("No pluginhost");
482
return false;
483
}
484
485
return pluginHost->HavePluginForExtension(ext, mimeType);
486
}
487
488
///
489
/// Member Functions
490
///
491
492
// Helper to queue a CheckPluginStopEvent for a OBJLC object
493
void nsObjectLoadingContent::QueueCheckPluginStopEvent() {
494
nsCOMPtr<nsIRunnable> event = new CheckPluginStopEvent(this);
495
mPendingCheckPluginStopEvent = event;
496
497
NS_DispatchToCurrentThread(event);
498
}
499
500
// Tedious syntax to create a plugin stream listener with checks and put it in
501
// mFinalListener
502
bool nsObjectLoadingContent::MakePluginListener() {
503
if (!mInstanceOwner) {
504
MOZ_ASSERT_UNREACHABLE("expecting a spawned plugin");
505
return false;
506
}
507
RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
508
if (!pluginHost) {
509
MOZ_ASSERT_UNREACHABLE("No pluginHost");
510
return false;
511
}
512
NS_ASSERTION(!mFinalListener, "overwriting a final listener");
513
nsresult rv;
514
RefPtr<nsNPAPIPluginInstance> inst = mInstanceOwner->GetInstance();
515
nsCOMPtr<nsIStreamListener> finalListener;
516
rv = pluginHost->NewPluginStreamListener(mURI, inst,
517
getter_AddRefs(finalListener));
518
NS_ENSURE_SUCCESS(rv, false);
519
mFinalListener = finalListener;
520
return true;
521
}
522
523
// Helper to spawn the frameloader.
524
void nsObjectLoadingContent::SetupFrameLoader(int32_t aJSPluginId) {
525
nsCOMPtr<nsIContent> thisContent =
526
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
527
NS_ASSERTION(thisContent, "must be a content");
528
529
mFrameLoader =
530
nsFrameLoader::Create(thisContent->AsElement(),
531
/* aOpener = */ nullptr, mNetworkCreated);
532
MOZ_ASSERT(mFrameLoader, "nsFrameLoader::Create failed");
533
}
534
535
// Helper to spawn the frameloader and return a pointer to its docshell.
536
already_AddRefed<nsIDocShell> nsObjectLoadingContent::SetupDocShell(
537
nsIURI* aRecursionCheckURI) {
538
SetupFrameLoader(nsFakePluginTag::NOT_JSPLUGIN);
539
if (!mFrameLoader) {
540
return nullptr;
541
}
542
543
nsCOMPtr<nsIDocShell> docShell;
544
545
if (aRecursionCheckURI) {
546
nsresult rv = mFrameLoader->CheckForRecursiveLoad(aRecursionCheckURI);
547
if (NS_SUCCEEDED(rv)) {
548
IgnoredErrorResult result;
549
docShell = mFrameLoader->GetDocShell(result);
550
if (result.Failed()) {
551
MOZ_ASSERT_UNREACHABLE("Could not get DocShell from mFrameLoader?");
552
}
553
} else {
554
LOG(("OBJLC [%p]: Aborting recursive load", this));
555
}
556
}
557
558
if (!docShell) {
559
mFrameLoader->Destroy();
560
mFrameLoader = nullptr;
561
return nullptr;
562
}
563
564
return docShell.forget();
565
}
566
567
nsresult nsObjectLoadingContent::BindToTree(BindContext& aContext,
568
nsINode& aParent) {
569
nsImageLoadingContent::BindToTree(aContext, aParent);
570
// FIXME(emilio): Should probably use composed doc?
571
if (Document* doc = aContext.GetUncomposedDoc()) {
572
doc->AddPlugin(this);
573
}
574
return NS_OK;
575
}
576
577
void nsObjectLoadingContent::UnbindFromTree(bool aNullParent) {
578
nsImageLoadingContent::UnbindFromTree(aNullParent);
579
580
nsCOMPtr<Element> thisElement =
581
do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
582
MOZ_ASSERT(thisElement);
583
Document* ownerDoc = thisElement->OwnerDoc();
584
ownerDoc->RemovePlugin(this);
585
586
/// XXX(johns): Do we want to somehow propogate the reparenting behavior to
587
/// FakePlugin types as well?
588
if (mType == eType_Plugin && (mInstanceOwner || mInstantiating)) {
589
// we'll let the plugin continue to run at least until we get back to
590
// the event loop. If we get back to the event loop and the node
591
// has still not been added back to the document then we tear down the
592
// plugin
593
QueueCheckPluginStopEvent();
594
} else if (mType != eType_Image) {
595
// nsImageLoadingContent handles the image case.
596
// Reset state and clear pending events
597
/// XXX(johns): The implementation for GenericFrame notes that ideally we
598
/// would keep the docshell around, but trash the frameloader
599
UnloadObject();
600
}
601
602
// Unattach plugin problem UIWidget if any.
603
if (thisElement->IsInComposedDoc()) {
604
thisElement->NotifyUAWidgetTeardown();
605
}
606
607
if (mType == eType_Plugin) {
608
Document* doc = thisElement->GetComposedDoc();
609
if (doc && doc->IsActive()) {
610
nsCOMPtr<nsIRunnable> ev =
611
new nsSimplePluginEvent(doc, NS_LITERAL_STRING("PluginRemoved"));
612
NS_DispatchToCurrentThread(ev);
613
}
614
}
615
}
616
617
nsObjectLoadingContent::nsObjectLoadingContent()
618
: mType(eType_Loading),
619
mFallbackType(eFallbackAlternate),
620
mRunID(0),
621
mHasRunID(false),
622
mChannelLoaded(false),
623
mInstantiating(false),
624
mNetworkCreated(true),
625
mActivated(false),
626
mContentBlockingEnabled(false),
627
mSkipFakePlugins(false),
628
mIsStopping(false),
629
mIsLoading(false),
630
mScriptRequested(false),
631
mRewrittenYoutubeEmbed(false),
632
mPreferFallback(false),
633
mPreferFallbackKnown(false) {}
634
635
nsObjectLoadingContent::~nsObjectLoadingContent() {
636
// Should have been unbound from the tree at this point, and
637
// CheckPluginStopEvent keeps us alive
638
if (mFrameLoader) {
639
MOZ_ASSERT_UNREACHABLE(
640
"Should not be tearing down frame loaders at this point");
641
mFrameLoader->Destroy();
642
}
643
if (mInstanceOwner || mInstantiating) {
644
// This is especially bad as delayed stop will try to hold on to this
645
// object...
646
MOZ_ASSERT_UNREACHABLE(
647
"Should not be tearing down a plugin at this point!");
648
StopPluginInstance();
649
}
650
DestroyImageLoadingContent();
651
}
652
653
nsresult nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading) {
654
if (mInstanceOwner || mType != eType_Plugin || (mIsLoading != aIsLoading) ||
655
mInstantiating) {
656
// If we hit this assertion it's probably because LoadObject re-entered :(
657
//
658
// XXX(johns): This hackiness will go away in bug 767635
659
NS_ASSERTION(mIsLoading || !aIsLoading,
660
"aIsLoading should only be true inside LoadObject");
661
return NS_OK;
662
}
663
664
mInstantiating = true;
665
AutoSetInstantiatingToFalse autoInstantiating(this);
666
667
nsCOMPtr<nsIContent> thisContent =
668
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
669
670
nsCOMPtr<Document> doc = thisContent->GetComposedDoc();
671
if (!doc || !InActiveDocument(thisContent)) {
672
NS_ERROR(
673
"Shouldn't be calling "
674
"InstantiatePluginInstance without an active document");
675
return NS_ERROR_FAILURE;
676
}
677
678
// Instantiating an instance can result in script execution, which
679
// can destroy this DOM object. Don't allow that for the scope
680
// of this method.
681
nsCOMPtr<nsIObjectLoadingContent> kungFuDeathGrip = this;
682
683
// Flush layout so that the frame is created if possible and the plugin is
684
// initialized with the latest information.
685
doc->FlushPendingNotifications(FlushType::Layout);
686
// Flushing layout may have re-entered and loaded something underneath us
687
NS_ENSURE_TRUE(mInstantiating, NS_OK);
688
689
if (!thisContent->GetPrimaryFrame()) {
690
LOG(("OBJLC [%p]: Not instantiating plugin with no frame", this));
691
return NS_OK;
692
}
693
694
RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
695
696
if (!pluginHost) {
697
MOZ_ASSERT_UNREACHABLE("No pluginhost");
698
return NS_ERROR_FAILURE;
699
}
700
701
// If you add early return(s), be sure to balance this call to
702
// appShell->SuspendNative() with additional call(s) to
703
// appShell->ReturnNative().
704
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
705
if (appShell) {
706
appShell->SuspendNative();
707
}
708
709
RefPtr<nsPluginInstanceOwner> newOwner;
710
nsresult rv = pluginHost->InstantiatePluginInstance(
711
mContentType, mURI.get(), this, getter_AddRefs(newOwner));
712
713
// XXX(johns): We don't suspend native inside stopping plugins...
714
if (appShell) {
715
appShell->ResumeNative();
716
}
717
718
if (!mInstantiating || NS_FAILED(rv)) {
719
LOG(
720
("OBJLC [%p]: Plugin instantiation failed or re-entered, "
721
"killing old instance",
722
this));
723
// XXX(johns): This needs to be de-duplicated with DoStopPlugin, but we
724
// don't want to touch the protochain or delayed stop.
725
// (Bug 767635)
726
if (newOwner) {
727
RefPtr<nsNPAPIPluginInstance> inst = newOwner->GetInstance();
728
newOwner->SetFrame(nullptr);
729
if (inst) {
730
pluginHost->StopPluginInstance(inst);
731
}
732
newOwner->Destroy();
733
}
734
return NS_OK;
735
}
736
737
mInstanceOwner = newOwner;
738
739
if (mInstanceOwner) {
740
RefPtr<nsNPAPIPluginInstance> inst = mInstanceOwner->GetInstance();
741
742
rv = inst->GetRunID(&mRunID);
743
mHasRunID = NS_SUCCEEDED(rv);
744
}
745
746
// Ensure the frame did not change during instantiation re-entry (common).
747
// HasNewFrame would not have mInstanceOwner yet, so the new frame would be
748
// dangling. (Bug 854082)
749
nsIFrame* frame = thisContent->GetPrimaryFrame();
750
if (frame && mInstanceOwner) {
751
mInstanceOwner->SetFrame(static_cast<nsPluginFrame*>(frame));
752
753
// Bug 870216 - Adobe Reader renders with incorrect dimensions until it gets
754
// a second SetWindow call. This is otherwise redundant.
755
mInstanceOwner->CallSetWindow();
756
}
757
758
// Set up scripting interfaces.
759
NotifyContentObjectWrapper();
760
761
RefPtr<nsNPAPIPluginInstance> pluginInstance = GetPluginInstance();
762
if (pluginInstance) {
763
nsCOMPtr<nsIPluginTag> pluginTag;
764
pluginHost->GetPluginTagForInstance(pluginInstance,
765
getter_AddRefs(pluginTag));
766
767
uint32_t blockState = nsIBlocklistService::STATE_NOT_BLOCKED;
768
pluginTag->GetBlocklistState(&blockState);
769
if (blockState == nsIBlocklistService::STATE_OUTDATED) {
770
// Fire plugin outdated event if necessary
771
LOG(("OBJLC [%p]: Dispatching plugin outdated event for content\n",
772
this));
773
nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(
774
thisContent, NS_LITERAL_STRING("PluginOutdated"));
775
nsresult rv = NS_DispatchToCurrentThread(ev);
776
if (NS_FAILED(rv)) {
777
NS_WARNING("failed to dispatch nsSimplePluginEvent");
778
}
779
}
780
781
// If we have a URI but didn't open a channel yet (eAllowPluginSkipChannel)
782
// or we did load with a channel but are re-instantiating, re-open the
783
// channel. OpenChannel() performs security checks, and this plugin has
784
// already passed content policy in LoadObject.
785
if ((mURI && !mChannelLoaded) || (mChannelLoaded && !aIsLoading)) {
786
NS_ASSERTION(!mChannel, "should not have an existing channel here");
787
// We intentionally ignore errors here, leaving it up to the plugin to
788
// deal with not having an initial stream.
789
OpenChannel();
790
}
791
}
792
793
nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(
794
thisContent, doc, NS_LITERAL_STRING("PluginInstantiated"));
795
NS_DispatchToCurrentThread(ev);
796
797
#ifdef XP_MACOSX
798
HTMLObjectElement::HandlePluginInstantiated(thisContent->AsElement());
799
#endif
800
801
return NS_OK;
802
}
803
804
void nsObjectLoadingContent::GetPluginAttributes(
805
nsTArray<MozPluginParameter>& aAttributes) {
806
aAttributes = mCachedAttributes;
807
}
808
809
void nsObjectLoadingContent::GetPluginParameters(
810
nsTArray<MozPluginParameter>& aParameters) {
811
aParameters = mCachedParameters;
812
}
813
814
void nsObjectLoadingContent::GetNestedParams(
815
nsTArray<MozPluginParameter>& aParams) {
816
nsCOMPtr<Element> ourElement =
817
do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
818
819
nsCOMPtr<nsIHTMLCollection> allParams;
820
NS_NAMED_LITERAL_STRING(xhtml_ns, "http://www.w3.org/1999/xhtml");
821
ErrorResult rv;
822
allParams = ourElement->GetElementsByTagNameNS(
823
xhtml_ns, NS_LITERAL_STRING("param"), rv);
824
if (rv.Failed()) {
825
return;
826
}
827
MOZ_ASSERT(allParams);
828
829
uint32_t numAllParams = allParams->Length();
830
for (uint32_t i = 0; i < numAllParams; i++) {
831
RefPtr<Element> element = allParams->Item(i);
832
833
nsAutoString name;
834
element->GetAttribute(NS_LITERAL_STRING("name"), name);
835
836
if (name.IsEmpty()) continue;
837
838
nsCOMPtr<nsIContent> parent = element->GetParent();
839
RefPtr<HTMLObjectElement> objectElement;
840
while (!objectElement && parent) {
841
objectElement = HTMLObjectElement::FromNode(parent);
842
parent = parent->GetParent();
843
}
844
845
if (objectElement) {
846
parent = objectElement;
847
} else {
848
continue;
849
}
850
851
if (parent == ourElement) {
852
MozPluginParameter param;
853
element->GetAttribute(NS_LITERAL_STRING("name"), param.mName);
854
element->GetAttribute(NS_LITERAL_STRING("value"), param.mValue);
855
856
param.mName.Trim(" \n\r\t\b", true, true, false);
857
param.mValue.Trim(" \n\r\t\b", true, true, false);
858
859
aParams.AppendElement(param);
860
}
861
}
862
}
863
864
nsresult nsObjectLoadingContent::BuildParametersArray() {
865
if (mCachedAttributes.Length() || mCachedParameters.Length()) {
866
MOZ_ASSERT(false, "Parameters array should be empty.");
867
return NS_OK;
868
}
869
870
nsCOMPtr<Element> element =
871
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
872
873
for (uint32_t i = 0; i != element->GetAttrCount(); i += 1) {
874
MozPluginParameter param;
875
const nsAttrName* attrName = element->GetAttrNameAt(i);
876
nsAtom* atom = attrName->LocalName();
877
element->GetAttr(attrName->NamespaceID(), atom, param.mValue);
878
atom->ToString(param.mName);
879
mCachedAttributes.AppendElement(param);
880
}
881
882
nsAutoCString wmodeOverride;
883
Preferences::GetCString("plugins.force.wmode", wmodeOverride);
884
885
for (uint32_t i = 0; i < mCachedAttributes.Length(); i++) {
886
if (!wmodeOverride.IsEmpty() &&
887
mCachedAttributes[i].mName.EqualsIgnoreCase("wmode")) {
888
CopyASCIItoUTF16(wmodeOverride, mCachedAttributes[i].mValue);
889
wmodeOverride.Truncate();
890
}
891
}
892
893
if (!wmodeOverride.IsEmpty()) {
894
MozPluginParameter param;
895
param.mName = NS_LITERAL_STRING("wmode");
896
CopyASCIItoUTF16(wmodeOverride, param.mValue);
897
mCachedAttributes.AppendElement(param);
898
}
899
900
// Some plugins were never written to understand the "data" attribute of the
901
// OBJECT tag. Real and WMP will not play unless they find a "src" attribute,
902
// see bug 152334. Nav 4.x would simply replace the "data" with "src". Because
903
// some plugins correctly look for "data", lets instead copy the "data"
904
// attribute and add another entry to the bottom of the array if there isn't
905
// already a "src" specified.
906
if (element->IsHTMLElement(nsGkAtoms::object) &&
907
!element->HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
908
MozPluginParameter param;
909
element->GetAttr(kNameSpaceID_None, nsGkAtoms::data, param.mValue);
910
if (!param.mValue.IsEmpty()) {
911
param.mName = NS_LITERAL_STRING("SRC");
912
mCachedAttributes.AppendElement(param);
913
}
914
}
915
916
GetNestedParams(mCachedParameters);
917
918
return NS_OK;
919
}
920
921
void nsObjectLoadingContent::NotifyOwnerDocumentActivityChanged() {
922
// XXX(johns): We cannot touch plugins or run arbitrary script from this call,
923
// as Document is in a non-reentrant state.
924
925
// If we have a plugin we want to queue an event to stop it unless we are
926
// moved into an active document before returning to the event loop.
927
if (mInstanceOwner || mInstantiating) {
928
QueueCheckPluginStopEvent();
929
}
930
nsImageLoadingContent::NotifyOwnerDocumentActivityChanged();
931
}
932
933
// nsIRequestObserver
934
NS_IMETHODIMP
935
nsObjectLoadingContent::OnStartRequest(nsIRequest* aRequest) {
936
AUTO_PROFILER_LABEL("nsObjectLoadingContent::OnStartRequest", NETWORK);
937
938
LOG(("OBJLC [%p]: Channel OnStartRequest", this));
939
940
if (aRequest != mChannel || !aRequest) {
941
// happens when a new load starts before the previous one got here
942
return NS_BINDING_ABORTED;
943
}
944
945
// If we already switched to type plugin, this channel can just be passed to
946
// the final listener.
947
if (mType == eType_Plugin) {
948
if (!mInstanceOwner) {
949
// We drop mChannel when stopping plugins, so something is wrong
950
MOZ_ASSERT_UNREACHABLE(
951
"Opened a channel in plugin mode, but don't have "
952
"a plugin");
953
return NS_BINDING_ABORTED;
954
}
955
if (MakePluginListener()) {
956
return mFinalListener->OnStartRequest(aRequest);
957
}
958
MOZ_ASSERT_UNREACHABLE(
959
"Failed to create PluginStreamListener, aborting "
960
"channel");
961
return NS_BINDING_ABORTED;
962
}
963
964
// Otherwise we should be state loading, and call LoadObject with the channel
965
if (mType != eType_Loading) {
966
MOZ_ASSERT_UNREACHABLE("Should be type loading at this point");
967
return NS_BINDING_ABORTED;
968
}
969
NS_ASSERTION(!mChannelLoaded, "mChannelLoaded set already?");
970
NS_ASSERTION(!mFinalListener, "mFinalListener exists already?");
971
972
mChannelLoaded = true;
973
974
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
975
NS_ASSERTION(chan, "Why is our request not a channel?");
976
977
nsresult status = NS_OK;
978
bool success = IsSuccessfulRequest(aRequest, &status);
979
980
if (status == NS_ERROR_BLOCKED_URI) {
981
nsCOMPtr<nsIConsoleService> console(
982
do_GetService("@mozilla.org/consoleservice;1"));
983
if (console) {
984
nsCOMPtr<nsIURI> uri;
985
chan->GetURI(getter_AddRefs(uri));
986
nsString message =
987
NS_LITERAL_STRING("Blocking ") +
988
NS_ConvertASCIItoUTF16(uri->GetSpecOrDefault().get()) +
989
NS_LITERAL_STRING(
990
" since it was found on an internal Firefox blocklist.");
991
console->LogStringMessage(message.get());
992
}
993
mContentBlockingEnabled = true;
994
return NS_ERROR_FAILURE;
995
}
996
997
if (UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(status)) {
998
mContentBlockingEnabled = true;
999
return NS_ERROR_FAILURE;
1000
}
1001
1002
if (!success) {
1003
LOG(("OBJLC [%p]: OnStartRequest: Request failed\n", this));
1004
// If the request fails, we still call LoadObject() to handle fallback
1005
// content and notifying of failure. (mChannelLoaded && !mChannel) indicates
1006
// the bad state.
1007
mChannel = nullptr;
1008
LoadObject(true, false);
1009
return NS_ERROR_FAILURE;
1010
}
1011
1012
return LoadObject(true, false, aRequest);
1013
}
1014
1015
NS_IMETHODIMP
1016
nsObjectLoadingContent::OnStopRequest(nsIRequest* aRequest,
1017
nsresult aStatusCode) {
1018
AUTO_PROFILER_LABEL("nsObjectLoadingContent::OnStopRequest", NETWORK);
1019
1020
// Handle object not loading error because source was a tracking URL (or
1021
// fingerprinting, cryptomining, etc.).
1022
// We make a note of this object node by including it in a dedicated
1023
// array of blocked tracking nodes under its parent document.
1024
if (UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(aStatusCode)) {
1025
nsCOMPtr<nsIContent> thisNode =
1026
do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
1027
if (thisNode && thisNode->IsInComposedDoc()) {
1028
thisNode->GetComposedDoc()->AddBlockedNodeByClassifier(thisNode);
1029
}
1030
}
1031
1032
if (aRequest != mChannel) {
1033
return NS_BINDING_ABORTED;
1034
}
1035
1036
mChannel = nullptr;
1037
1038
if (mFinalListener) {
1039
// This may re-enter in the case of plugin listeners
1040
nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
1041
mFinalListener = nullptr;
1042
listenerGrip->OnStopRequest(aRequest, aStatusCode);
1043
}
1044
1045
// Return value doesn't matter
1046
return NS_OK;
1047
}
1048
1049
// nsIStreamListener
1050
NS_IMETHODIMP
1051
nsObjectLoadingContent::OnDataAvailable(nsIRequest* aRequest,
1052
nsIInputStream* aInputStream,
1053
uint64_t aOffset, uint32_t aCount) {
1054
if (aRequest != mChannel) {
1055
return NS_BINDING_ABORTED;
1056
}
1057
1058
if (mFinalListener) {
1059
// This may re-enter in the case of plugin listeners
1060
nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
1061
return listenerGrip->OnDataAvailable(aRequest, aInputStream, aOffset,
1062
aCount);
1063
}
1064
1065
// We shouldn't have a connected channel with no final listener
1066
MOZ_ASSERT_UNREACHABLE(
1067
"Got data for channel with no connected final "
1068
"listener");
1069
mChannel = nullptr;
1070
1071
return NS_ERROR_UNEXPECTED;
1072
}
1073
1074
void nsObjectLoadingContent::PresetOpenerWindow(
1075
const Nullable<WindowProxyHolder>& aOpenerWindow, ErrorResult& aRv) {
1076
aRv.Throw(NS_ERROR_FAILURE);
1077
}
1078
1079
NS_IMETHODIMP
1080
nsObjectLoadingContent::GetActualType(nsACString& aType) {
1081
aType = mContentType;
1082
return NS_OK;
1083
}
1084
1085
NS_IMETHODIMP
1086
nsObjectLoadingContent::GetDisplayedType(uint32_t* aType) {
1087
*aType = DisplayedType();
1088
return NS_OK;
1089
}
1090
1091
NS_IMETHODIMP
1092
nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame) {
1093
if (mType != eType_Plugin) {
1094
return NS_OK;
1095
}
1096
1097
if (!aFrame) {
1098
// Lost our frame. If we aren't going to be getting a new frame, e.g. we've
1099
// become display:none, we'll want to stop the plugin. Queue a
1100
// CheckPluginStopEvent
1101
if (mInstanceOwner || mInstantiating) {
1102
if (mInstanceOwner) {
1103
mInstanceOwner->SetFrame(nullptr);
1104
}
1105
QueueCheckPluginStopEvent();
1106
}
1107
return NS_OK;
1108
}
1109
1110
// Have a new frame
1111
1112
if (!mInstanceOwner) {
1113
// We are successfully setup as type plugin, but have not spawned an
1114
// instance due to a lack of a frame.
1115
AsyncStartPluginInstance();
1116
return NS_OK;
1117
}
1118
1119
// Otherwise, we're just changing frames
1120
// Set up relationship between instance owner and frame.
1121
nsPluginFrame* objFrame = static_cast<nsPluginFrame*>(aFrame);
1122
mInstanceOwner->SetFrame(objFrame);
1123
1124
return NS_OK;
1125
}
1126
1127
nsNPAPIPluginInstance* nsObjectLoadingContent::GetPluginInstance() {
1128
if (!mInstanceOwner) {
1129
return nullptr;
1130
}
1131
1132
return mInstanceOwner->GetInstance();
1133
}
1134
1135
NS_IMETHODIMP
1136
nsObjectLoadingContent::GetContentTypeForMIMEType(const nsACString& aMIMEType,
1137
uint32_t* aType) {
1138
*aType = GetTypeOfContent(PromiseFlatCString(aMIMEType), false);
1139
return NS_OK;
1140
}
1141
1142
// nsIInterfaceRequestor
1143
// We use a shim class to implement this so that JS consumers still
1144
// see an interface requestor even though WebIDL bindings don't expose
1145
// that stuff.
1146
class ObjectInterfaceRequestorShim final : public nsIInterfaceRequestor,
1147
public nsIChannelEventSink,
1148
public nsIStreamListener {
1149
public:
1150
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
1151
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ObjectInterfaceRequestorShim,
1152
nsIInterfaceRequestor)
1153
NS_DECL_NSIINTERFACEREQUESTOR
1154
// RefPtr<nsObjectLoadingContent> fails due to ambiguous AddRef/Release,
1155
// hence the ugly static cast :(
1156
NS_FORWARD_NSICHANNELEVENTSINK(
1157
static_cast<nsObjectLoadingContent*>(mContent.get())->)
1158
NS_FORWARD_NSISTREAMLISTENER(
1159
static_cast<nsObjectLoadingContent*>(mContent.get())->)
1160
NS_FORWARD_NSIREQUESTOBSERVER(
1161
static_cast<nsObjectLoadingContent*>(mContent.get())->)
1162
1163
explicit ObjectInterfaceRequestorShim(nsIObjectLoadingContent* aContent)
1164
: mContent(aContent) {}
1165
1166
protected:
1167
~ObjectInterfaceRequestorShim() = default;
1168
nsCOMPtr<nsIObjectLoadingContent> mContent;
1169
};
1170
1171
NS_IMPL_CYCLE_COLLECTION(ObjectInterfaceRequestorShim, mContent)
1172
1173
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ObjectInterfaceRequestorShim)
1174
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
1175
NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
1176
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
1177
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
1178
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInterfaceRequestor)
1179
NS_INTERFACE_MAP_END
1180
1181
NS_IMPL_CYCLE_COLLECTING_ADDREF(ObjectInterfaceRequestorShim)
1182
NS_IMPL_CYCLE_COLLECTING_RELEASE(ObjectInterfaceRequestorShim)
1183
1184
NS_IMETHODIMP
1185
ObjectInterfaceRequestorShim::GetInterface(const nsIID& aIID, void** aResult) {
1186
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
1187
nsIChannelEventSink* sink = this;
1188
*aResult = sink;
1189
NS_ADDREF(sink);
1190
return NS_OK;
1191
}
1192
return NS_NOINTERFACE;
1193
}
1194
1195
// nsIChannelEventSink
1196
NS_IMETHODIMP
1197
nsObjectLoadingContent::AsyncOnChannelRedirect(
1198
nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags,
1199
nsIAsyncVerifyRedirectCallback* cb) {
1200
// If we're already busy with a new load, or have no load at all,
1201
// cancel the redirect.
1202
if (!mChannel || aOldChannel != mChannel) {
1203
return NS_BINDING_ABORTED;
1204
}
1205
1206
mChannel = aNewChannel;
1207
cb->OnRedirectVerifyCallback(NS_OK);
1208
return NS_OK;
1209
}
1210
1211
// <public>
1212
EventStates nsObjectLoadingContent::ObjectState() const {
1213
switch (mType) {
1214
case eType_Loading:
1215
return NS_EVENT_STATE_LOADING;
1216
case eType_Image:
1217
return ImageState();
1218
case eType_Plugin:
1219
case eType_FakePlugin:
1220
case eType_Document:
1221
// These are OK. If documents start to load successfully, they display
1222
// something, and are thus not broken in this sense. The same goes for
1223
// plugins.
1224
return EventStates();
1225
case eType_Null:
1226
switch (mFallbackType) {
1227
case eFallbackSuppressed:
1228
return NS_EVENT_STATE_SUPPRESSED;
1229
case eFallbackUserDisabled:
1230
return NS_EVENT_STATE_USERDISABLED;
1231
case eFallbackClickToPlay:
1232
case eFallbackClickToPlayQuiet:
1233
return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY;
1234
case eFallbackDisabled:
1235
return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_DISABLED;
1236
case eFallbackBlocklisted:
1237
return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_BLOCKED;
1238
case eFallbackCrashed:
1239
return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_CRASHED;
1240
case eFallbackUnsupported:
1241
case eFallbackOutdated:
1242
case eFallbackAlternate:
1243
return NS_EVENT_STATE_BROKEN;
1244
case eFallbackVulnerableUpdatable:
1245
return NS_EVENT_STATE_VULNERABLE_UPDATABLE;
1246
case eFallbackVulnerableNoUpdate:
1247
return NS_EVENT_STATE_VULNERABLE_NO_UPDATE;
1248
}
1249
}
1250
MOZ_ASSERT_UNREACHABLE("unknown type?");
1251
return NS_EVENT_STATE_LOADING;
1252
}
1253
1254
void nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI,
1255
nsIURI* aBaseURI,
1256
nsIURI** aOutURI) {
1257
nsCOMPtr<nsIContent> thisContent =
1258
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1259
NS_ASSERTION(thisContent, "Must be an instance of content");
1260
1261
// We're only interested in switching out embed and object tags
1262
if (!thisContent->NodeInfo()->Equals(nsGkAtoms::embed) &&
1263
!thisContent->NodeInfo()->Equals(nsGkAtoms::object)) {
1264
return;
1265
}
1266
1267
nsCOMPtr<nsIEffectiveTLDService> tldService =
1268
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
1269
// If we can't analyze the URL, just pass on through.
1270
if (!tldService) {
1271
NS_WARNING("Could not get TLD service!");
1272
return;
1273
}
1274
1275
nsAutoCString currentBaseDomain;
1276
bool ok = NS_SUCCEEDED(tldService->GetBaseDomain(aURI, 0, currentBaseDomain));
1277
if (!ok) {
1278
// Data URIs (commonly used for things like svg embeds) won't parse
1279
// correctly, so just fail silently here.
1280
return;
1281
}
1282
1283
// See if URL is referencing youtube
1284
if (!currentBaseDomain.EqualsLiteral("youtube.com") &&
1285
!currentBaseDomain.EqualsLiteral("youtube-nocookie.com")) {
1286
return;
1287
}
1288
1289
// We should only rewrite URLs with paths starting with "/v/", as we shouldn't
1290
// touch object nodes with "/embed/" urls that already do that right thing.
1291
nsAutoCString path;
1292
aURI->GetPathQueryRef(path);
1293
if (!StringBeginsWith(path, NS_LITERAL_CSTRING("/v/"))) {
1294
return;
1295
}
1296
1297
// See if requester is planning on using the JS API.
1298
nsAutoCString uri;
1299
nsresult rv = aURI->GetSpec(uri);
1300
if (NS_FAILED(rv)) {
1301
return;
1302
}
1303
1304
// Some YouTube urls have parameters in path components, e.g.
1305
// http://youtube.com/embed/7LcUOEP7Brc&start=35. These URLs work with flash,
1306
// but break iframe/object embedding. If this situation occurs with rewritten
1307
// URLs, convert the parameters to query in order to make the video load
1308
// correctly as an iframe. In either case, warn about it in the
1309
// developer console.
1310
int32_t ampIndex = uri.FindChar('&', 0);
1311
bool replaceQuery = false;
1312
if (ampIndex != -1) {
1313
int32_t qmIndex = uri.FindChar('?', 0);
1314
if (qmIndex == -1 || qmIndex > ampIndex) {
1315
replaceQuery = true;
1316
}
1317
}
1318
1319
// If we're pref'd off, return after telemetry has been logged.
1320
if (!Preferences::GetBool(kPrefYoutubeRewrite)) {
1321
return;
1322
}
1323
1324
nsAutoString utf16OldURI = NS_ConvertUTF8toUTF16(uri);
1325
// If we need to convert the URL, it means an ampersand comes first.
1326
// Use the index we found earlier.
1327
if (replaceQuery) {
1328
// Replace question marks with ampersands.
1329
uri.ReplaceChar('?', '&');
1330
// Replace the first ampersand with a question mark.
1331
uri.SetCharAt('?', ampIndex);
1332
}
1333
// Switch out video access url formats, which should possibly allow HTML5
1334
// video loading.
1335
uri.ReplaceSubstring(NS_LITERAL_CSTRING("/v/"),
1336
NS_LITERAL_CSTRING("/embed/"));
1337
nsAutoString utf16URI = NS_ConvertUTF8toUTF16(uri);
1338
rv = nsContentUtils::NewURIWithDocumentCharset(
1339
aOutURI, utf16URI, thisContent->OwnerDoc(), aBaseURI);
1340
if (NS_FAILED(rv)) {
1341
return;
1342
}
1343
AutoTArray<nsString, 2> params = {utf16OldURI, utf16URI};
1344
const char* msgName;
1345
// If there's no query to rewrite, just notify in the developer console
1346
// that we're changing the embed.
1347
if (!replaceQuery) {
1348
msgName = "RewriteYouTubeEmbed";
1349
} else {
1350
msgName = "RewriteYouTubeEmbedPathParams";
1351
}
1352
nsContentUtils::ReportToConsole(
1353
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Plugins"),
1354
thisContent->OwnerDoc(), nsContentUtils::eDOM_PROPERTIES, msgName,
1355
params);
1356
}
1357
1358
bool nsObjectLoadingContent::CheckLoadPolicy(int16_t* aContentPolicy) {
1359
if (!aContentPolicy || !mURI) {
1360
MOZ_ASSERT_UNREACHABLE("Doing it wrong");
1361
return false;
1362
}
1363
1364
nsCOMPtr<nsIContent> thisContent =
1365
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1366
NS_ASSERTION(thisContent, "Must be an instance of content");
1367
1368
Document* doc = thisContent->OwnerDoc();
1369
1370
nsContentPolicyType contentPolicyType = GetContentPolicyType();
1371
1372
nsCOMPtr<nsILoadInfo> secCheckLoadInfo = new LoadInfo(
1373
doc->NodePrincipal(), // loading principal
1374
doc->NodePrincipal(), // triggering principal
1375
thisContent, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
1376
contentPolicyType);
1377
1378
*aContentPolicy = nsIContentPolicy::ACCEPT;
1379
nsresult rv = NS_CheckContentLoadPolicy(mURI, secCheckLoadInfo, mContentType,
1380
aContentPolicy,
1381
nsContentUtils::GetContentPolicy());
1382
NS_ENSURE_SUCCESS(rv, false);
1383
if (NS_CP_REJECTED(*aContentPolicy)) {
1384
LOG(("OBJLC [%p]: Content policy denied load of %s", this,
1385
mURI->GetSpecOrDefault().get()));
1386
return false;
1387
}
1388
1389
return true;
1390
}
1391
1392
bool nsObjectLoadingContent::CheckProcessPolicy(int16_t* aContentPolicy) {
1393
if (!aContentPolicy) {
1394
MOZ_ASSERT_UNREACHABLE("Null out variable");
1395
return false;
1396
}
1397
1398
nsCOMPtr<nsIContent> thisContent =
1399
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1400
NS_ASSERTION(thisContent, "Must be an instance of content");
1401
1402
Document* doc = thisContent->OwnerDoc();
1403
1404
int32_t objectType;
1405
switch (mType) {
1406
case eType_Image:
1407
objectType = nsIContentPolicy::TYPE_INTERNAL_IMAGE;
1408
break;
1409
case eType_Document:
1410
objectType = nsIContentPolicy::TYPE_DOCUMENT;
1411
break;
1412
// FIXME Fake plugins look just like real plugins to CSP, should they use
1413
// the fake plugin's handler URI and look like documents instead?
1414
case eType_FakePlugin:
1415
case eType_Plugin:
1416
objectType = GetContentPolicyType();
1417
break;
1418
default:
1419
MOZ_ASSERT_UNREACHABLE(
1420
"Calling checkProcessPolicy with an unloadable "
1421
"type");
1422
return false;
1423
}
1424
1425
nsCOMPtr<nsILoadInfo> secCheckLoadInfo = new LoadInfo(
1426
doc->NodePrincipal(), // loading principal
1427
doc->NodePrincipal(), // triggering principal
1428
thisContent, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
1429
objectType);
1430
1431
*aContentPolicy = nsIContentPolicy::ACCEPT;
1432
nsresult rv = NS_CheckContentProcessPolicy(
1433
mURI ? mURI : mBaseURI, secCheckLoadInfo, mContentType, aContentPolicy,
1434
nsContentUtils::GetContentPolicy());
1435
NS_ENSURE_SUCCESS(rv, false);
1436
1437
if (NS_CP_REJECTED(*aContentPolicy)) {
1438
LOG(("OBJLC [%p]: CheckContentProcessPolicy rejected load", this));
1439
return false;
1440
}
1441
1442
return true;
1443
}
1444
1445
nsObjectLoadingContent::ParameterUpdateFlags
1446
nsObjectLoadingContent::UpdateObjectParameters() {
1447
nsCOMPtr<Element> thisElement =
1448
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1449
MOZ_ASSERT(thisElement, "Must be an Element");
1450
1451
uint32_t caps = GetCapabilities();
1452
LOG(("OBJLC [%p]: Updating object parameters", this));
1453
1454
nsresult rv;
1455
nsAutoCString newMime;
1456
nsAutoString typeAttr;
1457
nsCOMPtr<nsIURI> newURI;
1458
nsCOMPtr<nsIURI> newBaseURI;
1459
ObjectType newType;
1460
// Set if this state can't be used to load anything, forces eType_Null
1461
bool stateInvalid = false;
1462
// Indicates what parameters changed.
1463
// eParamChannelChanged - means parameters that affect channel opening
1464
// decisions changed
1465
// eParamStateChanged - means anything that affects what content we load
1466
// changed, even if the channel we'd open remains the
1467
// same.
1468
//
1469
// State changes outside of the channel parameters only matter if we've
1470
// already opened a channel or tried to instantiate content, whereas channel
1471
// parameter changes require re-opening the channel even if we haven't gotten
1472
// that far.
1473
nsObjectLoadingContent::ParameterUpdateFlags retval = eParamNoChange;
1474
1475
///
1476
/// Initial MIME Type
1477
///
1478
1479
if (caps & eFallbackIfClassIDPresent) {
1480
nsAutoString classIDAttr;
1481
thisElement->GetAttr(kNameSpaceID_None, nsGkAtoms::classid, classIDAttr);
1482
// We don't support class ID plugin references, so we should always treat
1483
// having class Ids as attributes as invalid, and fallback accordingly.
1484
if (!classIDAttr.IsEmpty()) {
1485
newMime.Truncate();
1486
stateInvalid = true;
1487
}
1488
}
1489
1490
///
1491
/// Codebase
1492
///
1493
1494
nsAutoString codebaseStr;
1495
nsIURI* docBaseURI = thisElement->GetBaseURI();
1496
thisElement->GetAttr(kNameSpaceID_None, nsGkAtoms::codebase, codebaseStr);
1497
1498
if (!codebaseStr.IsEmpty()) {
1499
rv = nsContentUtils::NewURIWithDocumentCharset(
1500
getter_AddRefs(newBaseURI), codebaseStr, thisElement->OwnerDoc(),
1501
docBaseURI);
1502
if (NS_FAILED(rv)) {
1503
// Malformed URI
1504
LOG(
1505
("OBJLC [%p]: Could not parse plugin's codebase as a URI, "
1506
"will use document baseURI instead",
1507
this));
1508
}
1509
}
1510
1511
// If we failed to build a valid URI, use the document's base URI
1512
if (!newBaseURI) {
1513
newBaseURI = docBaseURI;
1514
}
1515
1516
nsAutoString rawTypeAttr;
1517
thisElement->GetAttr(kNameSpaceID_None, nsGkAtoms::type, rawTypeAttr);
1518
if (!rawTypeAttr.IsEmpty()) {
1519
typeAttr = rawTypeAttr;
1520
nsAutoString params;
1521
nsAutoString mime;
1522
nsContentUtils::SplitMimeType(rawTypeAttr, mime, params);
1523
CopyUTF16toUTF8(mime, newMime);
1524
}
1525
1526
///
1527
/// URI
1528
///
1529
1530
nsAutoString uriStr;
1531
// Different elements keep this in various locations
1532
if (thisElement->NodeInfo()->Equals(nsGkAtoms::object)) {
1533
thisElement->GetAttr(kNameSpaceID_None, nsGkAtoms::data, uriStr);
1534
} else if (thisElement->NodeInfo()->Equals(nsGkAtoms::embed)) {
1535
thisElement->GetAttr(kNameSpaceID_None, nsGkAtoms::src, uriStr);
1536
} else {
1537
MOZ_ASSERT_UNREACHABLE("Unrecognized plugin-loading tag");
1538
}
1539
1540
mRewrittenYoutubeEmbed = false;
1541
// Note that the baseURI changing could affect the newURI, even if uriStr did
1542
// not change.
1543
if (!uriStr.IsEmpty()) {
1544
rv = nsContentUtils::NewURIWithDocumentCharset(
1545
getter_AddRefs(newURI), uriStr, thisElement->OwnerDoc(), newBaseURI);
1546
nsCOMPtr<nsIURI> rewrittenURI;
1547
MaybeRewriteYoutubeEmbed(newURI, newBaseURI, getter_AddRefs(rewrittenURI));
1548
if (rewrittenURI) {
1549
newURI = rewrittenURI;
1550
mRewrittenYoutubeEmbed = true;
1551
newMime = NS_LITERAL_CSTRING("text/html");
1552
}
1553
1554
if (NS_FAILED(rv)) {
1555
stateInvalid = true;
1556
}
1557
}
1558
1559
// For eAllowPluginSkipChannel tags, if we have a non-plugin type, but can get
1560
// a plugin type from the extension, prefer that to falling back to a channel.
1561
if (!IsPluginType(GetTypeOfContent(newMime, mSkipFakePlugins)) && newURI &&
1562
(caps & eAllowPluginSkipChannel) &&
1563
IsPluginEnabledByExtension(newURI, newMime)) {
1564
LOG(("OBJLC [%p]: Using extension as type hint (%s)", this, newMime.get()));
1565
}
1566
1567
///
1568
/// Check if the original (pre-channel) content-type or URI changed, and
1569
/// record mOriginal{ContentType,URI}
1570
///
1571
1572
if ((mOriginalContentType != newMime) || !URIEquals(mOriginalURI, newURI)) {
1573
// These parameters changing requires re-opening the channel, so don't
1574
// consider the currently-open channel below
1575
// XXX(johns): Changing the mime type might change our decision on whether
1576
// or not we load a channel, so we count changes to it as a
1577
// channel parameter change for the sake of simplicity.
1578
retval = (ParameterUpdateFlags)(retval | eParamChannelChanged);
1579
LOG(("OBJLC [%p]: Channel parameters changed", this));
1580
}
1581
mOriginalContentType = newMime;
1582
mOriginalURI = newURI;
1583
1584
///
1585
/// If we have a channel, see if its MIME type should take precendence and
1586
/// check the final (redirected) URL
1587
///
1588
1589
// If we have a loaded channel and channel parameters did not change, use it
1590
// to determine what we would load.
1591
bool useChannel = mChannelLoaded && !(retval & eParamChannelChanged);
1592
// If we have a channel and are type loading, as opposed to having an existing
1593
// channel for a previous load.
1594
bool newChannel = useChannel && mType == eType_Loading;
1595
1596
if (newChannel && mChannel) {
1597
nsCString channelType;
1598
rv = mChannel->GetContentType(channelType);
1599
if (NS_FAILED(rv)) {
1600
MOZ_ASSERT_UNREACHABLE("GetContentType failed");
1601
stateInvalid = true;
1602
channelType.Truncate();
1603
}
1604
1605
LOG(("OBJLC [%p]: Channel has a content type of %s", this,
1606
channelType.get()));
1607
1608
bool binaryChannelType = false;
1609
if (channelType.EqualsASCII(APPLICATION_GUESS_FROM_EXT)) {
1610
channelType = APPLICATION_OCTET_STREAM;
1611
mChannel->SetContentType(channelType);
1612
binaryChannelType = true;
1613
} else if (channelType.EqualsASCII(APPLICATION_OCTET_STREAM) ||
1614
channelType.EqualsASCII(BINARY_OCTET_STREAM)) {
1615
binaryChannelType = true;
1616
}
1617
1618
// Channel can change our URI through redirection
1619
rv = NS_GetFinalChannelURI(mChannel, getter_AddRefs(newURI));
1620
if (NS_FAILED(rv)) {
1621
MOZ_ASSERT_UNREACHABLE("NS_GetFinalChannelURI failure");
1622
stateInvalid = true;
1623
}
1624
1625
ObjectType typeHint = newMime.IsEmpty()
1626
? eType_Null
1627
: GetTypeOfContent(newMime, mSkipFakePlugins);
1628
1629
//
1630
// In order of preference:
1631
//
1632
// 1) Use our type hint if it matches a plugin
1633
// 2) If we have eAllowPluginSkipChannel, use the uri file extension if
1634
// it matches a plugin
1635
// 3) If the channel returns a binary stream type:
1636
// 3a) If we have a type non-null non-document type hint, use that
1637
// 3b) If the uri file extension matches a plugin type, use that
1638
// 4) Use the channel type
1639
1640
bool overrideChannelType = false;
1641
if (IsPluginType(typeHint)) {
1642
LOG(("OBJLC [%p]: Using plugin type hint in favor of any channel type",
1643
this));
1644
overrideChannelType = true;
1645
} else if ((caps & eAllowPluginSkipChannel) &&
1646
IsPluginEnabledByExtension(newURI, newMime)) {
1647
LOG(
1648
("OBJLC [%p]: Using extension as type hint for "
1649
"eAllowPluginSkipChannel tag (%s)",
1650
this, newMime.get()));
1651
overrideChannelType = true;
1652
} else if (binaryChannelType && typeHint != eType_Null &&
1653
typeHint != eType_Document) {
1654
LOG(("OBJLC [%p]: Using type hint in favor of binary channel type",
1655
this));
1656
overrideChannelType = true;
1657
} else if (binaryChannelType &&
1658
IsPluginEnabledByExtension(newURI, newMime)) {
1659
LOG(("OBJLC [%p]: Using extension as type hint for binary channel (%s)",
1660
this, newMime.get()));
1661
overrideChannelType = true;
1662
}
1663
1664
if (overrideChannelType) {
1665
// Set the type we'll use for dispatch on the channel. Otherwise we could
1666
// end up trying to dispatch to a nsFrameLoader, which will complain that
1667
// it couldn't find a way to handle application/octet-stream
1668
nsAutoCString parsedMime, dummy;
1669
NS_ParseResponseContentType(newMime, parsedMime, dummy);
1670
if (!parsedMime.IsEmpty()) {
1671
mChannel->SetContentType(parsedMime);
1672
}
1673
} else {
1674
newMime = channelType;
1675
}
1676
} else if (newChannel) {
1677
LOG(("OBJLC [%p]: We failed to open a channel, marking invalid", this));
1678
stateInvalid = true;
1679
}
1680
1681
///
1682
/// Determine final type
1683
///
1684
// In order of preference:
1685
// 1) If we have attempted channel load, or set stateInvalid above, the type
1686
// is always null (fallback)
1687
// 2) If we have a loaded channel, we grabbed its mimeType above, use that
1688
// type.
1689
// 3) If we have a plugin type and no URI, use that type.
1690
// 4) If we have a plugin type and eAllowPluginSkipChannel, use that type.
1691
// 5) if we have a URI, set type to loading to indicate we'd need a channel
1692
// to proceed.
1693
// 6) Otherwise, type null to indicate unloadable content (fallback)
1694
//
1695
1696
ObjectType newMime_Type = GetTypeOfContent(newMime, mSkipFakePlugins);
1697
1698
if (stateInvalid) {
1699
newType = eType_Null;
1700
newMime.Truncate();
1701
} else if (newChannel) {
1702
// If newChannel is set above, we considered it in setting newMime
1703
newType = newMime_Type;
1704
LOG(("OBJLC [%p]: Using channel type", this));
1705
} else if (((caps & eAllowPluginSkipChannel) || !newURI) &&
1706
IsPluginType(newMime_Type)) {
1707
newType = newMime_Type;
1708
LOG(("OBJLC [%p]: Plugin type with no URI, skipping channel load", this));
1709
} else if (newURI &&
1710
(mOriginalContentType.IsEmpty() || newMime_Type != eType_Null)) {
1711
// We could potentially load this if we opened a channel on mURI, indicate
1712
// this by leaving type as loading.
1713
//
1714
// If a MIME type was requested in the tag, but we have decided to set load
1715
// type to null, ignore (otherwise we'll default to document type loading).
1716
newType = eType_Loading;
1717
} else {
1718
// Unloadable - no URI, and no plugin/MIME type. Non-plugin types (images,
1719
// documents) always load with a channel.
1720
newType = eType_Null;
1721
}
1722
1723
///
1724
/// Handle existing channels
1725
///
1726
1727
if (useChannel && newType == eType_Loading) {
1728
// We decided to use a channel, and also that the previous channel is still
1729
// usable, so re-use the existing values.
1730
newType = mType;
1731
newMime = mContentType;
1732
newURI = mURI;
1733
} else if (useChannel && !newChannel) {
1734
// We have an existing channel, but did not decide to use one.
1735
retval = (ParameterUpdateFlags)(retval | eParamChannelChanged);
1736
useChannel = false;
1737
}
1738
1739
///
1740
/// Update changed values
1741
///
1742
1743
if (newType != mType) {
1744
retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
1745
LOG(("OBJLC [%p]: Type changed from %u -> %u", this, mType, newType));
1746
bool updateIMEState = (mType == eType_Loading && newType == eType_Plugin);
1747
mType = newType;
1748
// The IME manager needs to know if this is a plugin so it can adjust
1749
// input handling to an appropriate mode for plugins.
1750
nsFocusManager* fm = nsFocusManager::GetFocusManager();
1751
nsCOMPtr<nsIContent> thisContent =
1752
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1753
MOZ_ASSERT(thisContent, "should have content");
1754
if (updateIMEState && thisContent && fm && fm->IsFocused(thisContent)) {
1755
widget::IMEState state;
1756
state.mEnabled = widget::IMEState::PLUGIN;
1757
state.mOpen = widget::IMEState::DONT_CHANGE_OPEN_STATE;
1758
IMEStateManager::UpdateIMEState(state, thisContent, nullptr);
1759
}
1760
}
1761
1762
if (!URIEquals(mBaseURI, newBaseURI)) {
1763
LOG(("OBJLC [%p]: Object effective baseURI changed", this));
1764
mBaseURI = newBaseURI;
1765
}
1766
1767
if (!URIEquals(newURI, mURI)) {
1768
retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
1769
LOG(("OBJLC [%p]: Object effective URI changed", this));
1770
mURI = newURI;
1771
}
1772
1773
// We don't update content type when loading, as the type is not final and we
1774
// don't want to superfluously change between mOriginalContentType ->
1775
// mContentType when doing |obj.data = obj.data| with a channel and differing
1776
// type.
1777
if (mType != eType_Loading && mContentType != newMime) {
1778
retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
1779
retval = (ParameterUpdateFlags)(retval | eParamContentTypeChanged);
1780
LOG(("OBJLC [%p]: Object effective mime type changed (%s -> %s)", this,
1781
mContentType.get(), newMime.get()));
1782
mContentType = newMime;
1783
}
1784
1785
// If we decided to keep using info from an old channel, but also that state
1786
// changed, we need to invalidate it.
1787
if (useChannel && !newChannel && (retval & eParamStateChanged)) {
1788
mType = eType_Loading;
1789
retval = (ParameterUpdateFlags)(retval | eParamChannelChanged);
1790
}
1791
1792
return retval;
1793
}
1794
1795
// Used by PluginDocument to kick off our initial load from the already-opened
1796
// channel.
1797
NS_IMETHODIMP
1798
nsObjectLoadingContent::InitializeFromChannel(nsIRequest* aChannel) {
1799
LOG(("OBJLC [%p] InitializeFromChannel: %p", this, aChannel));
1800
if (mType != eType_Loading || mChannel) {
1801
// We could technically call UnloadObject() here, if consumers have a valid
1802
// reason for wanting to call this on an already-loaded tag.
1803
MOZ_ASSERT_UNREACHABLE("Should not have begun loading at this point");
1804
return NS_ERROR_UNEXPECTED;
1805
}
1806
1807
// Because we didn't open this channel from an initial LoadObject, we'll
1808
// update our parameters now, so the OnStartRequest->LoadObject doesn't