1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : // vim:set et cin sw=2 sts=2:
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla <object> loading code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Christian Biesinger <cbiesinger@web.de>.
20 : * Portions created by the Initial Developer are Copyright (C) 2005
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Justin Dolske <dolske@mozilla.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : /*
41 : * A base class implementing nsIObjectLoadingContent for use by
42 : * various content nodes that want to provide plugin/document/image
43 : * loading functionality (eg <embed>, <object>, <applet>, etc).
44 : */
45 :
46 : // Interface headers
47 : #include "imgILoader.h"
48 : #include "nsEventDispatcher.h"
49 : #include "nsIContent.h"
50 : #include "nsIDocShell.h"
51 : #include "nsIDocument.h"
52 : #include "nsIDOMDataContainerEvent.h"
53 : #include "nsIDOMDocument.h"
54 : #include "nsIDOMEventTarget.h"
55 : #include "nsIExternalProtocolHandler.h"
56 : #include "nsEventStates.h"
57 : #include "nsIObjectFrame.h"
58 : #include "nsIPluginDocument.h"
59 : #include "nsPluginHost.h"
60 : #include "nsIPresShell.h"
61 : #include "nsIPrivateDOMEvent.h"
62 : #include "nsIScriptGlobalObject.h"
63 : #include "nsIScriptSecurityManager.h"
64 : #include "nsIStreamConverterService.h"
65 : #include "nsIURILoader.h"
66 : #include "nsIURL.h"
67 : #include "nsIWebNavigation.h"
68 : #include "nsIWebNavigationInfo.h"
69 : #include "nsIScriptChannel.h"
70 : #include "nsIBlocklistService.h"
71 : #include "nsIAsyncVerifyRedirectCallback.h"
72 : #include "nsIAppShell.h"
73 :
74 : #include "nsPluginError.h"
75 :
76 : // Util headers
77 : #include "prlog.h"
78 :
79 : #include "nsAutoPtr.h"
80 : #include "nsCURILoader.h"
81 : #include "nsContentPolicyUtils.h"
82 : #include "nsContentUtils.h"
83 : #include "nsDocShellCID.h"
84 : #include "nsGkAtoms.h"
85 : #include "nsThreadUtils.h"
86 : #include "nsNetUtil.h"
87 : #include "nsMimeTypes.h"
88 : #include "nsStyleUtil.h"
89 : #include "nsGUIEvent.h"
90 : #include "nsUnicharUtils.h"
91 :
92 : // Concrete classes
93 : #include "nsFrameLoader.h"
94 :
95 : #include "nsObjectLoadingContent.h"
96 : #include "mozAutoDocUpdate.h"
97 : #include "nsIContentSecurityPolicy.h"
98 : #include "nsIChannelPolicy.h"
99 : #include "nsChannelPolicy.h"
100 : #include "mozilla/dom/Element.h"
101 : #include "sampler.h"
102 : #include "nsObjectFrame.h"
103 : #include "nsDOMClassInfo.h"
104 :
105 : #include "nsWidgetsCID.h"
106 : #include "nsContentCID.h"
107 : static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
108 :
109 : #ifdef PR_LOGGING
110 1396 : static PRLogModuleInfo* gObjectLog = PR_NewLogModule("objlc");
111 : #endif
112 :
113 : #define LOG(args) PR_LOG(gObjectLog, PR_LOG_DEBUG, args)
114 : #define LOG_ENABLED() PR_LOG_TEST(gObjectLog, PR_LOG_DEBUG)
115 :
116 : #include "mozilla/Preferences.h"
117 :
118 : class nsAsyncInstantiateEvent : public nsRunnable {
119 : public:
120 : nsObjectLoadingContent *mContent;
121 0 : nsAsyncInstantiateEvent(nsObjectLoadingContent* aContent)
122 0 : : mContent(aContent)
123 : {
124 0 : static_cast<nsIObjectLoadingContent *>(mContent)->AddRef();
125 0 : }
126 :
127 0 : ~nsAsyncInstantiateEvent()
128 0 : {
129 0 : static_cast<nsIObjectLoadingContent *>(mContent)->Release();
130 0 : }
131 :
132 : NS_IMETHOD Run();
133 : };
134 :
135 : NS_IMETHODIMP
136 0 : nsAsyncInstantiateEvent::Run()
137 : {
138 : // do nothing if we've been revoked
139 0 : if (mContent->mPendingInstantiateEvent != this) {
140 0 : return NS_OK;
141 : }
142 0 : mContent->mPendingInstantiateEvent = nsnull;
143 :
144 0 : return mContent->SyncStartPluginInstance();
145 : }
146 :
147 : // Checks to see if the content for a plugin instance has a parent.
148 : // The plugin instance is stopped if there is no parent.
149 : class InDocCheckEvent : public nsRunnable {
150 : public:
151 : nsCOMPtr<nsIContent> mContent;
152 :
153 0 : InDocCheckEvent(nsIContent* aContent)
154 0 : : mContent(aContent)
155 : {
156 0 : }
157 :
158 0 : ~InDocCheckEvent()
159 0 : {
160 0 : }
161 :
162 : NS_IMETHOD Run();
163 : };
164 :
165 : NS_IMETHODIMP
166 0 : InDocCheckEvent::Run()
167 : {
168 0 : if (!mContent->IsInDoc()) {
169 0 : nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(mContent);
170 0 : if (olc) {
171 0 : olc->StopPluginInstance();
172 : }
173 : }
174 0 : return NS_OK;
175 : }
176 :
177 : /**
178 : * A task for firing PluginNotFound and PluginBlocklisted DOM Events.
179 : */
180 : class nsPluginErrorEvent : public nsRunnable {
181 : public:
182 : nsCOMPtr<nsIContent> mContent;
183 : PluginSupportState mState;
184 :
185 0 : nsPluginErrorEvent(nsIContent* aContent, PluginSupportState aState)
186 : : mContent(aContent),
187 0 : mState(aState)
188 0 : {}
189 :
190 0 : ~nsPluginErrorEvent() {}
191 :
192 : NS_IMETHOD Run();
193 : };
194 :
195 : NS_IMETHODIMP
196 0 : nsPluginErrorEvent::Run()
197 : {
198 0 : LOG(("OBJLC []: Firing plugin not found event for content %p\n",
199 : mContent.get()));
200 0 : nsString type;
201 0 : switch (mState) {
202 : case ePluginClickToPlay:
203 0 : type = NS_LITERAL_STRING("PluginClickToPlay");
204 0 : break;
205 : case ePluginUnsupported:
206 0 : type = NS_LITERAL_STRING("PluginNotFound");
207 0 : break;
208 : case ePluginDisabled:
209 0 : type = NS_LITERAL_STRING("PluginDisabled");
210 0 : break;
211 : case ePluginBlocklisted:
212 0 : type = NS_LITERAL_STRING("PluginBlocklisted");
213 0 : break;
214 : case ePluginOutdated:
215 0 : type = NS_LITERAL_STRING("PluginOutdated");
216 0 : break;
217 : default:
218 0 : return NS_OK;
219 : }
220 : nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent,
221 0 : type, true, true);
222 :
223 0 : return NS_OK;
224 : }
225 :
226 : /**
227 : * A task for firing PluginCrashed DOM Events.
228 : */
229 : class nsPluginCrashedEvent : public nsRunnable {
230 : public:
231 : nsCOMPtr<nsIContent> mContent;
232 : nsString mPluginDumpID;
233 : nsString mBrowserDumpID;
234 : nsString mPluginName;
235 : nsString mPluginFilename;
236 : bool mSubmittedCrashReport;
237 :
238 0 : nsPluginCrashedEvent(nsIContent* aContent,
239 : const nsAString& aPluginDumpID,
240 : const nsAString& aBrowserDumpID,
241 : const nsAString& aPluginName,
242 : const nsAString& aPluginFilename,
243 : bool submittedCrashReport)
244 : : mContent(aContent),
245 : mPluginDumpID(aPluginDumpID),
246 : mBrowserDumpID(aBrowserDumpID),
247 : mPluginName(aPluginName),
248 : mPluginFilename(aPluginFilename),
249 0 : mSubmittedCrashReport(submittedCrashReport)
250 0 : {}
251 :
252 0 : ~nsPluginCrashedEvent() {}
253 :
254 : NS_IMETHOD Run();
255 : };
256 :
257 : NS_IMETHODIMP
258 0 : nsPluginCrashedEvent::Run()
259 : {
260 0 : LOG(("OBJLC []: Firing plugin crashed event for content %p\n",
261 : mContent.get()));
262 :
263 : nsCOMPtr<nsIDOMDocument> domDoc =
264 0 : do_QueryInterface(mContent->GetDocument());
265 0 : if (!domDoc) {
266 0 : NS_WARNING("Couldn't get document for PluginCrashed event!");
267 0 : return NS_OK;
268 : }
269 :
270 0 : nsCOMPtr<nsIDOMEvent> event;
271 0 : domDoc->CreateEvent(NS_LITERAL_STRING("datacontainerevents"),
272 0 : getter_AddRefs(event));
273 0 : nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
274 0 : nsCOMPtr<nsIDOMDataContainerEvent> containerEvent(do_QueryInterface(event));
275 0 : if (!privateEvent || !containerEvent) {
276 0 : NS_WARNING("Couldn't QI event for PluginCrashed event!");
277 0 : return NS_OK;
278 : }
279 :
280 0 : event->InitEvent(NS_LITERAL_STRING("PluginCrashed"), true, true);
281 0 : privateEvent->SetTrusted(true);
282 0 : privateEvent->GetInternalNSEvent()->flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
283 :
284 0 : nsCOMPtr<nsIWritableVariant> variant;
285 :
286 : // add a "pluginDumpID" property to this event
287 0 : variant = do_CreateInstance("@mozilla.org/variant;1");
288 0 : if (!variant) {
289 0 : NS_WARNING("Couldn't create pluginDumpID variant for PluginCrashed event!");
290 0 : return NS_OK;
291 : }
292 0 : variant->SetAsAString(mPluginDumpID);
293 0 : containerEvent->SetData(NS_LITERAL_STRING("pluginDumpID"), variant);
294 :
295 : // add a "browserDumpID" property to this event
296 0 : variant = do_CreateInstance("@mozilla.org/variant;1");
297 0 : if (!variant) {
298 0 : NS_WARNING("Couldn't create browserDumpID variant for PluginCrashed event!");
299 0 : return NS_OK;
300 : }
301 0 : variant->SetAsAString(mBrowserDumpID);
302 0 : containerEvent->SetData(NS_LITERAL_STRING("browserDumpID"), variant);
303 :
304 : // add a "pluginName" property to this event
305 0 : variant = do_CreateInstance("@mozilla.org/variant;1");
306 0 : if (!variant) {
307 0 : NS_WARNING("Couldn't create pluginName variant for PluginCrashed event!");
308 0 : return NS_OK;
309 : }
310 0 : variant->SetAsAString(mPluginName);
311 0 : containerEvent->SetData(NS_LITERAL_STRING("pluginName"), variant);
312 :
313 : // add a "pluginFilename" property to this event
314 0 : variant = do_CreateInstance("@mozilla.org/variant;1");
315 0 : if (!variant) {
316 0 : NS_WARNING("Couldn't create pluginFilename variant for PluginCrashed event!");
317 0 : return NS_OK;
318 : }
319 0 : variant->SetAsAString(mPluginFilename);
320 0 : containerEvent->SetData(NS_LITERAL_STRING("pluginFilename"), variant);
321 :
322 : // add a "submittedCrashReport" property to this event
323 0 : variant = do_CreateInstance("@mozilla.org/variant;1");
324 0 : if (!variant) {
325 0 : NS_WARNING("Couldn't create crashSubmit variant for PluginCrashed event!");
326 0 : return NS_OK;
327 : }
328 0 : variant->SetAsBool(mSubmittedCrashReport);
329 0 : containerEvent->SetData(NS_LITERAL_STRING("submittedCrashReport"), variant);
330 :
331 0 : nsEventDispatcher::DispatchDOMEvent(mContent, nsnull, event, nsnull, nsnull);
332 0 : return NS_OK;
333 : }
334 :
335 : class nsStopPluginRunnable : public nsRunnable, public nsITimerCallback
336 0 : {
337 : public:
338 : NS_DECL_ISUPPORTS_INHERITED
339 :
340 0 : nsStopPluginRunnable(nsPluginInstanceOwner *aInstanceOwner)
341 0 : : mInstanceOwner(aInstanceOwner)
342 : {
343 0 : NS_ASSERTION(aInstanceOwner, "need an owner");
344 0 : }
345 :
346 : // nsRunnable
347 : NS_IMETHOD Run();
348 :
349 : // nsITimerCallback
350 : NS_IMETHOD Notify(nsITimer *timer);
351 :
352 : private:
353 : nsCOMPtr<nsITimer> mTimer;
354 : nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
355 : };
356 :
357 0 : NS_IMPL_ISUPPORTS_INHERITED1(nsStopPluginRunnable, nsRunnable, nsITimerCallback)
358 :
359 : NS_IMETHODIMP
360 0 : nsStopPluginRunnable::Notify(nsITimer *aTimer)
361 : {
362 0 : return Run();
363 : }
364 :
365 : NS_IMETHODIMP
366 0 : nsStopPluginRunnable::Run()
367 : {
368 : // InitWithCallback calls Release before AddRef so we need to hold a
369 : // strong ref on 'this' since we fall through to this scope if it fails.
370 0 : nsCOMPtr<nsITimerCallback> kungFuDeathGrip = this;
371 0 : nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
372 0 : if (appShell) {
373 0 : PRUint32 currentLevel = 0;
374 0 : appShell->GetEventloopNestingLevel(¤tLevel);
375 0 : if (currentLevel > mInstanceOwner->GetLastEventloopNestingLevel()) {
376 0 : if (!mTimer)
377 0 : mTimer = do_CreateInstance("@mozilla.org/timer;1");
378 0 : if (mTimer) {
379 : // Fire 100ms timer to try to tear down this plugin as quickly as
380 : // possible once the nesting level comes back down.
381 0 : nsresult rv = mTimer->InitWithCallback(this, 100, nsITimer::TYPE_ONE_SHOT);
382 0 : if (NS_SUCCEEDED(rv)) {
383 0 : return rv;
384 : }
385 : }
386 : NS_ERROR("Failed to setup a timer to stop the plugin later (at a safe "
387 0 : "time). Stopping the plugin now, this might crash.");
388 : }
389 : }
390 :
391 0 : mTimer = nsnull;
392 :
393 0 : nsObjectLoadingContent::DoStopPlugin(mInstanceOwner, false);
394 :
395 0 : return NS_OK;
396 : }
397 :
398 : class AutoNotifier {
399 : public:
400 0 : AutoNotifier(nsObjectLoadingContent* aContent, bool aNotify) :
401 0 : mContent(aContent), mNotify(aNotify) {
402 0 : mOldType = aContent->Type();
403 0 : mOldState = aContent->ObjectState();
404 0 : }
405 0 : ~AutoNotifier() {
406 0 : mContent->NotifyStateChanged(mOldType, mOldState, false, mNotify);
407 0 : }
408 :
409 : /**
410 : * Send notifications now, ignoring the value of mNotify. The new type and
411 : * state is saved, and the destructor will notify again if mNotify is true
412 : * and the values changed.
413 : */
414 0 : void Notify() {
415 0 : NS_ASSERTION(mNotify, "Should not notify when notify=false");
416 :
417 0 : mContent->NotifyStateChanged(mOldType, mOldState, true, true);
418 0 : mOldType = mContent->Type();
419 0 : mOldState = mContent->ObjectState();
420 0 : }
421 :
422 : private:
423 : nsObjectLoadingContent* mContent;
424 : bool mNotify;
425 : nsObjectLoadingContent::ObjectType mOldType;
426 : nsEventStates mOldState;
427 : };
428 :
429 : /**
430 : * A class that will automatically fall back if a |rv| variable has a failure
431 : * code when this class is destroyed. It does not notify.
432 : */
433 : class AutoFallback {
434 : public:
435 0 : AutoFallback(nsObjectLoadingContent* aContent, const nsresult* rv)
436 0 : : mContent(aContent), mResult(rv), mPluginState(ePluginOtherState) {}
437 0 : ~AutoFallback() {
438 0 : if (NS_FAILED(*mResult)) {
439 0 : LOG(("OBJLC [%p]: rv=%08x, falling back\n", mContent, *mResult));
440 0 : mContent->Fallback(false);
441 0 : if (mPluginState != ePluginOtherState) {
442 0 : mContent->mFallbackReason = mPluginState;
443 : }
444 : }
445 0 : }
446 :
447 : /**
448 : * This should be set to something other than ePluginOtherState to indicate
449 : * a specific failure that should be passed on.
450 : */
451 0 : void SetPluginState(PluginSupportState aState) {
452 0 : NS_ASSERTION(aState != ePluginOtherState, "Should not be setting ePluginOtherState");
453 0 : mPluginState = aState;
454 0 : }
455 : private:
456 : nsObjectLoadingContent* mContent;
457 : const nsresult* mResult;
458 : PluginSupportState mPluginState;
459 : };
460 :
461 : /**
462 : * A class that automatically sets mInstantiating to false when it goes
463 : * out of scope.
464 : */
465 : class AutoSetInstantiatingToFalse {
466 : public:
467 0 : AutoSetInstantiatingToFalse(nsObjectLoadingContent* objlc) : mContent(objlc) {}
468 0 : ~AutoSetInstantiatingToFalse() { mContent->mInstantiating = false; }
469 : private:
470 : nsObjectLoadingContent* mContent;
471 : };
472 :
473 : // helper functions
474 : static bool
475 0 : IsSupportedImage(const nsCString& aMimeType)
476 : {
477 0 : imgILoader* loader = nsContentUtils::GetImgLoader();
478 0 : if (!loader) {
479 0 : return false;
480 : }
481 :
482 : bool supported;
483 0 : nsresult rv = loader->SupportImageWithMimeType(aMimeType.get(), &supported);
484 0 : return NS_SUCCEEDED(rv) && supported;
485 : }
486 :
487 0 : nsresult nsObjectLoadingContent::IsPluginEnabledForType(const nsCString& aMIMEType)
488 : {
489 0 : if (!mShouldPlay) {
490 0 : return NS_ERROR_PLUGIN_CLICKTOPLAY;
491 : }
492 :
493 0 : nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
494 0 : nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
495 0 : if (!pluginHost) {
496 0 : return false;
497 : }
498 0 : return pluginHost->IsPluginEnabledForType(aMIMEType.get());
499 : }
500 :
501 : static void
502 0 : GetExtensionFromURI(nsIURI* uri, nsCString& ext)
503 : {
504 0 : nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
505 0 : if (url) {
506 0 : url->GetFileExtension(ext);
507 : } else {
508 0 : nsCString spec;
509 0 : uri->GetSpec(spec);
510 :
511 0 : PRInt32 offset = spec.RFindChar('.');
512 0 : if (offset != kNotFound) {
513 0 : ext = Substring(spec, offset + 1, spec.Length());
514 : }
515 : }
516 0 : }
517 :
518 : /**
519 : * Checks whether a plugin exists and is enabled for the extension
520 : * in the given URI. The MIME type is returned in the mimeType out parameter.
521 : */
522 0 : bool nsObjectLoadingContent::IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType)
523 : {
524 0 : if (!mShouldPlay) {
525 0 : return false;
526 : }
527 :
528 0 : nsCAutoString ext;
529 0 : GetExtensionFromURI(uri, ext);
530 :
531 0 : if (ext.IsEmpty()) {
532 0 : return false;
533 : }
534 :
535 0 : nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
536 0 : nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
537 0 : if (!pluginHost) {
538 0 : return false;
539 : }
540 :
541 : const char* typeFromExt;
542 0 : if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForExtension(ext.get(), typeFromExt))) {
543 0 : mimeType = typeFromExt;
544 0 : return true;
545 : }
546 0 : return false;
547 : }
548 :
549 0 : nsObjectLoadingContent::nsObjectLoadingContent()
550 : : mPendingInstantiateEvent(nsnull)
551 : , mChannel(nsnull)
552 : , mType(eType_Loading)
553 : , mInstantiating(false)
554 : , mUserDisabled(false)
555 : , mSuppressed(false)
556 : , mNetworkCreated(true)
557 : // If plugins.click_to_play is false, plugins should always play
558 0 : , mShouldPlay(!mozilla::Preferences::GetBool("plugins.click_to_play", false))
559 : , mSrcStreamLoading(false)
560 0 : , mFallbackReason(ePluginOtherState)
561 : {
562 0 : }
563 :
564 0 : nsObjectLoadingContent::~nsObjectLoadingContent()
565 : {
566 0 : DestroyImageLoadingContent();
567 0 : if (mFrameLoader) {
568 0 : mFrameLoader->Destroy();
569 : }
570 0 : }
571 :
572 : nsresult
573 0 : nsObjectLoadingContent::InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI)
574 : {
575 0 : if (!mShouldPlay) {
576 0 : return NS_ERROR_PLUGIN_CLICKTOPLAY;
577 : }
578 :
579 : // Don't do anything if we already have an active instance.
580 0 : if (mInstanceOwner) {
581 0 : return NS_OK;
582 : }
583 :
584 : // Don't allow re-entry into initialization code.
585 0 : if (mInstantiating) {
586 0 : return NS_OK;
587 : }
588 0 : mInstantiating = true;
589 0 : AutoSetInstantiatingToFalse autoInstantiating(this);
590 :
591 : // Instantiating an instance can result in script execution, which
592 : // can destroy this DOM object. Don't allow that for the scope
593 : // of this method.
594 0 : nsCOMPtr<nsIObjectLoadingContent> kungFuDeathGrip = this;
595 0 : nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
596 :
597 0 : nsCOMPtr<nsIURI> baseURI;
598 0 : if (!aURI) {
599 : // We need some URI. If we have nothing else, use the base URI.
600 : // XXX(biesi): The code used to do this. Not sure why this is correct...
601 0 : GetObjectBaseURI(thisContent, getter_AddRefs(baseURI));
602 0 : aURI = baseURI;
603 : }
604 :
605 : // Flush layout so that the plugin is initialized with the latest information.
606 0 : nsIDocument* doc = thisContent->GetCurrentDoc();
607 0 : if (!doc) {
608 0 : return NS_ERROR_FAILURE;
609 : }
610 0 : doc->FlushPendingNotifications(Flush_Layout);
611 :
612 0 : nsresult rv = NS_ERROR_FAILURE;
613 0 : nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv));
614 0 : nsPluginHost* pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
615 0 : if (NS_FAILED(rv)) {
616 0 : return rv;
617 : }
618 :
619 : // If you add early return(s), be sure to balance this call to
620 : // appShell->SuspendNative() with additional call(s) to
621 : // appShell->ReturnNative().
622 0 : nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
623 0 : if (appShell) {
624 0 : appShell->SuspendNative();
625 : }
626 :
627 0 : nsCOMPtr<nsIPluginDocument> pDoc(do_QueryInterface(doc));
628 0 : bool fullPageMode = false;
629 0 : if (pDoc) {
630 0 : pDoc->GetWillHandleInstantiation(&fullPageMode);
631 : }
632 :
633 0 : if (fullPageMode) {
634 0 : nsCOMPtr<nsIStreamListener> stream;
635 0 : rv = pluginHost->InstantiateFullPagePlugin(aMimeType, aURI, this, getter_AddRefs(mInstanceOwner), getter_AddRefs(stream));
636 0 : if (NS_SUCCEEDED(rv)) {
637 0 : pDoc->SetStreamListener(stream);
638 : }
639 : } else {
640 0 : rv = pluginHost->InstantiateEmbeddedPlugin(aMimeType, aURI, this, getter_AddRefs(mInstanceOwner));
641 : }
642 :
643 0 : if (appShell) {
644 0 : appShell->ResumeNative();
645 : }
646 :
647 0 : if (NS_FAILED(rv)) {
648 0 : return rv;
649 : }
650 :
651 : // Set up scripting interfaces.
652 0 : NotifyContentObjectWrapper();
653 :
654 0 : nsRefPtr<nsNPAPIPluginInstance> pluginInstance;
655 0 : GetPluginInstance(getter_AddRefs(pluginInstance));
656 0 : if (pluginInstance) {
657 0 : nsCOMPtr<nsIPluginTag> pluginTag;
658 0 : pluginHost->GetPluginTagForInstance(pluginInstance, getter_AddRefs(pluginTag));
659 :
660 : nsCOMPtr<nsIBlocklistService> blocklist =
661 0 : do_GetService("@mozilla.org/extensions/blocklist;1");
662 0 : if (blocklist) {
663 0 : PRUint32 blockState = nsIBlocklistService::STATE_NOT_BLOCKED;
664 0 : blocklist->GetPluginBlocklistState(pluginTag, EmptyString(),
665 0 : EmptyString(), &blockState);
666 0 : if (blockState == nsIBlocklistService::STATE_OUTDATED)
667 0 : FirePluginError(thisContent, ePluginOutdated);
668 : }
669 : }
670 :
671 0 : return NS_OK;
672 : }
673 :
674 : void
675 0 : nsObjectLoadingContent::NotifyOwnerDocumentActivityChanged()
676 : {
677 0 : if (!mInstanceOwner) {
678 0 : return;
679 : }
680 :
681 0 : nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
682 0 : nsIDocument* ownerDoc = thisContent->OwnerDoc();
683 0 : if (!ownerDoc->IsActive()) {
684 0 : StopPluginInstance();
685 : }
686 : }
687 :
688 : // nsIRequestObserver
689 : NS_IMETHODIMP
690 0 : nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest,
691 : nsISupports *aContext)
692 : {
693 0 : SAMPLE_LABEL("nsObjectLoadingContent", "OnStartRequest");
694 :
695 0 : if (aRequest != mChannel || !aRequest) {
696 : // This is a bit of an edge case - happens when a new load starts before the
697 : // previous one got here
698 0 : return NS_BINDING_ABORTED;
699 : }
700 :
701 0 : AutoNotifier notifier(this, true);
702 :
703 0 : if (!IsSuccessfulRequest(aRequest)) {
704 0 : LOG(("OBJLC [%p]: OnStartRequest: Request failed\n", this));
705 0 : Fallback(false);
706 0 : return NS_BINDING_ABORTED;
707 : }
708 :
709 0 : nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
710 0 : NS_ASSERTION(chan, "Why is our request not a channel?");
711 :
712 0 : nsresult rv = NS_ERROR_UNEXPECTED;
713 : // This fallback variable MUST be declared after the notifier variable. Do NOT
714 : // change the order of the declarations!
715 0 : AutoFallback fallback(this, &rv);
716 :
717 0 : nsCString channelType;
718 0 : rv = chan->GetContentType(channelType);
719 0 : NS_ENSURE_SUCCESS(rv, rv);
720 :
721 0 : if (channelType.EqualsASCII(APPLICATION_GUESS_FROM_EXT)) {
722 0 : channelType = APPLICATION_OCTET_STREAM;
723 0 : chan->SetContentType(channelType);
724 : }
725 :
726 : // We want to use the channel type unless one of the following is true:
727 : //
728 : // 1) The channel type is application/octet-stream and we have a
729 : // type hint and the type hint is not a document type.
730 : // 2) Our type hint is a type that we support with a plugin.
731 0 : if ((channelType.EqualsASCII(APPLICATION_OCTET_STREAM) &&
732 0 : !mContentType.IsEmpty() &&
733 0 : GetTypeOfContent(mContentType) != eType_Document) ||
734 : // Need to check IsPluginEnabledForType() in addition to GetTypeOfContent()
735 : // because otherwise the default plug-in's catch-all behavior would
736 : // confuse things.
737 0 : (NS_SUCCEEDED(IsPluginEnabledForType(mContentType)) &&
738 0 : GetTypeOfContent(mContentType) == eType_Plugin)) {
739 : // Set the type we'll use for dispatch on the channel. Otherwise we could
740 : // end up trying to dispatch to a nsFrameLoader, which will complain that
741 : // it couldn't find a way to handle application/octet-stream
742 0 : nsCAutoString typeHint, dummy;
743 0 : NS_ParseContentType(mContentType, typeHint, dummy);
744 0 : if (!typeHint.IsEmpty()) {
745 0 : chan->SetContentType(typeHint);
746 : }
747 : } else {
748 0 : mContentType = channelType;
749 : }
750 :
751 0 : nsCOMPtr<nsIURI> uri;
752 0 : chan->GetURI(getter_AddRefs(uri));
753 :
754 0 : if (mContentType.EqualsASCII(APPLICATION_OCTET_STREAM)) {
755 0 : nsCAutoString extType;
756 0 : if (IsPluginEnabledByExtension(uri, extType)) {
757 0 : mContentType = extType;
758 0 : chan->SetContentType(extType);
759 : }
760 : }
761 :
762 : // Now find out what type the content is
763 : // UnloadContent will set our type to null; need to be sure to only set it to
764 : // the real value on success
765 0 : ObjectType newType = GetTypeOfContent(mContentType);
766 0 : LOG(("OBJLC [%p]: OnStartRequest: Content Type=<%s> Old type=%u New Type=%u\n",
767 : this, mContentType.get(), mType, newType));
768 :
769 : // Now do a content policy check
770 : // XXXbz this duplicates some code in nsContentBlocker::ShouldLoad
771 : PRInt32 contentPolicyType;
772 0 : switch (newType) {
773 : case eType_Image:
774 0 : contentPolicyType = nsIContentPolicy::TYPE_IMAGE;
775 0 : break;
776 : case eType_Document:
777 0 : contentPolicyType = nsIContentPolicy::TYPE_SUBDOCUMENT;
778 0 : break;
779 : default:
780 0 : contentPolicyType = nsIContentPolicy::TYPE_OBJECT;
781 0 : break;
782 : }
783 : nsCOMPtr<nsIContent> thisContent =
784 0 : do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
785 0 : NS_ASSERTION(thisContent, "must be a content");
786 :
787 0 : nsIDocument* doc = thisContent->OwnerDoc();
788 :
789 0 : PRInt16 shouldProcess = nsIContentPolicy::ACCEPT;
790 : rv =
791 : NS_CheckContentProcessPolicy(contentPolicyType,
792 : uri,
793 : doc->NodePrincipal(),
794 : static_cast<nsIImageLoadingContent*>(this),
795 : mContentType,
796 : nsnull, //extra
797 : &shouldProcess,
798 : nsContentUtils::GetContentPolicy(),
799 0 : nsContentUtils::GetSecurityManager());
800 0 : if (NS_FAILED(rv) || NS_CP_REJECTED(shouldProcess)) {
801 0 : HandleBeingBlockedByContentPolicy(rv, shouldProcess);
802 0 : rv = NS_OK; // otherwise, the AutoFallback will make us fall back
803 0 : return NS_BINDING_ABORTED;
804 : }
805 :
806 0 : if (mType != newType) {
807 0 : UnloadContent();
808 : }
809 :
810 0 : switch (newType) {
811 : case eType_Image:
812 0 : rv = LoadImageWithChannel(chan, getter_AddRefs(mFinalListener));
813 0 : NS_ENSURE_SUCCESS(rv, rv);
814 :
815 : // If we have a success result but no final listener, then the image is
816 : // cached. In that case, we can just return: No need to try to call the
817 : // final listener.
818 0 : if (!mFinalListener) {
819 0 : mType = newType;
820 0 : return NS_BINDING_ABORTED;
821 : }
822 0 : break;
823 : case eType_Document: {
824 0 : if (!mFrameLoader) {
825 0 : mFrameLoader = nsFrameLoader::Create(thisContent->AsElement(),
826 0 : mNetworkCreated);
827 0 : if (!mFrameLoader) {
828 0 : Fallback(false);
829 0 : return NS_ERROR_UNEXPECTED;
830 : }
831 : }
832 :
833 0 : rv = mFrameLoader->CheckForRecursiveLoad(uri);
834 0 : if (NS_FAILED(rv)) {
835 0 : Fallback(false);
836 0 : return rv;
837 : }
838 :
839 0 : if (mType != newType) {
840 : // XXX We must call this before getting the docshell to work around
841 : // bug 300540; when that's fixed, this if statement can be removed.
842 0 : mType = newType;
843 0 : notifier.Notify();
844 :
845 0 : if (!mFrameLoader) {
846 : // mFrameLoader got nulled out when we notified, which most
847 : // likely means the node was removed from the
848 : // document. Abort the load that just started.
849 0 : return NS_BINDING_ABORTED;
850 : }
851 : }
852 :
853 : // We're loading a document, so we have to set LOAD_DOCUMENT_URI
854 : // (especially important for firing onload)
855 0 : nsLoadFlags flags = 0;
856 0 : chan->GetLoadFlags(&flags);
857 0 : flags |= nsIChannel::LOAD_DOCUMENT_URI;
858 0 : chan->SetLoadFlags(flags);
859 :
860 0 : nsCOMPtr<nsIDocShell> docShell;
861 0 : rv = mFrameLoader->GetDocShell(getter_AddRefs(docShell));
862 0 : NS_ENSURE_SUCCESS(rv, rv);
863 :
864 0 : nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(docShell));
865 0 : NS_ASSERTION(req, "Docshell must be an ifreq");
866 :
867 : nsCOMPtr<nsIURILoader>
868 0 : uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID, &rv));
869 0 : NS_ENSURE_SUCCESS(rv, rv);
870 0 : rv = uriLoader->OpenChannel(chan, nsIURILoader::DONT_RETARGET, req,
871 0 : getter_AddRefs(mFinalListener));
872 0 : break;
873 : }
874 : case eType_Plugin: {
875 0 : if (mType != newType) {
876 0 : mType = newType;
877 0 : notifier.Notify();
878 : }
879 0 : nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
880 0 : nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
881 0 : if (!pluginHost) {
882 0 : return NS_ERROR_NOT_AVAILABLE;
883 : }
884 0 : pluginHost->CreateListenerForChannel(chan, this, getter_AddRefs(mFinalListener));
885 0 : break;
886 : }
887 : case eType_Loading:
888 0 : NS_NOTREACHED("Should not have a loading type here!");
889 : case eType_Null:
890 : // Need to fallback here (instead of using the case below), so that we can
891 : // set mFallbackReason without it being overwritten. This is also why we
892 : // return early.
893 0 : Fallback(false);
894 :
895 : PluginSupportState pluginState = GetPluginSupportState(thisContent,
896 0 : mContentType);
897 : // Do nothing, but fire the plugin not found event if needed
898 0 : if (pluginState != ePluginOtherState) {
899 0 : mFallbackReason = pluginState;
900 0 : FirePluginError(thisContent, pluginState);
901 : }
902 0 : return NS_BINDING_ABORTED;
903 : }
904 :
905 0 : if (mFinalListener) {
906 0 : mType = newType;
907 :
908 0 : mSrcStreamLoading = true;
909 0 : rv = mFinalListener->OnStartRequest(aRequest, aContext);
910 0 : mSrcStreamLoading = false;
911 :
912 0 : if (NS_SUCCEEDED(rv)) {
913 : // Plugins need to set up for NPRuntime.
914 0 : if (mType == eType_Plugin) {
915 0 : NotifyContentObjectWrapper();
916 : }
917 : } else {
918 : // Plugins don't fall back if there is an error here.
919 0 : if (mType == eType_Plugin) {
920 0 : rv = NS_OK; // this is necessary to avoid auto-fallback
921 0 : return NS_BINDING_ABORTED;
922 : }
923 0 : Fallback(false);
924 : }
925 :
926 0 : return rv;
927 : }
928 :
929 0 : Fallback(false);
930 0 : return NS_BINDING_ABORTED;
931 : }
932 :
933 : NS_IMETHODIMP
934 0 : nsObjectLoadingContent::OnStopRequest(nsIRequest *aRequest,
935 : nsISupports *aContext,
936 : nsresult aStatusCode)
937 : {
938 0 : NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
939 :
940 0 : if (aRequest != mChannel) {
941 0 : return NS_BINDING_ABORTED;
942 : }
943 :
944 0 : mChannel = nsnull;
945 :
946 0 : if (mFinalListener) {
947 0 : mFinalListener->OnStopRequest(aRequest, aContext, aStatusCode);
948 0 : mFinalListener = nsnull;
949 : }
950 :
951 : // Return value doesn't matter
952 0 : return NS_OK;
953 : }
954 :
955 :
956 : // nsIStreamListener
957 : NS_IMETHODIMP
958 0 : nsObjectLoadingContent::OnDataAvailable(nsIRequest *aRequest,
959 : nsISupports *aContext,
960 : nsIInputStream *aInputStream,
961 : PRUint32 aOffset, PRUint32 aCount)
962 : {
963 0 : NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
964 :
965 0 : if (aRequest != mChannel) {
966 0 : return NS_BINDING_ABORTED;
967 : }
968 :
969 0 : if (mFinalListener) {
970 0 : return mFinalListener->OnDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount);
971 : }
972 :
973 : // Abort this load if we have no listener here
974 0 : return NS_ERROR_UNEXPECTED;
975 : }
976 :
977 : // nsIFrameLoaderOwner
978 : NS_IMETHODIMP
979 0 : nsObjectLoadingContent::GetFrameLoader(nsIFrameLoader** aFrameLoader)
980 : {
981 0 : *aFrameLoader = mFrameLoader;
982 0 : NS_IF_ADDREF(*aFrameLoader);
983 0 : return NS_OK;
984 : }
985 :
986 : NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
987 0 : nsObjectLoadingContent::GetFrameLoader()
988 : {
989 0 : nsFrameLoader* loader = mFrameLoader;
990 0 : NS_IF_ADDREF(loader);
991 0 : return loader;
992 : }
993 :
994 : NS_IMETHODIMP
995 0 : nsObjectLoadingContent::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherLoader)
996 : {
997 0 : return NS_ERROR_NOT_IMPLEMENTED;
998 : }
999 :
1000 : // nsIObjectLoadingContent
1001 : NS_IMETHODIMP
1002 0 : nsObjectLoadingContent::GetActualType(nsACString& aType)
1003 : {
1004 0 : aType = mContentType;
1005 0 : return NS_OK;
1006 : }
1007 :
1008 : NS_IMETHODIMP
1009 0 : nsObjectLoadingContent::GetDisplayedType(PRUint32* aType)
1010 : {
1011 0 : *aType = mType;
1012 0 : return NS_OK;
1013 : }
1014 :
1015 : NS_IMETHODIMP
1016 0 : nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
1017 : {
1018 : // Not having an instance yet is OK, but try to start one now that
1019 : // we have a frame.
1020 0 : if (!mInstanceOwner) {
1021 0 : AsyncStartPluginInstance();
1022 0 : return NS_OK;
1023 : }
1024 :
1025 : // Disconnect any existing frame
1026 0 : DisconnectFrame();
1027 :
1028 : // Set up relationship between instance owner and frame.
1029 0 : nsObjectFrame *objFrame = static_cast<nsObjectFrame*>(aFrame);
1030 0 : mInstanceOwner->SetFrame(objFrame);
1031 :
1032 : // Set up new frame to draw.
1033 0 : objFrame->FixupWindow(objFrame->GetContentRectRelativeToSelf().Size());
1034 0 : objFrame->Invalidate(objFrame->GetContentRectRelativeToSelf());
1035 :
1036 0 : return NS_OK;
1037 : }
1038 :
1039 : NS_IMETHODIMP
1040 0 : nsObjectLoadingContent::DisconnectFrame()
1041 : {
1042 0 : if (mInstanceOwner) {
1043 0 : mInstanceOwner->SetFrame(nsnull);
1044 : }
1045 0 : return NS_OK;
1046 : }
1047 :
1048 : NS_IMETHODIMP
1049 0 : nsObjectLoadingContent::GetPluginInstance(nsNPAPIPluginInstance** aInstance)
1050 : {
1051 0 : *aInstance = nsnull;
1052 :
1053 0 : if (!mInstanceOwner) {
1054 0 : return NS_OK;
1055 : }
1056 :
1057 0 : return mInstanceOwner->GetInstance(aInstance);
1058 : }
1059 :
1060 : NS_IMETHODIMP
1061 0 : nsObjectLoadingContent::GetContentTypeForMIMEType(const nsACString& aMIMEType,
1062 : PRUint32* aType)
1063 : {
1064 0 : *aType = GetTypeOfContent(PromiseFlatCString(aMIMEType));
1065 0 : return NS_OK;
1066 : }
1067 :
1068 : // nsIInterfaceRequestor
1069 : NS_IMETHODIMP
1070 0 : nsObjectLoadingContent::GetInterface(const nsIID & aIID, void **aResult)
1071 : {
1072 0 : if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
1073 0 : nsIChannelEventSink* sink = this;
1074 0 : *aResult = sink;
1075 0 : NS_ADDREF(sink);
1076 0 : return NS_OK;
1077 : }
1078 0 : return NS_NOINTERFACE;
1079 : }
1080 :
1081 : // nsIChannelEventSink
1082 : NS_IMETHODIMP
1083 0 : nsObjectLoadingContent::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
1084 : nsIChannel *aNewChannel,
1085 : PRUint32 aFlags,
1086 : nsIAsyncVerifyRedirectCallback *cb)
1087 : {
1088 : // If we're already busy with a new load, or have no load at all,
1089 : // cancel the redirect.
1090 0 : if (!mChannel || aOldChannel != mChannel) {
1091 0 : return NS_BINDING_ABORTED;
1092 : }
1093 :
1094 0 : mChannel = aNewChannel;
1095 0 : cb->OnRedirectVerifyCallback(NS_OK);
1096 0 : return NS_OK;
1097 : }
1098 :
1099 : // <public>
1100 : nsEventStates
1101 0 : nsObjectLoadingContent::ObjectState() const
1102 : {
1103 0 : switch (mType) {
1104 : case eType_Loading:
1105 0 : return NS_EVENT_STATE_LOADING;
1106 : case eType_Image:
1107 0 : return ImageState();
1108 : case eType_Plugin:
1109 : case eType_Document:
1110 : // These are OK. If documents start to load successfully, they display
1111 : // something, and are thus not broken in this sense. The same goes for
1112 : // plugins.
1113 0 : return nsEventStates();
1114 : case eType_Null:
1115 0 : if (mSuppressed)
1116 0 : return NS_EVENT_STATE_SUPPRESSED;
1117 0 : if (mUserDisabled)
1118 0 : return NS_EVENT_STATE_USERDISABLED;
1119 :
1120 : // Otherwise, broken
1121 0 : nsEventStates state = NS_EVENT_STATE_BROKEN;
1122 0 : switch (mFallbackReason) {
1123 : case ePluginClickToPlay:
1124 0 : return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY;
1125 : case ePluginDisabled:
1126 0 : state |= NS_EVENT_STATE_HANDLER_DISABLED;
1127 0 : break;
1128 : case ePluginBlocklisted:
1129 0 : state |= NS_EVENT_STATE_HANDLER_BLOCKED;
1130 0 : break;
1131 : case ePluginCrashed:
1132 0 : state |= NS_EVENT_STATE_HANDLER_CRASHED;
1133 0 : break;
1134 : case ePluginUnsupported:
1135 0 : state |= NS_EVENT_STATE_TYPE_UNSUPPORTED;
1136 0 : break;
1137 : case ePluginOutdated:
1138 : case ePluginOtherState:
1139 : // Do nothing, but avoid a compile warning
1140 0 : break;
1141 : }
1142 0 : return state;
1143 : };
1144 0 : NS_NOTREACHED("unknown type?");
1145 : // this return statement only exists to avoid a compile warning
1146 0 : return nsEventStates();
1147 : }
1148 :
1149 : // <protected>
1150 : nsresult
1151 0 : nsObjectLoadingContent::LoadObject(const nsAString& aURI,
1152 : bool aNotify,
1153 : const nsCString& aTypeHint,
1154 : bool aForceLoad)
1155 : {
1156 0 : LOG(("OBJLC [%p]: Loading object: URI string=<%s> notify=%i type=<%s> forceload=%i\n",
1157 : this, NS_ConvertUTF16toUTF8(aURI).get(), aNotify, aTypeHint.get(), aForceLoad));
1158 :
1159 : // Avoid StringToURI in order to use the codebase attribute as base URI
1160 : nsCOMPtr<nsIContent> thisContent =
1161 0 : do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1162 0 : NS_ASSERTION(thisContent, "must be a content");
1163 :
1164 0 : nsIDocument* doc = thisContent->OwnerDoc();
1165 0 : nsCOMPtr<nsIURI> baseURI;
1166 0 : GetObjectBaseURI(thisContent, getter_AddRefs(baseURI));
1167 :
1168 0 : nsCOMPtr<nsIURI> uri;
1169 0 : nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
1170 : aURI, doc,
1171 0 : baseURI);
1172 : // If URI creation failed, fallback immediately - this only happens for
1173 : // malformed URIs
1174 0 : if (!uri) {
1175 0 : Fallback(aNotify);
1176 0 : return NS_OK;
1177 : }
1178 :
1179 0 : NS_TryToSetImmutable(uri);
1180 :
1181 0 : return LoadObject(uri, aNotify, aTypeHint, aForceLoad);
1182 : }
1183 :
1184 : void
1185 0 : nsObjectLoadingContent::UpdateFallbackState(nsIContent* aContent,
1186 : AutoFallback& fallback,
1187 : const nsCString& aTypeHint)
1188 : {
1189 : // Notify the UI and update the fallback state
1190 0 : PluginSupportState state = GetPluginSupportState(aContent, aTypeHint);
1191 0 : if (state != ePluginOtherState) {
1192 0 : fallback.SetPluginState(state);
1193 0 : FirePluginError(aContent, state);
1194 : }
1195 0 : }
1196 :
1197 : nsresult
1198 0 : nsObjectLoadingContent::LoadObject(nsIURI* aURI,
1199 : bool aNotify,
1200 : const nsCString& aTypeHint,
1201 : bool aForceLoad)
1202 : {
1203 : // Only do a URI equality check for things that aren't stopped plugins.
1204 : // This is because we still need to load again if the plugin has been stopped.
1205 0 : if (mType == eType_Document || mType == eType_Image || mInstanceOwner) {
1206 0 : if (mURI && aURI) {
1207 : bool equal;
1208 0 : nsresult rv = mURI->Equals(aURI, &equal);
1209 0 : if (NS_SUCCEEDED(rv) && equal && !aForceLoad) {
1210 : // URI didn't change, do nothing
1211 0 : return NS_OK;
1212 : }
1213 0 : StopPluginInstance();
1214 : }
1215 : }
1216 :
1217 : // Need to revoke any potentially pending instantiate events
1218 0 : if (mType == eType_Plugin && mPendingInstantiateEvent) {
1219 0 : mPendingInstantiateEvent = nsnull;
1220 : }
1221 :
1222 0 : AutoNotifier notifier(this, aNotify);
1223 :
1224 0 : mUserDisabled = mSuppressed = false;
1225 :
1226 0 : mURI = aURI;
1227 0 : mContentType = aTypeHint;
1228 :
1229 : nsCOMPtr<nsIContent> thisContent =
1230 0 : do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1231 0 : NS_ASSERTION(thisContent, "must be a content");
1232 :
1233 0 : nsIDocument* doc = thisContent->OwnerDoc();
1234 0 : if (doc->IsBeingUsedAsImage()) {
1235 0 : return NS_OK;
1236 : }
1237 :
1238 : // From here on, we will always change the content. This means that a
1239 : // possibly-loading channel should be aborted.
1240 0 : if (mChannel) {
1241 0 : LOG(("OBJLC [%p]: Cancelling existing load\n", this));
1242 :
1243 : // These three statements are carefully ordered:
1244 : // - onStopRequest should get a channel whose status is the same as the
1245 : // status argument
1246 : // - onStopRequest must get a non-null channel
1247 0 : mChannel->Cancel(NS_BINDING_ABORTED);
1248 0 : if (mFinalListener) {
1249 : // NOTE: Since mFinalListener is only set in onStartRequest, which takes
1250 : // care of calling mFinalListener->OnStartRequest, mFinalListener is only
1251 : // non-null here if onStartRequest was already called.
1252 0 : mFinalListener->OnStopRequest(mChannel, nsnull, NS_BINDING_ABORTED);
1253 0 : mFinalListener = nsnull;
1254 : }
1255 0 : mChannel = nsnull;
1256 : }
1257 :
1258 : // Security checks
1259 0 : if (doc->IsLoadedAsData()) {
1260 0 : if (!doc->IsStaticDocument()) {
1261 0 : Fallback(false);
1262 : }
1263 0 : return NS_OK;
1264 : }
1265 :
1266 : // Can't do security checks without a URI - hopefully the plugin will take
1267 : // care of that
1268 : // Null URIs happen when the URL to load is specified via other means than the
1269 : // data/src attribute, for example via custom <param> elements.
1270 0 : if (aURI) {
1271 0 : nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
1272 0 : NS_ASSERTION(secMan, "No security manager!?");
1273 : nsresult rv =
1274 0 : secMan->CheckLoadURIWithPrincipal(thisContent->NodePrincipal(), aURI, 0);
1275 0 : if (NS_FAILED(rv)) {
1276 0 : Fallback(false);
1277 0 : return NS_OK;
1278 : }
1279 :
1280 0 : PRInt16 shouldLoad = nsIContentPolicy::ACCEPT; // default permit
1281 : rv =
1282 : NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT,
1283 : aURI,
1284 : doc->NodePrincipal(),
1285 : static_cast<nsIImageLoadingContent*>(this),
1286 : aTypeHint,
1287 : nsnull, //extra
1288 : &shouldLoad,
1289 : nsContentUtils::GetContentPolicy(),
1290 0 : secMan);
1291 0 : if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
1292 0 : HandleBeingBlockedByContentPolicy(rv, shouldLoad);
1293 0 : return NS_OK;
1294 : }
1295 : }
1296 :
1297 0 : nsresult rv = NS_ERROR_UNEXPECTED;
1298 : // This fallback variable MUST be declared after the notifier variable. Do NOT
1299 : // change the order of the declarations!
1300 0 : AutoFallback fallback(this, &rv);
1301 :
1302 0 : PRUint32 caps = GetCapabilities();
1303 0 : LOG(("OBJLC [%p]: Capabilities: %04x\n", this, caps));
1304 :
1305 0 : nsCAutoString overrideType;
1306 0 : if ((caps & eOverrideServerType) &&
1307 0 : ((!aTypeHint.IsEmpty() && NS_SUCCEEDED(IsPluginEnabledForType(aTypeHint))) ||
1308 0 : (aURI && IsPluginEnabledByExtension(aURI, overrideType)))) {
1309 : ObjectType newType;
1310 0 : if (overrideType.IsEmpty()) {
1311 0 : newType = GetTypeOfContent(aTypeHint);
1312 : } else {
1313 0 : mContentType = overrideType;
1314 0 : newType = eType_Plugin;
1315 : }
1316 :
1317 0 : if (newType != mType) {
1318 0 : LOG(("OBJLC [%p]: (eOverrideServerType) Changing type from %u to %u\n", this, mType, newType));
1319 :
1320 0 : UnloadContent();
1321 :
1322 : // Must have a frameloader before creating a frame, or the frame will
1323 : // create its own.
1324 0 : if (!mFrameLoader && newType == eType_Document) {
1325 0 : mFrameLoader = nsFrameLoader::Create(thisContent->AsElement(),
1326 0 : mNetworkCreated);
1327 0 : if (!mFrameLoader) {
1328 0 : mURI = nsnull;
1329 0 : return NS_OK;
1330 : }
1331 : }
1332 :
1333 : // Must notify here for plugins
1334 : // If aNotify is false, we'll just wait until we get a frame and use the
1335 : // async instantiate path.
1336 : // XXX is this still needed? (for documents?)
1337 0 : mType = newType;
1338 0 : if (aNotify)
1339 0 : notifier.Notify();
1340 : }
1341 0 : switch (newType) {
1342 : case eType_Image:
1343 : // Don't notify, because we will take care of that ourselves.
1344 0 : if (aURI) {
1345 0 : rv = LoadImage(aURI, aForceLoad, false);
1346 : } else {
1347 0 : rv = NS_ERROR_NOT_AVAILABLE;
1348 : }
1349 0 : break;
1350 : case eType_Plugin:
1351 0 : rv = AsyncStartPluginInstance();
1352 0 : break;
1353 : case eType_Document:
1354 0 : if (aURI) {
1355 0 : rv = mFrameLoader->LoadURI(aURI);
1356 : } else {
1357 0 : rv = NS_ERROR_NOT_AVAILABLE;
1358 : }
1359 0 : break;
1360 : case eType_Loading:
1361 0 : NS_NOTREACHED("Should not have a loading type here!");
1362 : case eType_Null:
1363 : // No need to load anything, notify of the failure.
1364 0 : UpdateFallbackState(thisContent, fallback, aTypeHint);
1365 0 : break;
1366 : };
1367 0 : return NS_OK;
1368 : }
1369 :
1370 : // If the class ID specifies a supported plugin, or if we have no explicit URI
1371 : // but a type, immediately instantiate the plugin.
1372 0 : bool isSupportedClassID = false;
1373 0 : nsCAutoString typeForID; // Will be set iff isSupportedClassID == true
1374 0 : bool hasID = false;
1375 0 : if (caps & eSupportClassID) {
1376 0 : nsAutoString classid;
1377 0 : thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::classid, classid);
1378 0 : if (!classid.IsEmpty()) {
1379 0 : hasID = true;
1380 0 : isSupportedClassID = NS_SUCCEEDED(TypeForClassID(classid, typeForID));
1381 : }
1382 : }
1383 :
1384 0 : if (hasID && !isSupportedClassID) {
1385 : // We have a class ID and it's unsupported. Fallback in that case.
1386 0 : rv = NS_ERROR_NOT_AVAILABLE;
1387 0 : return NS_OK;
1388 : }
1389 :
1390 0 : if (isSupportedClassID ||
1391 0 : (!aURI && !aTypeHint.IsEmpty() &&
1392 0 : GetTypeOfContent(aTypeHint) == eType_Plugin)) {
1393 : // No URI, but we have a type. The plugin will handle the load.
1394 : // Or: supported class id, plugin will handle the load.
1395 0 : mType = eType_Plugin;
1396 :
1397 : // At this point, the stored content type
1398 : // must be equal to our type hint. Similar,
1399 : // our URI must be the requested URI.
1400 : // (->Equals would suffice, but == is cheaper
1401 : // and handles NULL)
1402 0 : NS_ASSERTION(mContentType.Equals(aTypeHint), "mContentType wrong!");
1403 0 : NS_ASSERTION(mURI == aURI, "mURI wrong!");
1404 :
1405 0 : if (isSupportedClassID) {
1406 : // Use the classid's type
1407 0 : NS_ASSERTION(!typeForID.IsEmpty(), "Must have a real type!");
1408 0 : mContentType = typeForID;
1409 : // XXX(biesi). The plugin instantiation code used to pass the base URI
1410 : // here instead of the plugin URI for instantiation via class ID, so I
1411 : // continue to do so. Why that is, no idea...
1412 0 : GetObjectBaseURI(thisContent, getter_AddRefs(mURI));
1413 0 : if (!mURI) {
1414 0 : mURI = aURI;
1415 : }
1416 : }
1417 :
1418 : // rv is references by a stack-based object, need to assign here
1419 0 : rv = AsyncStartPluginInstance();
1420 :
1421 0 : return rv;
1422 : }
1423 :
1424 0 : if (!aURI) {
1425 : // No URI and if we have got this far no enabled plugin supports the type
1426 0 : rv = NS_ERROR_NOT_AVAILABLE;
1427 :
1428 : // We should only notify the UI if there is at least a type to go on for
1429 : // finding a plugin to use, unless it's a supported image or document type.
1430 0 : if (!aTypeHint.IsEmpty() && GetTypeOfContent(aTypeHint) == eType_Null) {
1431 0 : UpdateFallbackState(thisContent, fallback, aTypeHint);
1432 : }
1433 :
1434 0 : return NS_OK;
1435 : }
1436 :
1437 : // E.g. mms://
1438 0 : if (!CanHandleURI(aURI)) {
1439 0 : if (aTypeHint.IsEmpty()) {
1440 0 : rv = NS_ERROR_NOT_AVAILABLE;
1441 0 : return NS_OK;
1442 : }
1443 :
1444 0 : if (NS_SUCCEEDED(IsPluginEnabledForType(aTypeHint))) {
1445 0 : mType = eType_Plugin;
1446 : } else {
1447 0 : rv = NS_ERROR_NOT_AVAILABLE;
1448 : // No plugin to load, notify of the failure.
1449 0 : UpdateFallbackState(thisContent, fallback, aTypeHint);
1450 : }
1451 :
1452 0 : return NS_OK;
1453 : }
1454 :
1455 0 : nsCOMPtr<nsILoadGroup> group = doc->GetDocumentLoadGroup();
1456 0 : nsCOMPtr<nsIChannel> chan;
1457 0 : nsCOMPtr<nsIChannelPolicy> channelPolicy;
1458 0 : nsCOMPtr<nsIContentSecurityPolicy> csp;
1459 0 : rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
1460 0 : NS_ENSURE_SUCCESS(rv, rv);
1461 0 : if (csp) {
1462 0 : channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
1463 0 : channelPolicy->SetContentSecurityPolicy(csp);
1464 0 : channelPolicy->SetLoadType(nsIContentPolicy::TYPE_OBJECT);
1465 : }
1466 0 : rv = NS_NewChannel(getter_AddRefs(chan), aURI, nsnull, group, this,
1467 : nsIChannel::LOAD_CALL_CONTENT_SNIFFERS |
1468 : nsIChannel::LOAD_CLASSIFY_URI,
1469 0 : channelPolicy);
1470 0 : NS_ENSURE_SUCCESS(rv, rv);
1471 :
1472 : // Referrer
1473 0 : nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
1474 0 : if (httpChan) {
1475 0 : httpChan->SetReferrer(doc->GetDocumentURI());
1476 : }
1477 :
1478 : // MIME Type hint
1479 0 : if (!aTypeHint.IsEmpty()) {
1480 0 : nsCAutoString typeHint, dummy;
1481 0 : NS_ParseContentType(aTypeHint, typeHint, dummy);
1482 0 : if (!typeHint.IsEmpty()) {
1483 0 : chan->SetContentType(typeHint);
1484 : }
1485 : }
1486 :
1487 : // Set up the channel's principal and such, like nsDocShell::DoURILoad does
1488 0 : nsContentUtils::SetUpChannelOwner(thisContent->NodePrincipal(),
1489 0 : chan, aURI, true);
1490 :
1491 0 : nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(chan);
1492 0 : if (scriptChannel) {
1493 : // Allow execution against our context if the principals match
1494 0 : scriptChannel->
1495 0 : SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
1496 : }
1497 :
1498 : // AsyncOpen can fail if a file does not exist.
1499 : // Show fallback content in that case.
1500 0 : rv = chan->AsyncOpen(this, nsnull);
1501 0 : if (NS_SUCCEEDED(rv)) {
1502 0 : LOG(("OBJLC [%p]: Channel opened.\n", this));
1503 :
1504 0 : mChannel = chan;
1505 0 : mType = eType_Loading;
1506 : }
1507 0 : return NS_OK;
1508 : }
1509 :
1510 : PRUint32
1511 0 : nsObjectLoadingContent::GetCapabilities() const
1512 : {
1513 : return eSupportImages |
1514 : eSupportPlugins |
1515 : eSupportDocuments |
1516 0 : eSupportSVG;
1517 : }
1518 :
1519 : void
1520 0 : nsObjectLoadingContent::Fallback(bool aNotify)
1521 : {
1522 0 : AutoNotifier notifier(this, aNotify);
1523 :
1524 0 : UnloadContent();
1525 0 : }
1526 :
1527 : void
1528 0 : nsObjectLoadingContent::RemovedFromDocument()
1529 : {
1530 0 : if (mFrameLoader) {
1531 : // XXX This is very temporary and must go away
1532 0 : mFrameLoader->Destroy();
1533 0 : mFrameLoader = nsnull;
1534 :
1535 : // Clear the current URI, so that LoadObject doesn't think that we
1536 : // have already loaded the content.
1537 0 : mURI = nsnull;
1538 : }
1539 :
1540 : // When a plugin instance node is removed from the document we'll
1541 : // let the plugin continue to run at least until we get back to
1542 : // the event loop. If we get back to the event loop and the node
1543 : // has still not been added back to the document then we stop
1544 : // the plugin.
1545 0 : nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1546 0 : nsCOMPtr<nsIRunnable> event = new InDocCheckEvent(thisContent);
1547 :
1548 0 : nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
1549 0 : if (appShell) {
1550 0 : appShell->RunInStableState(event);
1551 : }
1552 0 : }
1553 :
1554 : /* static */
1555 : void
1556 0 : nsObjectLoadingContent::Traverse(nsObjectLoadingContent *tmp,
1557 : nsCycleCollectionTraversalCallback &cb)
1558 : {
1559 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameLoader");
1560 0 : cb.NoteXPCOMChild(static_cast<nsIFrameLoader*>(tmp->mFrameLoader));
1561 0 : }
1562 :
1563 : // <private>
1564 : /* static */ bool
1565 0 : nsObjectLoadingContent::IsSuccessfulRequest(nsIRequest* aRequest)
1566 : {
1567 : nsresult status;
1568 0 : nsresult rv = aRequest->GetStatus(&status);
1569 0 : if (NS_FAILED(rv) || NS_FAILED(status)) {
1570 0 : return false;
1571 : }
1572 :
1573 : // This may still be an error page or somesuch
1574 0 : nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(aRequest));
1575 0 : if (httpChan) {
1576 : bool success;
1577 0 : rv = httpChan->GetRequestSucceeded(&success);
1578 0 : if (NS_FAILED(rv) || !success) {
1579 0 : return false;
1580 : }
1581 : }
1582 :
1583 : // Otherwise, the request is successful
1584 0 : return true;
1585 : }
1586 :
1587 : /* static */ bool
1588 0 : nsObjectLoadingContent::CanHandleURI(nsIURI* aURI)
1589 : {
1590 0 : nsCAutoString scheme;
1591 0 : if (NS_FAILED(aURI->GetScheme(scheme))) {
1592 0 : return false;
1593 : }
1594 :
1595 0 : nsIIOService* ios = nsContentUtils::GetIOService();
1596 0 : if (!ios)
1597 0 : return false;
1598 :
1599 0 : nsCOMPtr<nsIProtocolHandler> handler;
1600 0 : ios->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
1601 0 : if (!handler) {
1602 0 : return false;
1603 : }
1604 :
1605 : nsCOMPtr<nsIExternalProtocolHandler> extHandler =
1606 0 : do_QueryInterface(handler);
1607 : // We can handle this URI if its protocol handler is not the external one
1608 0 : return extHandler == nsnull;
1609 : }
1610 :
1611 : bool
1612 0 : nsObjectLoadingContent::IsSupportedDocument(const nsCString& aMimeType)
1613 : {
1614 : nsCOMPtr<nsIContent> thisContent =
1615 0 : do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1616 0 : NS_ASSERTION(thisContent, "must be a content");
1617 :
1618 : nsresult rv;
1619 : nsCOMPtr<nsIWebNavigationInfo> info(
1620 0 : do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID, &rv));
1621 : PRUint32 supported;
1622 0 : if (info) {
1623 0 : nsCOMPtr<nsIWebNavigation> webNav;
1624 0 : nsIDocument* currentDoc = thisContent->GetCurrentDoc();
1625 0 : if (currentDoc) {
1626 0 : webNav = do_GetInterface(currentDoc->GetScriptGlobalObject());
1627 : }
1628 0 : rv = info->IsTypeSupported(aMimeType, webNav, &supported);
1629 : }
1630 :
1631 0 : if (NS_SUCCEEDED(rv)) {
1632 0 : if (supported == nsIWebNavigationInfo::UNSUPPORTED) {
1633 : // Try a stream converter
1634 : // NOTE: We treat any type we can convert from as a supported type. If a
1635 : // type is not actually supported, the URI loader will detect that and
1636 : // return an error, and we'll fallback.
1637 : nsCOMPtr<nsIStreamConverterService> convServ =
1638 0 : do_GetService("@mozilla.org/streamConverters;1");
1639 0 : bool canConvert = false;
1640 0 : if (convServ) {
1641 0 : rv = convServ->CanConvert(aMimeType.get(), "*/*", &canConvert);
1642 : }
1643 :
1644 0 : return NS_SUCCEEDED(rv) && canConvert;
1645 : }
1646 :
1647 : // Don't want to support plugins as documents
1648 0 : return supported != nsIWebNavigationInfo::PLUGIN;
1649 : }
1650 :
1651 0 : return false;
1652 : }
1653 :
1654 : void
1655 0 : nsObjectLoadingContent::UnloadContent()
1656 : {
1657 : // Don't notify in CancelImageRequests. We do it ourselves.
1658 0 : CancelImageRequests(false);
1659 0 : if (mFrameLoader) {
1660 0 : mFrameLoader->Destroy();
1661 0 : mFrameLoader = nsnull;
1662 : }
1663 0 : mType = eType_Null;
1664 0 : mUserDisabled = mSuppressed = false;
1665 0 : mFallbackReason = ePluginOtherState;
1666 0 : }
1667 :
1668 : void
1669 0 : nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
1670 : nsEventStates aOldState,
1671 : bool aSync,
1672 : bool aNotify)
1673 : {
1674 0 : LOG(("OBJLC [%p]: Notifying about state change: (%u, %llx) -> (%u, %llx) (sync=%i)\n",
1675 : this, aOldType, aOldState.GetInternalValue(), mType,
1676 : ObjectState().GetInternalValue(), aSync));
1677 :
1678 : nsCOMPtr<nsIContent> thisContent =
1679 0 : do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1680 0 : NS_ASSERTION(thisContent, "must be a content");
1681 :
1682 0 : NS_ASSERTION(thisContent->IsElement(), "Not an element?");
1683 :
1684 : // Unfortunately, we do some state changes without notifying
1685 : // (e.g. in Fallback when canceling image requests), so we have to
1686 : // manually notify object state changes.
1687 0 : thisContent->AsElement()->UpdateState(false);
1688 :
1689 0 : if (!aNotify) {
1690 : // We're done here
1691 : return;
1692 : }
1693 :
1694 0 : nsIDocument* doc = thisContent->GetCurrentDoc();
1695 0 : if (!doc) {
1696 : return; // Nothing to do
1697 : }
1698 :
1699 0 : nsEventStates newState = ObjectState();
1700 :
1701 0 : if (newState != aOldState) {
1702 : // This will trigger frame construction
1703 0 : NS_ASSERTION(thisContent->IsInDoc(), "Something is confused");
1704 0 : nsEventStates changedBits = aOldState ^ newState;
1705 :
1706 : {
1707 0 : nsAutoScriptBlocker scriptBlocker;
1708 0 : doc->ContentStateChanged(thisContent, changedBits);
1709 : }
1710 0 : if (aSync) {
1711 : // Make sure that frames are actually constructed immediately.
1712 0 : doc->FlushPendingNotifications(Flush_Frames);
1713 : }
1714 0 : } else if (aOldType != mType) {
1715 : // If our state changed, then we already recreated frames
1716 : // Otherwise, need to do that here
1717 0 : nsCOMPtr<nsIPresShell> shell = doc->GetShell();
1718 0 : if (shell) {
1719 0 : shell->RecreateFramesFor(thisContent);
1720 : }
1721 : }
1722 : }
1723 :
1724 : /* static */ void
1725 0 : nsObjectLoadingContent::FirePluginError(nsIContent* thisContent,
1726 : PluginSupportState state)
1727 : {
1728 0 : LOG(("OBJLC []: Dispatching nsPluginErrorEvent for content %p\n",
1729 : thisContent));
1730 :
1731 0 : nsCOMPtr<nsIRunnable> ev = new nsPluginErrorEvent(thisContent, state);
1732 0 : nsresult rv = NS_DispatchToCurrentThread(ev);
1733 0 : if (NS_FAILED(rv)) {
1734 0 : NS_WARNING("failed to dispatch nsPluginErrorEvent");
1735 : }
1736 0 : }
1737 :
1738 : nsObjectLoadingContent::ObjectType
1739 0 : nsObjectLoadingContent::GetTypeOfContent(const nsCString& aMIMEType)
1740 : {
1741 0 : PRUint32 caps = GetCapabilities();
1742 :
1743 0 : if ((caps & eSupportImages) && IsSupportedImage(aMIMEType)) {
1744 0 : return eType_Image;
1745 : }
1746 :
1747 0 : bool isSVG = aMIMEType.LowerCaseEqualsLiteral("image/svg+xml");
1748 0 : bool supportedSVG = isSVG && (caps & eSupportSVG);
1749 0 : if (((caps & eSupportDocuments) || supportedSVG) &&
1750 0 : IsSupportedDocument(aMIMEType)) {
1751 0 : return eType_Document;
1752 : }
1753 :
1754 0 : if ((caps & eSupportPlugins) && NS_SUCCEEDED(IsPluginEnabledForType(aMIMEType))) {
1755 0 : return eType_Plugin;
1756 : }
1757 :
1758 0 : return eType_Null;
1759 : }
1760 :
1761 : nsresult
1762 0 : nsObjectLoadingContent::TypeForClassID(const nsAString& aClassID,
1763 : nsACString& aType)
1764 : {
1765 0 : if (StringBeginsWith(aClassID, NS_LITERAL_STRING("java:"))) {
1766 : // Supported if we have a java plugin
1767 0 : aType.AssignLiteral("application/x-java-vm");
1768 0 : nsresult rv = IsPluginEnabledForType(NS_LITERAL_CSTRING("application/x-java-vm"));
1769 0 : return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_NOT_AVAILABLE;
1770 : }
1771 :
1772 : // If it starts with "clsid:", this is ActiveX content
1773 0 : if (StringBeginsWith(aClassID, NS_LITERAL_STRING("clsid:"), nsCaseInsensitiveStringComparator())) {
1774 : // Check if we have a plugin for that
1775 :
1776 0 : if (NS_SUCCEEDED(IsPluginEnabledForType(NS_LITERAL_CSTRING("application/x-oleobject")))) {
1777 0 : aType.AssignLiteral("application/x-oleobject");
1778 0 : return NS_OK;
1779 : }
1780 0 : if (NS_SUCCEEDED(IsPluginEnabledForType(NS_LITERAL_CSTRING("application/oleobject")))) {
1781 0 : aType.AssignLiteral("application/oleobject");
1782 0 : return NS_OK;
1783 : }
1784 : }
1785 :
1786 0 : return NS_ERROR_NOT_AVAILABLE;
1787 : }
1788 :
1789 : void
1790 0 : nsObjectLoadingContent::GetObjectBaseURI(nsIContent* thisContent, nsIURI** aURI)
1791 : {
1792 : // We want to use swap(); since this is just called from this file,
1793 : // we can assert this (callers use comptrs)
1794 0 : NS_PRECONDITION(*aURI == nsnull, "URI must be inited to zero");
1795 :
1796 : // For plugins, the codebase attribute is the base URI
1797 0 : nsCOMPtr<nsIURI> baseURI = thisContent->GetBaseURI();
1798 0 : nsAutoString codebase;
1799 : thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::codebase,
1800 0 : codebase);
1801 0 : if (!codebase.IsEmpty()) {
1802 : nsContentUtils::NewURIWithDocumentCharset(aURI, codebase,
1803 : thisContent->OwnerDoc(),
1804 0 : baseURI);
1805 : } else {
1806 0 : baseURI.swap(*aURI);
1807 : }
1808 0 : }
1809 :
1810 : nsObjectFrame*
1811 0 : nsObjectLoadingContent::GetExistingFrame()
1812 : {
1813 0 : nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1814 0 : nsIFrame* frame = thisContent->GetPrimaryFrame();
1815 0 : nsIObjectFrame* objFrame = do_QueryFrame(frame);
1816 0 : return static_cast<nsObjectFrame*>(objFrame);
1817 : }
1818 :
1819 : void
1820 0 : nsObjectLoadingContent::HandleBeingBlockedByContentPolicy(nsresult aStatus,
1821 : PRInt16 aRetval)
1822 : {
1823 : // Must call UnloadContent first, as it overwrites
1824 : // mSuppressed/mUserDisabled. It also takes care of setting the type to
1825 : // eType_Null.
1826 0 : UnloadContent();
1827 0 : if (NS_SUCCEEDED(aStatus)) {
1828 0 : if (aRetval == nsIContentPolicy::REJECT_TYPE) {
1829 0 : mUserDisabled = true;
1830 0 : } else if (aRetval == nsIContentPolicy::REJECT_SERVER) {
1831 0 : mSuppressed = true;
1832 : }
1833 : }
1834 0 : }
1835 :
1836 : PluginSupportState
1837 0 : nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent,
1838 : const nsCString& aContentType)
1839 : {
1840 0 : if (!aContent->IsHTML()) {
1841 0 : return ePluginOtherState;
1842 : }
1843 :
1844 0 : if (aContent->Tag() == nsGkAtoms::embed ||
1845 0 : aContent->Tag() == nsGkAtoms::applet) {
1846 0 : return GetPluginDisabledState(aContentType);
1847 : }
1848 :
1849 0 : bool hasAlternateContent = false;
1850 :
1851 : // Search for a child <param> with a pluginurl name
1852 0 : for (nsIContent* child = aContent->GetFirstChild();
1853 : child;
1854 0 : child = child->GetNextSibling()) {
1855 0 : if (child->IsHTML(nsGkAtoms::param)) {
1856 0 : if (child->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
1857 0 : NS_LITERAL_STRING("pluginurl"), eIgnoreCase)) {
1858 0 : return GetPluginDisabledState(aContentType);
1859 : }
1860 0 : } else if (!hasAlternateContent) {
1861 : hasAlternateContent =
1862 0 : nsStyleUtil::IsSignificantChild(child, true, false);
1863 : }
1864 : }
1865 :
1866 : return hasAlternateContent ? ePluginOtherState :
1867 0 : GetPluginDisabledState(aContentType);
1868 : }
1869 :
1870 : PluginSupportState
1871 0 : nsObjectLoadingContent::GetPluginDisabledState(const nsCString& aContentType)
1872 : {
1873 0 : nsresult rv = IsPluginEnabledForType(aContentType);
1874 0 : if (rv == NS_ERROR_PLUGIN_DISABLED)
1875 0 : return ePluginDisabled;
1876 0 : if (rv == NS_ERROR_PLUGIN_CLICKTOPLAY)
1877 0 : return ePluginClickToPlay;
1878 0 : if (rv == NS_ERROR_PLUGIN_BLOCKLISTED)
1879 0 : return ePluginBlocklisted;
1880 0 : return ePluginUnsupported;
1881 : }
1882 :
1883 : void
1884 0 : nsObjectLoadingContent::CreateStaticClone(nsObjectLoadingContent* aDest) const
1885 : {
1886 0 : nsImageLoadingContent::CreateStaticImageClone(aDest);
1887 :
1888 0 : aDest->mType = mType;
1889 0 : nsObjectLoadingContent* thisObj = const_cast<nsObjectLoadingContent*>(this);
1890 0 : if (thisObj->mPrintFrame.IsAlive()) {
1891 0 : aDest->mPrintFrame = thisObj->mPrintFrame;
1892 : } else {
1893 0 : aDest->mPrintFrame = const_cast<nsObjectLoadingContent*>(this)->GetExistingFrame();
1894 : }
1895 :
1896 0 : if (mFrameLoader) {
1897 : nsCOMPtr<nsIContent> content =
1898 0 : do_QueryInterface(static_cast<nsIImageLoadingContent*>(aDest));
1899 0 : nsFrameLoader* fl = nsFrameLoader::Create(content->AsElement(), false);
1900 0 : if (fl) {
1901 0 : aDest->mFrameLoader = fl;
1902 0 : mFrameLoader->CreateStaticClone(fl);
1903 : }
1904 : }
1905 0 : }
1906 :
1907 : NS_IMETHODIMP
1908 0 : nsObjectLoadingContent::GetPrintFrame(nsIFrame** aFrame)
1909 : {
1910 0 : *aFrame = mPrintFrame.GetFrame();
1911 0 : return NS_OK;
1912 : }
1913 :
1914 : NS_IMETHODIMP
1915 0 : nsObjectLoadingContent::PluginCrashed(nsIPluginTag* aPluginTag,
1916 : const nsAString& pluginDumpID,
1917 : const nsAString& browserDumpID,
1918 : bool submittedCrashReport)
1919 : {
1920 0 : AutoNotifier notifier(this, true);
1921 0 : UnloadContent();
1922 0 : mFallbackReason = ePluginCrashed;
1923 0 : nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1924 :
1925 : // Note that aPluginTag in invalidated after we're called, so copy
1926 : // out any data we need now.
1927 0 : nsCAutoString pluginName;
1928 0 : aPluginTag->GetName(pluginName);
1929 0 : nsCAutoString pluginFilename;
1930 0 : aPluginTag->GetFilename(pluginFilename);
1931 :
1932 : nsCOMPtr<nsIRunnable> ev = new nsPluginCrashedEvent(thisContent,
1933 : pluginDumpID,
1934 : browserDumpID,
1935 0 : NS_ConvertUTF8toUTF16(pluginName),
1936 0 : NS_ConvertUTF8toUTF16(pluginFilename),
1937 0 : submittedCrashReport);
1938 0 : nsresult rv = NS_DispatchToCurrentThread(ev);
1939 0 : if (NS_FAILED(rv)) {
1940 0 : NS_WARNING("failed to dispatch nsPluginCrashedEvent");
1941 : }
1942 0 : return NS_OK;
1943 : }
1944 :
1945 : NS_IMETHODIMP
1946 0 : nsObjectLoadingContent::SyncStartPluginInstance()
1947 : {
1948 0 : NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
1949 : "Must be able to run script in order to instantiate a plugin instance!");
1950 :
1951 : // Don't even attempt to start an instance unless the content is in
1952 : // the document.
1953 : nsCOMPtr<nsIContent> thisContent =
1954 0 : do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1955 0 : if (!thisContent->IsInDoc()) {
1956 0 : return NS_ERROR_FAILURE;
1957 : }
1958 :
1959 0 : nsCOMPtr<nsIURI> kungFuURIGrip(mURI);
1960 0 : nsCString contentType(mContentType);
1961 0 : return InstantiatePluginInstance(contentType.get(), mURI.get());
1962 : }
1963 :
1964 : NS_IMETHODIMP
1965 0 : nsObjectLoadingContent::AsyncStartPluginInstance()
1966 : {
1967 : // OK to have an instance already.
1968 0 : if (mInstanceOwner) {
1969 0 : return NS_OK;
1970 : }
1971 :
1972 0 : nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1973 0 : nsIDocument* doc = thisContent->OwnerDoc();
1974 0 : if (doc->IsStaticDocument() || doc->IsBeingUsedAsImage()) {
1975 0 : return NS_OK;
1976 : }
1977 :
1978 : // We always start plugins on a runnable.
1979 : // We don't want a script blocker on the stack during instantiation.
1980 0 : nsCOMPtr<nsIRunnable> event = new nsAsyncInstantiateEvent(this);
1981 0 : if (!event) {
1982 0 : return NS_ERROR_OUT_OF_MEMORY;
1983 : }
1984 0 : nsresult rv = NS_DispatchToCurrentThread(event);
1985 0 : if (NS_SUCCEEDED(rv)) {
1986 : // Remember this event. This is a weak reference that will be cleared
1987 : // when the event runs.
1988 0 : mPendingInstantiateEvent = event;
1989 : }
1990 :
1991 0 : return rv;
1992 : }
1993 :
1994 : NS_IMETHODIMP
1995 0 : nsObjectLoadingContent::GetSrcURI(nsIURI** aURI)
1996 : {
1997 0 : NS_IF_ADDREF(*aURI = mURI);
1998 0 : return NS_OK;
1999 : }
2000 :
2001 : static bool
2002 0 : DoDelayedStop(nsPluginInstanceOwner *aInstanceOwner, bool aDelayedStop)
2003 : {
2004 : #if (MOZ_PLATFORM_MAEMO==5)
2005 : // Don't delay stop on Maemo/Hildon (bug 530739).
2006 : if (aDelayedStop && aInstanceOwner->MatchPluginName("Shockwave Flash"))
2007 : return false;
2008 : #endif
2009 :
2010 : // Don't delay stopping QuickTime (bug 425157), Flip4Mac (bug 426524),
2011 : // XStandard (bug 430219), CMISS Zinc (bug 429604).
2012 0 : if (aDelayedStop
2013 : #if !(defined XP_WIN || defined MOZ_X11)
2014 : && !aInstanceOwner->MatchPluginName("QuickTime")
2015 : && !aInstanceOwner->MatchPluginName("Flip4Mac")
2016 : && !aInstanceOwner->MatchPluginName("XStandard plugin")
2017 : && !aInstanceOwner->MatchPluginName("CMISS Zinc Plugin")
2018 : #endif
2019 : ) {
2020 0 : nsCOMPtr<nsIRunnable> evt = new nsStopPluginRunnable(aInstanceOwner);
2021 0 : NS_DispatchToCurrentThread(evt);
2022 0 : return true;
2023 : }
2024 0 : return false;
2025 : }
2026 :
2027 : void
2028 0 : nsObjectLoadingContent::DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner, bool aDelayedStop)
2029 : {
2030 0 : nsRefPtr<nsNPAPIPluginInstance> inst;
2031 0 : aInstanceOwner->GetInstance(getter_AddRefs(inst));
2032 0 : if (inst) {
2033 0 : if (DoDelayedStop(aInstanceOwner, aDelayedStop)) {
2034 : return;
2035 : }
2036 :
2037 : #if defined(XP_MACOSX)
2038 : aInstanceOwner->HidePluginWindow();
2039 : #endif
2040 :
2041 0 : nsCOMPtr<nsIPluginHost> pluginHost = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
2042 0 : NS_ASSERTION(pluginHost, "Without a pluginHost, how can we have an instance to destroy?");
2043 0 : static_cast<nsPluginHost*>(pluginHost.get())->StopPluginInstance(inst);
2044 : }
2045 :
2046 0 : aInstanceOwner->Destroy();
2047 : }
2048 :
2049 : NS_IMETHODIMP
2050 0 : nsObjectLoadingContent::StopPluginInstance()
2051 : {
2052 0 : if (!mInstanceOwner) {
2053 0 : return NS_OK;
2054 : }
2055 :
2056 0 : DisconnectFrame();
2057 :
2058 0 : bool delayedStop = false;
2059 : #ifdef XP_WIN
2060 : // Force delayed stop for Real plugin only; see bug 420886, 426852.
2061 : nsRefPtr<nsNPAPIPluginInstance> inst;
2062 : mInstanceOwner->GetInstance(getter_AddRefs(inst));
2063 : if (inst) {
2064 : const char* mime = nsnull;
2065 : if (NS_SUCCEEDED(inst->GetMIMEType(&mime)) && mime) {
2066 : if (strcmp(mime, "audio/x-pn-realaudio-plugin") == 0) {
2067 : delayedStop = true;
2068 : }
2069 : }
2070 : }
2071 : #endif
2072 :
2073 : // DoStopPlugin can process events and there may be pending InDocCheckEvent
2074 : // events which can drop in underneath us and destroy the instance we are
2075 : // about to destroy. Make sure this doesn't happen via this temp ref ptr and
2076 : // the !mInstanceOwner check above.
2077 0 : nsRefPtr<nsPluginInstanceOwner> instOwner = mInstanceOwner;
2078 0 : mInstanceOwner = nsnull;
2079 0 : DoStopPlugin(instOwner, delayedStop);
2080 0 : return NS_OK;
2081 : }
2082 :
2083 : void
2084 0 : nsObjectLoadingContent::NotifyContentObjectWrapper()
2085 : {
2086 0 : nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
2087 :
2088 0 : nsCOMPtr<nsIDocument> doc = thisContent->GetDocument();
2089 0 : if (!doc)
2090 : return;
2091 :
2092 0 : nsIScriptGlobalObject *sgo = doc->GetScopeObject();
2093 0 : if (!sgo)
2094 : return;
2095 :
2096 0 : nsIScriptContext *scx = sgo->GetContext();
2097 0 : if (!scx)
2098 : return;
2099 :
2100 0 : JSContext *cx = scx->GetNativeContext();
2101 :
2102 0 : nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
2103 0 : nsContentUtils::XPConnect()->
2104 0 : GetWrappedNativeOfNativeObject(cx, sgo->GetGlobalJSObject(), thisContent,
2105 : NS_GET_IID(nsISupports),
2106 0 : getter_AddRefs(wrapper));
2107 :
2108 0 : if (!wrapper) {
2109 : // Nothing to do here if there's no wrapper for mContent. The proto
2110 : // chain will be fixed appropriately when the wrapper is created.
2111 : return;
2112 : }
2113 :
2114 0 : JSObject *obj = nsnull;
2115 0 : nsresult rv = wrapper->GetJSObject(&obj);
2116 0 : if (NS_FAILED(rv))
2117 : return;
2118 :
2119 0 : nsHTMLPluginObjElementSH::SetupProtoChain(wrapper, cx, obj);
2120 : }
2121 :
2122 : NS_IMETHODIMP
2123 0 : nsObjectLoadingContent::PlayPlugin()
2124 : {
2125 0 : if (!nsContentUtils::IsCallerChrome())
2126 0 : return NS_OK;
2127 :
2128 0 : mShouldPlay = true;
2129 0 : return LoadObject(mURI, true, mContentType, true);
2130 4188 : }
|