Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:set et cin sw=2 sts=2:
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/. */
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>, <applet>, etc).
11 */
13 #ifndef NSOBJECTLOADINGCONTENT_H_
14 #define NSOBJECTLOADINGCONTENT_H_
16 #include "mozilla/Attributes.h"
17 #include "nsImageLoadingContent.h"
18 #include "nsIStreamListener.h"
19 #include "nsIChannelEventSink.h"
20 #include "nsIObjectLoadingContent.h"
21 #include "nsIRunnable.h"
22 #include "nsIThreadInternal.h"
23 #include "nsIFrame.h"
24 #include "nsIFrameLoader.h"
26 class nsAsyncInstantiateEvent;
27 class nsStopPluginRunnable;
28 class AutoSetInstantiatingToFalse;
29 class nsObjectFrame;
30 class nsFrameLoader;
31 class nsXULElement;
32 class nsPluginInstanceOwner;
34 namespace mozilla {
35 namespace dom {
36 template<typename T> class Sequence;
37 }
38 }
40 class nsObjectLoadingContent : public nsImageLoadingContent
41 , public nsIStreamListener
42 , public nsIFrameLoaderOwner
43 , public nsIObjectLoadingContent
44 , public nsIChannelEventSink
45 {
46 friend class AutoSetInstantiatingToFalse;
47 friend class AutoSetLoadingToFalse;
48 friend class CheckPluginStopEvent;
49 friend class nsStopPluginRunnable;
50 friend class nsAsyncInstantiateEvent;
52 public:
53 // This enum's values must be the same as the constants on
54 // nsIObjectLoadingContent
55 enum ObjectType {
56 // Loading, type not yet known. We may be waiting for a channel to open.
57 eType_Loading = TYPE_LOADING,
58 // Content is a *non-svg* image
59 eType_Image = TYPE_IMAGE,
60 // Content is a plugin
61 eType_Plugin = TYPE_PLUGIN,
62 // Content is a subdocument, possibly SVG
63 eType_Document = TYPE_DOCUMENT,
64 // No content loaded (fallback). May be showing alternate content or
65 // a custom error handler - *including* click-to-play dialogs
66 eType_Null = TYPE_NULL
67 };
68 enum FallbackType {
69 // The content type is not supported (e.g. plugin not installed)
70 eFallbackUnsupported = nsIObjectLoadingContent::PLUGIN_UNSUPPORTED,
71 // Showing alternate content
72 eFallbackAlternate = nsIObjectLoadingContent::PLUGIN_ALTERNATE,
73 // The plugin exists, but is disabled
74 eFallbackDisabled = nsIObjectLoadingContent::PLUGIN_DISABLED,
75 // The plugin is blocklisted and disabled
76 eFallbackBlocklisted = nsIObjectLoadingContent::PLUGIN_BLOCKLISTED,
77 // The plugin is considered outdated, but not disabled
78 eFallbackOutdated = nsIObjectLoadingContent::PLUGIN_OUTDATED,
79 // The plugin has crashed
80 eFallbackCrashed = nsIObjectLoadingContent::PLUGIN_CRASHED,
81 // Suppressed by security policy
82 eFallbackSuppressed = nsIObjectLoadingContent::PLUGIN_SUPPRESSED,
83 // Blocked by content policy
84 eFallbackUserDisabled = nsIObjectLoadingContent::PLUGIN_USER_DISABLED,
85 /// ** All values >= eFallbackClickToPlay are plugin placeholder types
86 /// that would be replaced by a real plugin if activated (PlayPlugin())
87 /// ** Furthermore, values >= eFallbackClickToPlay and
88 /// <= eFallbackVulnerableNoUpdate are click-to-play types.
89 // The plugin is disabled until the user clicks on it
90 eFallbackClickToPlay = nsIObjectLoadingContent::PLUGIN_CLICK_TO_PLAY,
91 // The plugin is vulnerable (update available)
92 eFallbackVulnerableUpdatable = nsIObjectLoadingContent::PLUGIN_VULNERABLE_UPDATABLE,
93 // The plugin is vulnerable (no update available)
94 eFallbackVulnerableNoUpdate = nsIObjectLoadingContent::PLUGIN_VULNERABLE_NO_UPDATE,
95 // The plugin is disabled and play preview content is displayed until
96 // the extension code enables it by sending the MozPlayPlugin event
97 eFallbackPlayPreview = nsIObjectLoadingContent::PLUGIN_PLAY_PREVIEW
98 };
100 nsObjectLoadingContent();
101 virtual ~nsObjectLoadingContent();
103 NS_DECL_NSIREQUESTOBSERVER
104 NS_DECL_NSISTREAMLISTENER
105 NS_DECL_NSIFRAMELOADEROWNER
106 NS_DECL_NSIOBJECTLOADINGCONTENT
107 NS_DECL_NSICHANNELEVENTSINK
109 /**
110 * Object state. This is a bitmask of NS_EVENT_STATEs epresenting the
111 * current state of the object.
112 */
113 mozilla::EventStates ObjectState() const;
115 ObjectType Type() const { return mType; }
117 void SetIsNetworkCreated(bool aNetworkCreated)
118 {
119 mNetworkCreated = aNetworkCreated;
120 }
122 /**
123 * Immediately instantiate a plugin instance. This is a no-op if mType !=
124 * eType_Plugin or a plugin is already running.
125 *
126 * aIsLoading indicates that we are in the loading code, and we can bypass
127 * the mIsLoading check.
128 */
129 nsresult InstantiatePluginInstance(bool aIsLoading = false);
131 /**
132 * Notify this class the document state has changed
133 * Called by nsDocument so we may suspend plugins in inactive documents)
134 */
135 void NotifyOwnerDocumentActivityChanged();
137 /**
138 * When a plug-in is instantiated, it can create a scriptable
139 * object that the page wants to interact with. We expose this
140 * object by placing it on the prototype chain of our element,
141 * between the element itself and its most-derived DOM prototype.
142 *
143 * SetupProtoChain handles actually inserting the plug-in
144 * scriptable object into the proto chain if needed.
145 *
146 * DoNewResolve is a hook that allows us to find out when the web
147 * page is looking up a property name on our object and make sure
148 * that our plug-in, if any, is instantiated.
149 */
150 // Helper for WebIDL node wrapping
151 void SetupProtoChain(JSContext* aCx, JS::Handle<JSObject*> aObject);
153 // Remove plugin from protochain
154 void TeardownProtoChain();
156 // Helper for WebIDL newResolve
157 bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
158 JS::Handle<jsid> aId,
159 JS::MutableHandle<JSPropertyDescriptor> aDesc);
160 // Helper for WebIDL enumeration
161 void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& /* unused */,
162 mozilla::ErrorResult& aRv);
164 // WebIDL API
165 nsIDocument* GetContentDocument();
166 void GetActualType(nsAString& aType) const
167 {
168 CopyUTF8toUTF16(mContentType, aType);
169 }
170 uint32_t DisplayedType() const
171 {
172 return mType;
173 }
174 uint32_t GetContentTypeForMIMEType(const nsAString& aMIMEType)
175 {
176 return GetTypeOfContent(NS_ConvertUTF16toUTF8(aMIMEType));
177 }
178 void PlayPlugin(mozilla::ErrorResult& aRv)
179 {
180 aRv = PlayPlugin();
181 }
182 void Reload(bool aClearActivation, mozilla::ErrorResult& aRv)
183 {
184 aRv = Reload(aClearActivation);
185 }
186 bool Activated() const
187 {
188 return mActivated;
189 }
190 nsIURI* GetSrcURI() const
191 {
192 return mURI;
193 }
195 /**
196 * The default state that this plugin would be without manual activation.
197 * @returns PLUGIN_ACTIVE if the default state would be active.
198 */
199 uint32_t DefaultFallbackType();
201 uint32_t PluginFallbackType() const
202 {
203 return mFallbackType;
204 }
205 bool HasRunningPlugin() const
206 {
207 return !!mInstanceOwner;
208 }
209 void CancelPlayPreview(mozilla::ErrorResult& aRv)
210 {
211 aRv = CancelPlayPreview();
212 }
213 void SwapFrameLoaders(nsXULElement& aOtherOwner, mozilla::ErrorResult& aRv)
214 {
215 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
216 }
217 void LegacyCall(JSContext* aCx, JS::Handle<JS::Value> aThisVal,
218 const mozilla::dom::Sequence<JS::Value>& aArguments,
219 JS::MutableHandle<JS::Value> aRetval,
220 mozilla::ErrorResult& aRv);
222 protected:
223 /**
224 * Begins loading the object when called
225 *
226 * Attributes of |this| QI'd to nsIContent will be inspected, depending on
227 * the node type. This function currently assumes it is a <applet>,
228 * <object>, or <embed> tag.
229 *
230 * The instantiated plugin depends on:
231 * - The URI (<embed src>, <object data>)
232 * - The type 'hint' (type attribute)
233 * - The mime type returned by opening the URI
234 * - Enabled plugins claiming the ultimate mime type
235 * - The capabilities returned by GetCapabilities
236 * - The classid attribute, if eSupportClassID is among the capabilities
237 *
238 * If eAllowPluginSkipChannel is true, we may skip opening the URI if our
239 * type hint points to a valid plugin, deferring that responsibility to the
240 * plugin.
241 * Similarly, if no URI is provided, but a type hint for a valid plugin is
242 * present, that plugin will be instantiated
243 *
244 * Otherwise a request to that URI is made and the type sent by the server
245 * is used to find a suitable handler, EXCEPT when:
246 * - The type hint refers to a *supported* plugin, in which case that
247 * plugin will be instantiated regardless of the server provided type
248 * - The server returns a binary-stream type, and our type hint refers to
249 * a valid non-document type, we will use the type hint
250 *
251 * @param aNotify If we should send notifications. If false, content
252 * loading may be deferred while appropriate frames are
253 * created
254 * @param aForceLoad If we should reload this content (and re-attempt the
255 * channel open) even if our parameters did not change
256 */
257 nsresult LoadObject(bool aNotify,
258 bool aForceLoad = false);
260 enum Capabilities {
261 eSupportImages = 1u << 0, // Images are supported (imgILoader)
262 eSupportPlugins = 1u << 1, // Plugins are supported (nsIPluginHost)
263 eSupportDocuments = 1u << 2, // Documents are supported
264 // (nsIDocumentLoaderFactory)
265 // This flag always includes SVG
266 eSupportSVG = 1u << 3, // SVG is supported (image/svg+xml)
267 eSupportClassID = 1u << 4, // The classid attribute is supported
269 // If possible to get a *plugin* type from the type attribute *or* file
270 // extension, we can use that type and begin loading the plugin before
271 // opening a channel.
272 // A side effect of this is if the channel fails, the plugin is still
273 // running.
274 eAllowPluginSkipChannel = 1u << 5
275 };
277 /**
278 * Returns the list of capabilities this content node supports. This is a
279 * bitmask consisting of flags from the Capabilities enum.
280 *
281 * The default implementation supports all types but not
282 * eSupportClassID or eAllowPluginSkipChannel
283 */
284 virtual uint32_t GetCapabilities() const;
286 /**
287 * Destroys all loaded documents/plugins and releases references
288 */
289 void DestroyContent();
291 static void Traverse(nsObjectLoadingContent *tmp,
292 nsCycleCollectionTraversalCallback &cb);
294 void CreateStaticClone(nsObjectLoadingContent* aDest) const;
296 void DoStopPlugin(nsPluginInstanceOwner* aInstanceOwner, bool aDelayedStop,
297 bool aForcedReentry = false);
299 nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
300 nsIContent* aBindingParent,
301 bool aCompileEventHandler);
302 void UnbindFromTree(bool aDeep = true,
303 bool aNullParent = true);
305 private:
307 // Object parameter changes returned by UpdateObjectParameters
308 enum ParameterUpdateFlags {
309 eParamNoChange = 0,
310 // Parameters that potentially affect the channel changed
311 // - mOriginalURI, mOriginalContentType
312 eParamChannelChanged = 1u << 0,
313 // Parameters that affect displayed content changed
314 // - mURI, mContentType, mType, mBaseURI
315 eParamStateChanged = 1u << 1,
316 // The effective content type changed, independant of object type. This
317 // can happen when changing from Loading -> Final type, but doesn't
318 // necessarily happen when changing between object types. E.g., if a PDF
319 // handler was installed between the last load of this object and now, we
320 // might change from eType_Document -> eType_Plugin without changing
321 // ContentType
322 eParamContentTypeChanged = 1u << 2
323 };
325 /**
326 * Loads fallback content with the specified FallbackType
327 *
328 * @param aType FallbackType value for type of fallback we're loading
329 * @param aNotify Send notifications and events. If false, caller is
330 * responsible for doing so
331 */
332 void LoadFallback(FallbackType aType, bool aNotify);
334 /**
335 * Internal version of LoadObject that should only be used by this class
336 * aLoadingChannel is passed by the LoadObject call from OnStartRequest,
337 * primarily for sanity-preservation
338 */
339 nsresult LoadObject(bool aNotify,
340 bool aForceLoad,
341 nsIRequest *aLoadingChannel);
343 /**
344 * Introspects the object and sets the following member variables:
345 * - mOriginalContentType : This is the type attribute on the element
346 * - mOriginalURI : The src or data attribute on the element
347 * - mURI : The final URI, considering mChannel if
348 * mChannelLoaded is set
349 * - mContentType : The final content type, considering mChannel if
350 * mChannelLoaded is set
351 * - mBaseURI : The object's base URI, which may be set by the
352 * object (codebase attribute)
353 * - mType : The type the object is determined to be based
354 * on the above
355 *
356 * NOTE The class assumes that mType is the currently loaded type at various
357 * points, so the caller of this function must take the appropriate
358 * actions to ensure this
359 *
360 * NOTE This function does not perform security checks, only determining the
361 * requested type and parameters of the object.
362 *
363 * @param aJavaURI Specify that the URI will be consumed by java, which
364 * changes codebase parsing and URI construction. Used
365 * internally.
366 *
367 * @return Returns a bitmask of ParameterUpdateFlags values
368 */
369 ParameterUpdateFlags UpdateObjectParameters(bool aJavaURI = false);
371 /**
372 * Queue a CheckPluginStopEvent and track it in mPendingCheckPluginStopEvent
373 */
374 void QueueCheckPluginStopEvent();
376 void NotifyContentObjectWrapper();
378 /**
379 * Opens the channel pointed to by mURI into mChannel.
380 */
381 nsresult OpenChannel();
383 /**
384 * Closes and releases references to mChannel and, if opened, mFinalListener
385 */
386 nsresult CloseChannel();
388 /**
389 * If this object is allowed to play plugin content, or if it would display
390 * click-to-play instead.
391 * NOTE that this does not actually check if the object is a loadable plugin
392 * NOTE This ignores the current activated state. The caller should check this if appropriate.
393 */
394 bool ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentType);
396 /*
397 * Helper to check if mBaseURI can be used by java as a codebase
398 */
399 bool CheckJavaCodebase();
401 /**
402 * Helper to check if our current URI passes policy
403 *
404 * @param aContentPolicy [out] The result of the content policy decision
405 *
406 * @return true if call succeeded and NS_CP_ACCEPTED(*aContentPolicy)
407 */
408 bool CheckLoadPolicy(int16_t *aContentPolicy);
410 /**
411 * Helper to check if the object passes process policy. Assumes we have a
412 * final determined type.
413 *
414 * @param aContentPolicy [out] The result of the content policy decision
415 *
416 * @return true if call succeeded and NS_CP_ACCEPTED(*aContentPolicy)
417 */
418 bool CheckProcessPolicy(int16_t *aContentPolicy);
420 /**
421 * Checks whether the given type is a supported document type
422 *
423 * NOTE Does not take content policy or capabilities into account
424 */
425 bool IsSupportedDocument(const nsCString& aType);
427 /**
428 * Gets the plugin instance and creates a plugin stream listener, assigning
429 * it to mFinalListener
430 */
431 bool MakePluginListener();
433 /**
434 * Unloads all content and resets the object to a completely unloaded state
435 *
436 * NOTE Calls StopPluginInstance() and may spin the event loop
437 *
438 * @param aResetState Reset the object type to 'loading' and destroy channel
439 * as well
440 */
441 void UnloadObject(bool aResetState = true);
443 /**
444 * Notifies document observes about a new type/state of this object.
445 * Triggers frame construction as needed. mType must be set correctly when
446 * this method is called. This method is cheap if the type and state didn't
447 * actually change.
448 *
449 * @param aSync If a synchronous frame construction is required. If false,
450 * the construction may either be sync or async.
451 * @param aNotify if false, only need to update the state of our element.
452 */
453 void NotifyStateChanged(ObjectType aOldType,
454 mozilla::EventStates aOldState,
455 bool aSync, bool aNotify);
457 /**
458 * Returns a ObjectType value corresponding to the type of content we would
459 * support the given MIME type as, taking capabilities and plugin state
460 * into account
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);
467 /**
468 * Gets the frame that's associated with this content node.
469 * Does not flush.
470 */
471 nsObjectFrame* GetExistingFrame();
473 // Helper class for SetupProtoChain
474 class SetupProtoChainRunner MOZ_FINAL : public nsIRunnable
475 {
476 public:
477 NS_DECL_ISUPPORTS
479 SetupProtoChainRunner(nsIScriptContext* scriptContext,
480 nsObjectLoadingContent* aContent);
482 NS_IMETHOD Run() MOZ_OVERRIDE;
484 private:
485 nsCOMPtr<nsIScriptContext> mContext;
486 // We store an nsIObjectLoadingContent because we can
487 // unambiguously refcount that.
488 nsRefPtr<nsIObjectLoadingContent> mContent;
489 };
491 // Utility getter for getting our nsNPAPIPluginInstance in a safe way.
492 nsresult ScriptRequestPluginInstance(JSContext* aCx,
493 nsNPAPIPluginInstance** aResult);
495 // Utility method for getting our plugin JSObject
496 static nsresult GetPluginJSObject(JSContext *cx,
497 JS::Handle<JSObject*> obj,
498 nsNPAPIPluginInstance *plugin_inst,
499 JS::MutableHandle<JSObject*> plugin_obj,
500 JS::MutableHandle<JSObject*> plugin_proto);
502 // The final listener for mChannel (uriloader, pluginstreamlistener, etc.)
503 nsCOMPtr<nsIStreamListener> mFinalListener;
505 // Frame loader, for content documents we load.
506 nsRefPtr<nsFrameLoader> mFrameLoader;
508 // Track if we have a pending AsyncInstantiateEvent
509 nsCOMPtr<nsIRunnable> mPendingInstantiateEvent;
511 // Tracks if we have a pending CheckPluginStopEvent
512 nsCOMPtr<nsIRunnable> mPendingCheckPluginStopEvent;
514 // The content type of our current load target, updated by
515 // UpdateObjectParameters(). Takes the channel's type into account once
516 // opened.
517 //
518 // May change if a channel is opened, does not imply a loaded state
519 nsCString mContentType;
521 // The content type 'hint' provided by the element's type attribute. May
522 // or may not be used as a final type
523 nsCString mOriginalContentType;
525 // The channel that's currently being loaded. If set, but mChannelLoaded is
526 // false, has not yet reached OnStartRequest
527 nsCOMPtr<nsIChannel> mChannel;
529 // The URI of the current content.
530 // May change as we open channels and encounter redirects - does not imply
531 // a loaded type
532 nsCOMPtr<nsIURI> mURI;
534 // The original URI obtained from inspecting the element (codebase, and
535 // src/data). May differ from mURI due to redirects
536 nsCOMPtr<nsIURI> mOriginalURI;
538 // The baseURI used for constructing mURI, and used by some plugins (java)
539 // as a root for other resource requests.
540 nsCOMPtr<nsIURI> mBaseURI;
544 // Type of the currently-loaded content.
545 ObjectType mType : 8;
546 // The type of fallback content we're showing (see ObjectState())
547 FallbackType mFallbackType : 8;
549 // If true, we have opened a channel as the listener and it has reached
550 // OnStartRequest. Does not get set for channels that are passed directly to
551 // the plugin listener.
552 bool mChannelLoaded : 1;
554 // Whether we are about to call instantiate on our frame. If we aren't,
555 // SetFrame needs to asynchronously call Instantiate.
556 bool mInstantiating : 1;
558 // True when the object is created for an element which the parser has
559 // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
560 // it may lose the flag.
561 bool mNetworkCreated : 1;
563 // Used to keep track of whether or not a plugin has been explicitly
564 // activated by PlayPlugin(). (see ShouldPlay())
565 bool mActivated : 1;
567 // Used to keep track of whether or not a plugin is blocked by play-preview.
568 bool mPlayPreviewCanceled : 1;
570 // Protects DoStopPlugin from reentry (bug 724781).
571 bool mIsStopping : 1;
573 // Protects LoadObject from re-entry
574 bool mIsLoading : 1;
576 // For plugin stand-in types (click-to-play, play preview, ...) tracks
577 // whether content js has tried to access the plugin script object.
578 bool mScriptRequested : 1;
580 nsWeakFrame mPrintFrame;
582 nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
583 };
585 #endif