nsObjectLoadingContent.h (18091B)
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/Maybe.h" 17 #include "mozilla/dom/BindingDeclarations.h" 18 #include "nsFrameLoaderOwner.h" 19 #include "nsIChannelEventSink.h" 20 #include "nsIFrame.h" // for WeakFrame only 21 #include "nsIObjectLoadingContent.h" 22 #include "nsIStreamListener.h" 23 24 class nsStopPluginRunnable; 25 class nsIPrincipal; 26 class nsFrameLoader; 27 28 namespace mozilla::dom { 29 struct BindContext; 30 class FeaturePolicy; 31 template <typename T> 32 class Sequence; 33 class HTMLIFrameElement; 34 template <typename T> 35 struct Nullable; 36 class WindowProxyHolder; 37 class XULFrameElement; 38 } // namespace mozilla::dom 39 40 class nsObjectLoadingContent : public nsIStreamListener, 41 public nsFrameLoaderOwner, 42 public nsIObjectLoadingContent, 43 public nsIChannelEventSink { 44 friend class AutoSetLoadingToFalse; 45 46 public: 47 // This enum's values must be the same as the constants on 48 // nsIObjectLoadingContent 49 enum class ObjectType : uint8_t { 50 // Loading, type not yet known. We may be waiting for a channel to open. 51 Loading = TYPE_LOADING, 52 // Content is a subdocument, possibly SVG 53 Document = TYPE_DOCUMENT, 54 // Content is unknown and should be represented by an empty element. 55 Fallback = TYPE_FALLBACK 56 }; 57 58 nsObjectLoadingContent(); 59 virtual ~nsObjectLoadingContent(); 60 61 NS_DECL_NSIREQUESTOBSERVER 62 NS_DECL_NSISTREAMLISTENER 63 NS_DECL_NSIOBJECTLOADINGCONTENT 64 NS_DECL_NSICHANNELEVENTSINK 65 66 ObjectType Type() const { return mType; } 67 68 void SetIsNetworkCreated(bool aNetworkCreated) { 69 mNetworkCreated = aNetworkCreated; 70 } 71 72 static bool IsSuccessfulRequest(nsIRequest*, nsresult* aStatus); 73 74 // WebIDL API 75 mozilla::dom::Document* GetContentDocument(nsIPrincipal& aSubjectPrincipal); 76 void GetActualType(nsAString& aType) const { 77 CopyUTF8toUTF16(mContentType, aType); 78 } 79 uint32_t DisplayedType() const { return uint32_t(mType); } 80 nsIURI* GetSrcURI() const { return mURI; } 81 82 void SwapFrameLoaders(mozilla::dom::HTMLIFrameElement& aOtherLoaderOwner, 83 mozilla::ErrorResult& aRv) { 84 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); 85 } 86 void SwapFrameLoaders(mozilla::dom::XULFrameElement& aOtherLoaderOwner, 87 mozilla::ErrorResult& aRv) { 88 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); 89 } 90 91 bool IsRewrittenYoutubeEmbed() const { return mRewrittenYoutubeEmbed; } 92 93 bool IsSyntheticImageDocument() const; 94 95 const mozilla::Maybe<mozilla::IntrinsicSize>& GetSubdocumentIntrinsicSize() 96 const { 97 return mSubdocumentIntrinsicSize; 98 } 99 100 const mozilla::Maybe<mozilla::AspectRatio>& GetSubdocumentIntrinsicRatio() 101 const { 102 return mSubdocumentIntrinsicRatio; 103 } 104 105 void SubdocumentIntrinsicSizeOrRatioChanged( 106 const mozilla::Maybe<mozilla::IntrinsicSize>& aIntrinsicSize, 107 const mozilla::Maybe<mozilla::AspectRatio>& aIntrinsicRatio); 108 109 void SubdocumentImageLoadComplete(nsresult aResult); 110 111 protected: 112 /** 113 * Begins loading the object when called 114 * 115 * Attributes of |this| QI'd to nsIContent will be inspected, depending on 116 * the node type. This function currently assumes it is a <object> or 117 * <embed> tag. 118 * 119 * The instantiated plugin depends on: 120 * - The URI (<embed src>, <object data>) 121 * - The type 'hint' (type attribute) 122 * - The mime type returned by opening the URI 123 * - Enabled plugins claiming the ultimate mime type 124 * - The capabilities returned by GetCapabilities 125 * - The classid attribute, if eFallbackIfClassIDPresent is among the 126 * capabilities 127 * 128 * If eAllowPluginSkipChannel is true, we may skip opening the URI if our 129 * type hint points to a valid plugin, deferring that responsibility to the 130 * plugin. 131 * Similarly, if no URI is provided, but a type hint for a valid plugin is 132 * present, that plugin will be instantiated 133 * 134 * Otherwise a request to that URI is made and the type sent by the server 135 * is used to find a suitable handler, EXCEPT when: 136 * - The type hint refers to a *supported* plugin, in which case that 137 * plugin will be instantiated regardless of the server provided type 138 * - The server returns a binary-stream type, and our type hint refers to 139 * a valid non-document type, we will use the type hint 140 * 141 * @param aNotify If we should send notifications. If false, content 142 * loading may be deferred while appropriate frames are 143 * created 144 * @param aForceLoad If we should reload this content (and re-attempt the 145 * channel open) even if our parameters did not change 146 */ 147 nsresult LoadObject(bool aNotify, bool aForceLoad = false); 148 149 enum Capabilities { 150 eSupportImages = 1u << 0, // Images are supported (imgILoader) 151 eSupportDocuments = 1u << 1, // Documents are supported 152 // (DocumentLoaderFactory) 153 // This flag always includes SVG 154 155 // Node supports class ID as an attribute, and should fallback if it is 156 // present, as class IDs are not supported. 157 eFallbackIfClassIDPresent = 1u << 2, 158 159 // If possible to get a *plugin* type from the type attribute *or* file 160 // extension, we can use that type and begin loading the plugin before 161 // opening a channel. 162 // A side effect of this is if the channel fails, the plugin is still 163 // running. 164 eAllowPluginSkipChannel = 1u << 3 165 }; 166 167 /** 168 * Returns the list of capabilities this content node supports. This is a 169 * bitmask consisting of flags from the Capabilities enum. 170 * 171 * The default implementation supports all types but not 172 * eSupportClassID or eAllowPluginSkipChannel 173 */ 174 virtual uint32_t GetCapabilities() const; 175 176 /** 177 * Destroys all loaded documents/plugins and releases references 178 */ 179 void Destroy(); 180 181 // Subclasses should call cycle collection methods from the respective 182 // traverse / unlink. 183 static void Traverse(nsObjectLoadingContent* tmp, 184 nsCycleCollectionTraversalCallback& cb); 185 static void Unlink(nsObjectLoadingContent* tmp); 186 187 void CreateStaticClone(nsObjectLoadingContent* aDest) const; 188 189 void UnbindFromTree(); 190 191 /** 192 * Return the content policy type used for loading the element. 193 */ 194 virtual nsContentPolicyType GetContentPolicyType() const = 0; 195 196 virtual const mozilla::dom::Element* AsElement() const = 0; 197 mozilla::dom::Element* AsElement() { 198 return const_cast<mozilla::dom::Element*>( 199 const_cast<const nsObjectLoadingContent*>(this)->AsElement()); 200 } 201 202 /** 203 * Decides whether we should load <embed>/<object> node content. 204 * 205 * If this is an <embed> or <object> node there are cases in which we should 206 * not try to load the content: 207 * 208 * - If the node is the child of a media element 209 * - If the node is the child of an <object> node that already has 210 * content being loaded. 211 * 212 * In these cases, this function will return false, which will cause 213 * us to skip calling LoadObject. 214 */ 215 bool BlockEmbedOrObjectContentLoading(); 216 217 /** 218 * Updates and stores the container's feature policy in its canonical browsing 219 * context. This gets called whenever the feature policy has changed, which 220 * can happen when this element is upgraded to a container or when the URI of 221 * the element has changed. 222 */ 223 void RefreshFeaturePolicy(); 224 225 private: 226 // Object parameter changes returned by UpdateObjectParameters 227 enum ParameterUpdateFlags { 228 eParamNoChange = 0, 229 // Parameters that potentially affect the channel changed 230 // - mOriginalURI, mOriginalContentType 231 eParamChannelChanged = 1u << 0, 232 // Parameters that affect displayed content changed 233 // - mURI, mContentType, mType, mBaseURI 234 eParamStateChanged = 1u << 1, 235 // The effective content type changed, independant of object type. This 236 // can happen when changing from Loading -> Final type, but doesn't 237 // necessarily happen when changing between object types. E.g., if a PDF 238 // handler was installed between the last load of this object and now, we 239 // might change from Document -> Plugin without changing 240 // ContentType 241 eParamContentTypeChanged = 1u << 2 242 }; 243 244 /** 245 * If we're an <object>, and show fallback, we might need to start nested 246 * <embed> or <object> loads that would otherwise be blocked by 247 * BlockEmbedOrObjectContentLoading(). 248 */ 249 void TriggerInnerFallbackLoads(); 250 251 /** 252 * Internal version of LoadObject that should only be used by this class 253 * aLoadingChannel is passed by the LoadObject call from OnStartRequest, 254 * primarily for sanity-preservation 255 */ 256 nsresult LoadObject(bool aNotify, bool aForceLoad, 257 nsIRequest* aLoadingChannel); 258 259 /** 260 * Inspects the object and sets the following member variables: 261 * - mOriginalContentType : This is the type attribute on the element 262 * - mOriginalURI : The src or data attribute on the element 263 * - mURI : The final URI, considering mChannel if 264 * mChannelLoaded is set 265 * - mContentType : The final content type, considering mChannel if 266 * mChannelLoaded is set 267 * - mBaseURI : The object's base URI, which may be set by the 268 * object 269 * - mType : The type the object is determined to be based 270 * on the above 271 * 272 * NOTE The class assumes that mType is the currently loaded type at various 273 * points, so the caller of this function must take the appropriate 274 * actions to ensure this 275 * 276 * NOTE This function does not perform security checks, only determining the 277 * requested type and parameters of the object. 278 * 279 * @return Returns a bitmask of ParameterUpdateFlags values 280 */ 281 ParameterUpdateFlags UpdateObjectParameters(); 282 283 public: 284 bool IsAboutBlankLoadOntoInitialAboutBlank(nsIURI* aURI, 285 bool aInheritPrincipal, 286 nsIPrincipal* aPrincipalToInherit); 287 288 private: 289 /** 290 * Opens the channel pointed to by mURI into mChannel. 291 */ 292 nsresult OpenChannel(); 293 294 /** 295 * Closes and releases references to mChannel and, if opened, mFinalListener 296 */ 297 nsresult CloseChannel(); 298 299 /** 300 * If this object should be tested against blocking list. 301 */ 302 bool ShouldBlockContent(); 303 304 /** 305 * This method tells the final answer on whether this object's fallback 306 * content should be used instead of the original plugin content. 307 * 308 * @param aIsPluginClickToPlay Whether this object instance is CTP. 309 */ 310 bool PreferFallback(bool aIsPluginClickToPlay); 311 312 /** 313 * Helper to check if our current URI passes policy 314 * 315 * @param aContentPolicy [out] The result of the content policy decision 316 * 317 * @return true if call succeeded and NS_CP_ACCEPTED(*aContentPolicy) 318 */ 319 bool CheckLoadPolicy(int16_t* aContentPolicy); 320 321 /** 322 * Helper to check if the object passes process policy. Assumes we have a 323 * final determined type. 324 * 325 * @param aContentPolicy [out] The result of the content policy decision 326 * 327 * @return true if call succeeded and NS_CP_ACCEPTED(*aContentPolicy) 328 */ 329 bool CheckProcessPolicy(int16_t* aContentPolicy); 330 331 void SetupFrameLoader(); 332 333 /** 334 * Helper to spawn mFrameLoader and return a pointer to its docshell 335 * 336 * @param aURI URI we intend to load for the recursive load check (does not 337 * actually load anything) 338 */ 339 already_AddRefed<nsIDocShell> SetupDocShell(nsIURI* aRecursionCheckURI); 340 341 /** 342 * Unloads all content and resets the object to a completely unloaded state 343 * 344 * NOTE Calls StopPluginInstance() and may spin the event loop 345 * 346 * @param aResetState Reset the object type to 'loading' and destroy channel 347 * as well 348 */ 349 void UnloadObject(bool aResetState = true); 350 351 /** 352 * Notifies document observes about a new type/state of this object. 353 * Triggers frame construction as needed. mType must be set correctly when 354 * this method is called. This method is cheap if the type and state didn't 355 * actually change. 356 * 357 * @param aNotify if false, only need to update the state of our element. 358 */ 359 void NotifyStateChanged(ObjectType aOldType, bool aNotify); 360 361 /** 362 * Returns a ObjectType value corresponding to the type of content we would 363 * support the given MIME type as, taking capabilities and plugin state 364 * into account 365 * 366 * @return The ObjectType enum value that we would attempt to load 367 * 368 * NOTE this does not consider whether the content would be suppressed by 369 * click-to-play or other content policy checks 370 */ 371 ObjectType GetTypeOfContent(const nsCString& aMIMEType); 372 373 /** 374 * Used for identifying whether we can rewrite a youtube flash embed to 375 * possibly use HTML5 instead. 376 * 377 * Returns true if plugin.rewrite_youtube_embeds pref is true and the 378 * element this nsObjectLoadingContent instance represents: 379 * 380 * - is an embed or object node 381 * - has a URL pointing at the youtube.com domain, using "/v/" style video 382 * path reference. 383 * 384 * Having the enablejsapi flag means the document that contains the element 385 * could possibly be manipulating the youtube video elsewhere on the page 386 * via javascript. In the context of embed elements, this usage has been 387 * deprecated by youtube, so we can just rewrite as normal. 388 * 389 * If we can rewrite the URL, we change the "/v/" to "/embed/", and change 390 * our type to Document so that we render similarly to an iframe 391 * embed. 392 */ 393 void MaybeRewriteYoutubeEmbed(nsIURI* aURI, nsIURI* aBaseURI, 394 nsIURI** aRewrittenURI); 395 396 // Utility for firing an error event, if we're an <object>. 397 void MaybeFireErrorEvent(); 398 399 /** 400 * Store feature policy in container browsing context so that it can be 401 * accessed cross process. 402 */ 403 void MaybeStoreCrossOriginFeaturePolicy(); 404 405 /** 406 * Return the value of either `data` or `src`, depending on element type, 407 * parsed as a URL. If URL is invalid or the attribute is missing this returns 408 * the document's origin. 409 */ 410 static already_AddRefed<nsIPrincipal> GetFeaturePolicyDefaultOrigin( 411 nsINode* aNode); 412 413 // The final listener for mChannel (uriloader, pluginstreamlistener, etc.) 414 nsCOMPtr<nsIStreamListener> mFinalListener; 415 416 // The content type of our current load target, updated by 417 // UpdateObjectParameters(). Takes the channel's type into account once 418 // opened. 419 // 420 // May change if a channel is opened, does not imply a loaded state 421 nsCString mContentType; 422 423 // The content type 'hint' provided by the element's type attribute. May 424 // or may not be used as a final type 425 nsCString mOriginalContentType; 426 427 // The channel that's currently being loaded. If set, but mChannelLoaded is 428 // false, has not yet reached OnStartRequest 429 nsCOMPtr<nsIChannel> mChannel; 430 431 // The URI of the current content. 432 // May change as we open channels and encounter redirects - does not imply 433 // a loaded type 434 nsCOMPtr<nsIURI> mURI; 435 436 // The original URI obtained from inspecting the element. May differ from 437 // mURI due to redirects 438 nsCOMPtr<nsIURI> mOriginalURI; 439 440 // The baseURI used for constructing mURI. 441 nsCOMPtr<nsIURI> mBaseURI; 442 443 // Type of the currently-loaded content. 444 ObjectType mType; 445 446 // If true, we have opened a channel as the listener and it has reached 447 // OnStartRequest. Does not get set for channels that are passed directly to 448 // the plugin listener. 449 bool mChannelLoaded : 1; 450 451 // True when the object is created for an element which the parser has 452 // created using NS_FROM_PARSER_NETWORK flag. If the element is modified, 453 // it may lose the flag. 454 bool mNetworkCreated : 1; 455 456 // Whether content blocking is enabled or not for this object. 457 bool mContentBlockingEnabled : 1; 458 459 // Protects DoStopPlugin from reentry (bug 724781). 460 bool mIsStopping : 1; 461 462 // Protects LoadObject from re-entry 463 bool mIsLoading : 1; 464 465 // For plugin stand-in types (click-to-play) tracks whether content js has 466 // tried to access the plugin script object. 467 bool mScriptRequested : 1; 468 469 // True if object represents an object/embed tag pointing to a flash embed 470 // for a youtube video. When possible (see IsRewritableYoutubeEmbed function 471 // comments for details), we change these to try to load HTML5 versions of 472 // videos. 473 bool mRewrittenYoutubeEmbed : 1; 474 475 // The intrinsic size and aspect ratio from a child SVG document that 476 // we should use. These are only set when we are an <object> or <embed> 477 // and the inner document is SVG. 478 // 479 // We store these here rather than on nsSubDocumentFrame since we are 480 // sometimes notified of our child's intrinsics before we've constructed 481 // our own frame. 482 mozilla::Maybe<mozilla::IntrinsicSize> mSubdocumentIntrinsicSize; 483 mozilla::Maybe<mozilla::AspectRatio> mSubdocumentIntrinsicRatio; 484 485 // This gets created on the first call of `RefreshFeaturePolicy`, and will be 486 // kept after that. Navigations of this element will use this if they're 487 // targetting documents, which is how iframe element works. If it's a 488 // non-document the feature policy isn't used, but it doesn't hurt to keep it 489 // around, and a subsequent document load will continue using it after 490 // refreshing it. 491 RefPtr<mozilla::dom::FeaturePolicy> mFeaturePolicy; 492 }; 493 494 #endif