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 /* 8 * A base class implementing nsIObjectLoadingContent for use by 9 * various content nodes that want to provide plugin/document/image 10 * loading functionality (eg <embed>, <object>, etc). 11 */ 12 13 #ifndef NSOBJECTLOADINGCONTENT_H_ 14 #define NSOBJECTLOADINGCONTENT_H_ 15 16 #include "mozilla/Attributes.h" 17 #include "mozilla/Maybe.h" 18 #include "mozilla/dom/BindingDeclarations.h" 19 #include "nsIFrame.h" // for WeakFrame only 20 #include "nsImageLoadingContent.h" 21 #include "nsIStreamListener.h" 22 #include "nsIChannelEventSink.h" 23 #include "nsIObjectLoadingContent.h" 24 #include "nsIRunnable.h" 25 #include "nsFrameLoaderOwner.h" 26 27 class nsAsyncInstantiateEvent; 28 class nsStopPluginRunnable; 29 class AutoSetInstantiatingToFalse; 30 class nsIPrincipal; 31 class nsFrameLoader; 32 33 namespace mozilla { 34 namespace dom { 35 struct BindContext; 36 template <typename T> 37 class Sequence; 38 struct MozPluginParameter; 39 class HTMLIFrameElement; 40 template <typename T> 41 struct Nullable; 42 class WindowProxyHolder; 43 class XULFrameElement; 44 } // namespace dom 45 } // namespace mozilla 46 47 class nsObjectLoadingContent : public nsImageLoadingContent, 48 public nsIStreamListener, 49 public nsFrameLoaderOwner, 50 public nsIObjectLoadingContent, 51 public nsIChannelEventSink { 52 friend class AutoSetInstantiatingToFalse; 53 friend class AutoSetLoadingToFalse; 54 friend class CheckPluginStopEvent; 55 friend class nsStopPluginRunnable; 56 friend class nsAsyncInstantiateEvent; 57 58 public: 59 // This enum's values must be the same as the constants on 60 // nsIObjectLoadingContent 61 enum ObjectType { 62 // Loading, type not yet known. We may be waiting for a channel to open. 63 eType_Loading = TYPE_LOADING, 64 // Content is a *non-svg* image 65 eType_Image = TYPE_IMAGE, 66 // Content is a "special" plugin. Plugins are removed but these MIME 67 // types display an transparent region in their place. 68 // (Special plugins that have an HTML fallback are eType_Null) 69 eType_Fallback = TYPE_FALLBACK, 70 // Content is a fake plugin, which loads as a document but behaves as a 71 // plugin (see nsPluginHost::CreateFakePlugin). Currently only used for 72 // pdf.js. 73 eType_FakePlugin = TYPE_FAKE_PLUGIN, 74 // Content is a subdocument, possibly SVG 75 eType_Document = TYPE_DOCUMENT, 76 // Content is unknown and should be represented by an empty element, 77 // unless an HTML fallback is available. 78 eType_Null = TYPE_NULL 79 }; 80 81 nsObjectLoadingContent(); 82 virtual ~nsObjectLoadingContent(); 83 84 NS_DECL_NSIREQUESTOBSERVER 85 NS_DECL_NSISTREAMLISTENER 86 NS_DECL_NSIOBJECTLOADINGCONTENT 87 NS_DECL_NSICHANNELEVENTSINK 88 89 /** 90 * Object state. This is a bitmask of NS_EVENT_STATEs epresenting the 91 * current state of the object. 92 */ 93 mozilla::EventStates ObjectState() const; 94 Type()95 ObjectType Type() const { return mType; } 96 SetIsNetworkCreated(bool aNetworkCreated)97 void SetIsNetworkCreated(bool aNetworkCreated) { 98 mNetworkCreated = aNetworkCreated; 99 } 100 101 /** 102 * When the object is loaded, the attributes and all nested <param> 103 * elements are cached as name:value string pairs to be passed as 104 * parameters when instantiating the plugin. 105 * 106 * Note: these cached values can be overriden for different quirk cases. 107 */ 108 // Returns the cached attributes array. 109 void GetPluginAttributes( 110 nsTArray<mozilla::dom::MozPluginParameter>& aAttributes); 111 112 // Returns the cached <param> array. 113 void GetPluginParameters( 114 nsTArray<mozilla::dom::MozPluginParameter>& aParameters); 115 116 /** 117 * Immediately instantiate a plugin instance. This is a no-op if mType != 118 * eType_Plugin or a plugin is already running. 119 * 120 * aIsLoading indicates that we are in the loading code, and we can bypass 121 * the mIsLoading check. 122 */ 123 nsresult InstantiatePluginInstance(bool aIsLoading = false); 124 125 /** 126 * Notify this class the document state has changed 127 * Called by Document so we may suspend plugins in inactive documents) 128 */ 129 void NotifyOwnerDocumentActivityChanged(); 130 131 // Helper for WebIDL NeedResolve 132 bool DoResolve( 133 JSContext* aCx, JS::Handle<JSObject*> aObject, JS::Handle<jsid> aId, 134 JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> aDesc); 135 // The return value is whether DoResolve might end up resolving the given 136 // id. If in doubt, return true. 137 static bool MayResolve(jsid aId); 138 139 // Helper for WebIDL enumeration 140 void GetOwnPropertyNames(JSContext* aCx, 141 JS::MutableHandleVector<jsid> /* unused */, 142 bool /* unused */, mozilla::ErrorResult& aRv); 143 144 // WebIDL API 145 mozilla::dom::Document* GetContentDocument(nsIPrincipal& aSubjectPrincipal); GetActualType(nsAString & aType)146 void GetActualType(nsAString& aType) const { 147 CopyUTF8toUTF16(mContentType, aType); 148 } DisplayedType()149 uint32_t DisplayedType() const { return mType; } GetContentTypeForMIMEType(const nsAString & aMIMEType)150 uint32_t GetContentTypeForMIMEType(const nsAString& aMIMEType) { 151 return GetTypeOfContent(NS_ConvertUTF16toUTF8(aMIMEType), false); 152 } Reload(bool aClearActivation,mozilla::ErrorResult & aRv)153 void Reload(bool aClearActivation, mozilla::ErrorResult& aRv) { 154 aRv = Reload(aClearActivation); 155 } GetSrcURI()156 nsIURI* GetSrcURI() const { return mURI; } 157 158 // FIXME rename this SkipFakePlugins(mozilla::ErrorResult & aRv)159 void SkipFakePlugins(mozilla::ErrorResult& aRv) { aRv = SkipFakePlugins(); } SwapFrameLoaders(mozilla::dom::HTMLIFrameElement & aOtherLoaderOwner,mozilla::ErrorResult & aRv)160 void SwapFrameLoaders(mozilla::dom::HTMLIFrameElement& aOtherLoaderOwner, 161 mozilla::ErrorResult& aRv) { 162 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); 163 } SwapFrameLoaders(mozilla::dom::XULFrameElement & aOtherLoaderOwner,mozilla::ErrorResult & aRv)164 void SwapFrameLoaders(mozilla::dom::XULFrameElement& aOtherLoaderOwner, 165 mozilla::ErrorResult& aRv) { 166 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); 167 } 168 169 uint32_t GetRunID(mozilla::dom::SystemCallerGuarantee, 170 mozilla::ErrorResult& aRv); 171 IsRewrittenYoutubeEmbed()172 bool IsRewrittenYoutubeEmbed() const { return mRewrittenYoutubeEmbed; } 173 174 void PresetOpenerWindow(const mozilla::dom::Nullable< 175 mozilla::dom::WindowProxyHolder>& aOpenerWindow, 176 mozilla::ErrorResult& aRv); 177 GetSubdocumentIntrinsicSize()178 const mozilla::Maybe<mozilla::IntrinsicSize>& GetSubdocumentIntrinsicSize() 179 const { 180 return mSubdocumentIntrinsicSize; 181 } 182 GetSubdocumentIntrinsicRatio()183 const mozilla::Maybe<mozilla::AspectRatio>& GetSubdocumentIntrinsicRatio() 184 const { 185 return mSubdocumentIntrinsicRatio; 186 } 187 188 void SubdocumentIntrinsicSizeOrRatioChanged( 189 const mozilla::Maybe<mozilla::IntrinsicSize>& aIntrinsicSize, 190 const mozilla::Maybe<mozilla::AspectRatio>& aIntrinsicRatio); 191 192 protected: 193 /** 194 * Begins loading the object when called 195 * 196 * Attributes of |this| QI'd to nsIContent will be inspected, depending on 197 * the node type. This function currently assumes it is a <object> or 198 * <embed> tag. 199 * 200 * The instantiated plugin depends on: 201 * - The URI (<embed src>, <object data>) 202 * - The type 'hint' (type attribute) 203 * - The mime type returned by opening the URI 204 * - Enabled plugins claiming the ultimate mime type 205 * - The capabilities returned by GetCapabilities 206 * - The classid attribute, if eFallbackIfClassIDPresent is among the 207 * capabilities 208 * 209 * If eAllowPluginSkipChannel is true, we may skip opening the URI if our 210 * type hint points to a valid plugin, deferring that responsibility to the 211 * plugin. 212 * Similarly, if no URI is provided, but a type hint for a valid plugin is 213 * present, that plugin will be instantiated 214 * 215 * Otherwise a request to that URI is made and the type sent by the server 216 * is used to find a suitable handler, EXCEPT when: 217 * - The type hint refers to a *supported* plugin, in which case that 218 * plugin will be instantiated regardless of the server provided type 219 * - The server returns a binary-stream type, and our type hint refers to 220 * a valid non-document type, we will use the type hint 221 * 222 * @param aNotify If we should send notifications. If false, content 223 * loading may be deferred while appropriate frames are 224 * created 225 * @param aForceLoad If we should reload this content (and re-attempt the 226 * channel open) even if our parameters did not change 227 */ 228 nsresult LoadObject(bool aNotify, bool aForceLoad = false); 229 230 enum Capabilities { 231 eSupportImages = 1u << 0, // Images are supported (imgILoader) 232 eSupportPlugins = 1u << 1, // Plugins are supported (nsIPluginHost) 233 eSupportDocuments = 1u << 2, // Documents are supported 234 // (DocumentLoaderFactory) 235 // This flag always includes SVG 236 237 // Node supports class ID as an attribute, and should fallback if it is 238 // present, as class IDs are not supported. 239 eFallbackIfClassIDPresent = 1u << 3, 240 241 // If possible to get a *plugin* type from the type attribute *or* file 242 // extension, we can use that type and begin loading the plugin before 243 // opening a channel. 244 // A side effect of this is if the channel fails, the plugin is still 245 // running. 246 eAllowPluginSkipChannel = 1u << 4 247 }; 248 249 /** 250 * Returns the list of capabilities this content node supports. This is a 251 * bitmask consisting of flags from the Capabilities enum. 252 * 253 * The default implementation supports all types but not 254 * eSupportClassID or eAllowPluginSkipChannel 255 */ 256 virtual uint32_t GetCapabilities() const; 257 258 /** 259 * Destroys all loaded documents/plugins and releases references 260 */ 261 void Destroy(); 262 263 // Subclasses should call cycle collection methods from the respective 264 // traverse / unlink. 265 static void Traverse(nsObjectLoadingContent* tmp, 266 nsCycleCollectionTraversalCallback& cb); 267 static void Unlink(nsObjectLoadingContent* tmp); 268 269 void CreateStaticClone(nsObjectLoadingContent* aDest) const; 270 BindToTree(mozilla::dom::BindContext & aCxt,nsINode & aParent)271 nsresult BindToTree(mozilla::dom::BindContext& aCxt, nsINode& aParent) { 272 nsImageLoadingContent::BindToTree(aCxt, aParent); 273 return NS_OK; 274 } 275 void UnbindFromTree(bool aNullParent = true); 276 277 /** 278 * Return the content policy type used for loading the element. 279 */ 280 virtual nsContentPolicyType GetContentPolicyType() const = 0; 281 282 /** 283 * Decides whether we should load <embed>/<object> node content. 284 * 285 * If this is an <embed> or <object> node there are cases in which we should 286 * not try to load the content: 287 * 288 * - If the node is the child of a media element 289 * - If the node is the child of an <object> node that already has 290 * content being loaded. 291 * 292 * In these cases, this function will return false, which will cause 293 * us to skip calling LoadObject. 294 */ 295 bool BlockEmbedOrObjectContentLoading(); 296 297 private: 298 // Object parameter changes returned by UpdateObjectParameters 299 enum ParameterUpdateFlags { 300 eParamNoChange = 0, 301 // Parameters that potentially affect the channel changed 302 // - mOriginalURI, mOriginalContentType 303 eParamChannelChanged = 1u << 0, 304 // Parameters that affect displayed content changed 305 // - mURI, mContentType, mType, mBaseURI 306 eParamStateChanged = 1u << 1, 307 // The effective content type changed, independant of object type. This 308 // can happen when changing from Loading -> Final type, but doesn't 309 // necessarily happen when changing between object types. E.g., if a PDF 310 // handler was installed between the last load of this object and now, we 311 // might change from eType_Document -> eType_Plugin without changing 312 // ContentType 313 eParamContentTypeChanged = 1u << 2 314 }; 315 316 /** 317 * Getter for child <param> elements that are not nested in another plugin 318 * dom element. 319 * This is an internal helper function and should not be used directly for 320 * passing parameters to the plugin instance. 321 * 322 * See GetPluginParameters and GetPluginAttributes, which also handle 323 * quirk-overrides. 324 * 325 * @param aParameters The array containing pairs of name/value strings 326 * from nested <param> objects. 327 */ 328 void GetNestedParams(nsTArray<mozilla::dom::MozPluginParameter>& aParameters); 329 330 [[nodiscard]] nsresult BuildParametersArray(); 331 332 /** 333 * Configure fallback for deprecated plugin and broken elements. 334 */ 335 void ConfigureFallback(); 336 337 /** 338 * Internal version of LoadObject that should only be used by this class 339 * aLoadingChannel is passed by the LoadObject call from OnStartRequest, 340 * primarily for sanity-preservation 341 */ 342 nsresult LoadObject(bool aNotify, bool aForceLoad, 343 nsIRequest* aLoadingChannel); 344 345 /** 346 * Inspects the object and sets the following member variables: 347 * - mOriginalContentType : This is the type attribute on the element 348 * - mOriginalURI : The src or data attribute on the element 349 * - mURI : The final URI, considering mChannel if 350 * mChannelLoaded is set 351 * - mContentType : The final content type, considering mChannel if 352 * mChannelLoaded is set 353 * - mBaseURI : The object's base URI, which may be set by the 354 * object 355 * - mType : The type the object is determined to be based 356 * on the above 357 * 358 * NOTE The class assumes that mType is the currently loaded type at various 359 * points, so the caller of this function must take the appropriate 360 * actions to ensure this 361 * 362 * NOTE This function does not perform security checks, only determining the 363 * requested type and parameters of the object. 364 * 365 * @return Returns a bitmask of ParameterUpdateFlags values 366 */ 367 ParameterUpdateFlags UpdateObjectParameters(); 368 369 /** 370 * Queue a CheckPluginStopEvent and track it in mPendingCheckPluginStopEvent 371 */ 372 void QueueCheckPluginStopEvent(); 373 374 public: 375 bool IsAboutBlankLoadOntoInitialAboutBlank(nsIURI* aURI, 376 bool aInheritPrincipal, 377 nsIPrincipal* aPrincipalToInherit); 378 379 private: 380 /** 381 * Opens the channel pointed to by mURI into mChannel. 382 */ 383 nsresult OpenChannel(); 384 385 /** 386 * Closes and releases references to mChannel and, if opened, mFinalListener 387 */ 388 nsresult CloseChannel(); 389 390 /** 391 * If this object should be tested against blocking list. 392 */ 393 bool ShouldBlockContent(); 394 395 /** 396 * This method tells the final answer on whether this object's fallback 397 * content should be used instead of the original plugin content. 398 * 399 * @param aIsPluginClickToPlay Whether this object instance is CTP. 400 */ 401 bool PreferFallback(bool aIsPluginClickToPlay); 402 403 /** 404 * Helper to check if our current URI passes policy 405 * 406 * @param aContentPolicy [out] The result of the content policy decision 407 * 408 * @return true if call succeeded and NS_CP_ACCEPTED(*aContentPolicy) 409 */ 410 bool CheckLoadPolicy(int16_t* aContentPolicy); 411 412 /** 413 * Helper to check if the object passes process policy. Assumes we have a 414 * final determined type. 415 * 416 * @param aContentPolicy [out] The result of the content policy decision 417 * 418 * @return true if call succeeded and NS_CP_ACCEPTED(*aContentPolicy) 419 */ 420 bool CheckProcessPolicy(int16_t* aContentPolicy); 421 422 void SetupFrameLoader(int32_t aJSPluginId); 423 424 /** 425 * Helper to spawn mFrameLoader and return a pointer to its docshell 426 * 427 * @param aURI URI we intend to load for the recursive load check (does not 428 * actually load anything) 429 */ 430 already_AddRefed<nsIDocShell> SetupDocShell(nsIURI* aRecursionCheckURI); 431 432 /** 433 * Unloads all content and resets the object to a completely unloaded state 434 * 435 * NOTE Calls StopPluginInstance() and may spin the event loop 436 * 437 * @param aResetState Reset the object type to 'loading' and destroy channel 438 * as well 439 */ 440 void UnloadObject(bool aResetState = true); 441 442 /** 443 * Notifies document observes about a new type/state of this object. 444 * Triggers frame construction as needed. mType must be set correctly when 445 * this method is called. This method is cheap if the type and state didn't 446 * actually change. 447 * 448 * @param aNotify if false, only need to update the state of our element. 449 */ 450 void NotifyStateChanged(ObjectType aOldType, mozilla::EventStates aOldState, 451 bool aNotify); 452 453 /** 454 * Returns a ObjectType value corresponding to the type of content we would 455 * support the given MIME type as, taking capabilities and plugin state 456 * into account 457 * 458 * @param aNoFakePlugin Don't select a fake plugin handler as a valid type, 459 * as when SkipFakePlugins() is called. 460 * @return The ObjectType enum value that we would attempt to load 461 * 462 * NOTE this does not consider whether the content would be suppressed by 463 * click-to-play or other content policy checks 464 */ 465 ObjectType GetTypeOfContent(const nsCString& aMIMEType, bool aNoFakePlugin); 466 467 /** 468 * Used for identifying whether we can rewrite a youtube flash embed to 469 * possibly use HTML5 instead. 470 * 471 * Returns true if plugin.rewrite_youtube_embeds pref is true and the 472 * element this nsObjectLoadingContent instance represents: 473 * 474 * - is an embed or object node 475 * - has a URL pointing at the youtube.com domain, using "/v/" style video 476 * path reference. 477 * 478 * Having the enablejsapi flag means the document that contains the element 479 * could possibly be manipulating the youtube video elsewhere on the page 480 * via javascript. In the context of embed elements, this usage has been 481 * deprecated by youtube, so we can just rewrite as normal. 482 * 483 * If we can rewrite the URL, we change the "/v/" to "/embed/", and change 484 * our type to eType_Document so that we render similarly to an iframe 485 * embed. 486 */ 487 void MaybeRewriteYoutubeEmbed(nsIURI* aURI, nsIURI* aBaseURI, 488 nsIURI** aRewrittenURI); 489 490 // Utility for firing an error event, if we're an <object>. 491 void MaybeFireErrorEvent(); 492 493 // The final listener for mChannel (uriloader, pluginstreamlistener, etc.) 494 nsCOMPtr<nsIStreamListener> mFinalListener; 495 496 // Track if we have a pending AsyncInstantiateEvent 497 nsCOMPtr<nsIRunnable> mPendingInstantiateEvent; 498 499 // Tracks if we have a pending CheckPluginStopEvent 500 nsCOMPtr<nsIRunnable> mPendingCheckPluginStopEvent; 501 502 // The content type of our current load target, updated by 503 // UpdateObjectParameters(). Takes the channel's type into account once 504 // opened. 505 // 506 // May change if a channel is opened, does not imply a loaded state 507 nsCString mContentType; 508 509 // The content type 'hint' provided by the element's type attribute. May 510 // or may not be used as a final type 511 nsCString mOriginalContentType; 512 513 // The channel that's currently being loaded. If set, but mChannelLoaded is 514 // false, has not yet reached OnStartRequest 515 nsCOMPtr<nsIChannel> mChannel; 516 517 // The URI of the current content. 518 // May change as we open channels and encounter redirects - does not imply 519 // a loaded type 520 nsCOMPtr<nsIURI> mURI; 521 522 // The original URI obtained from inspecting the element. May differ from 523 // mURI due to redirects 524 nsCOMPtr<nsIURI> mOriginalURI; 525 526 // The baseURI used for constructing mURI. 527 nsCOMPtr<nsIURI> mBaseURI; 528 529 // Type of the currently-loaded content. 530 ObjectType mType : 8; 531 532 uint32_t mRunID; 533 bool mHasRunID : 1; 534 535 // If true, we have opened a channel as the listener and it has reached 536 // OnStartRequest. Does not get set for channels that are passed directly to 537 // the plugin listener. 538 bool mChannelLoaded : 1; 539 540 // Whether we are about to call instantiate on our frame. If we aren't, 541 // SetFrame needs to asynchronously call Instantiate. 542 bool mInstantiating : 1; 543 544 // True when the object is created for an element which the parser has 545 // created using NS_FROM_PARSER_NETWORK flag. If the element is modified, 546 // it may lose the flag. 547 bool mNetworkCreated : 1; 548 549 // Whether content blocking is enabled or not for this object. 550 bool mContentBlockingEnabled : 1; 551 552 // If we should not use fake plugins until the next type change 553 bool mSkipFakePlugins : 1; 554 555 // Protects DoStopPlugin from reentry (bug 724781). 556 bool mIsStopping : 1; 557 558 // Protects LoadObject from re-entry 559 bool mIsLoading : 1; 560 561 // For plugin stand-in types (click-to-play) tracks whether content js has 562 // tried to access the plugin script object. 563 bool mScriptRequested : 1; 564 565 // True if object represents an object/embed tag pointing to a flash embed 566 // for a youtube video. When possible (see IsRewritableYoutubeEmbed function 567 // comments for details), we change these to try to load HTML5 versions of 568 // videos. 569 bool mRewrittenYoutubeEmbed : 1; 570 571 nsTArray<mozilla::dom::MozPluginParameter> mCachedAttributes; 572 nsTArray<mozilla::dom::MozPluginParameter> mCachedParameters; 573 574 // The intrinsic size and aspect ratio from a child SVG document that 575 // we should use. These are only set when we are an <object> or <embed> 576 // and the inner document is SVG. 577 // 578 // We store these here rather than on nsSubDocumentFrame since we are 579 // sometimes notified of our child's intrinsics before we've constructed 580 // our own frame. 581 mozilla::Maybe<mozilla::IntrinsicSize> mSubdocumentIntrinsicSize; 582 mozilla::Maybe<mozilla::AspectRatio> mSubdocumentIntrinsicRatio; 583 }; 584 585 #endif 586