tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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