• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Collabora Ltd.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "config.h"
28 #include "PluginPackage.h"
29 
30 #include "CString.h"
31 #include "MIMETypeRegistry.h"
32 #include "PluginDatabase.h"
33 #include "PluginDebug.h"
34 #include "Timer.h"
35 #include "npruntime_impl.h"
36 #include <string.h>
37 #include <wtf/OwnArrayPtr.h>
38 
39 namespace WebCore {
40 
~PluginPackage()41 PluginPackage::~PluginPackage()
42 {
43     // This destructor gets called during refresh() if PluginDatabase's
44     // PluginSet hash is already populated, as it removes items from
45     // the hash table. Calling the destructor on a loaded plug-in of
46     // course would cause a crash, so we check to call unload before we
47     // ASSERT.
48     // FIXME: There is probably a better way to fix this.
49     if (m_loadCount == 0)
50         unloadWithoutShutdown();
51     else
52         unload();
53 
54     ASSERT(!m_isLoaded);
55 }
56 
freeLibrarySoon()57 void PluginPackage::freeLibrarySoon()
58 {
59     ASSERT(!m_freeLibraryTimer.isActive());
60     ASSERT(m_module);
61     ASSERT(m_loadCount == 0);
62 
63 #ifdef ANDROID_PLUGINS
64     // TODO(jripley): Timer<T> is broken. Unload immediately for now.
65     unloadModule(m_module);
66     m_module = 0;
67 #else
68     m_freeLibraryTimer.startOneShot(0);
69 #endif
70 }
71 
freeLibraryTimerFired(Timer<PluginPackage> *)72 void PluginPackage::freeLibraryTimerFired(Timer<PluginPackage>*)
73 {
74     ASSERT(m_module);
75     ASSERT(m_loadCount == 0);
76 
77     unloadModule(m_module);
78     m_module = 0;
79 }
80 
81 
compare(const PluginPackage & compareTo) const82 int PluginPackage::compare(const PluginPackage& compareTo) const
83 {
84     // Sort plug-ins that allow multiple instances first.
85     bool AallowsMultipleInstances = !quirks().contains(PluginQuirkDontAllowMultipleInstances);
86     bool BallowsMultipleInstances = !compareTo.quirks().contains(PluginQuirkDontAllowMultipleInstances);
87     if (AallowsMultipleInstances != BallowsMultipleInstances)
88         return AallowsMultipleInstances ? -1 : 1;
89 
90     // Sort plug-ins in a preferred path first.
91     bool AisInPreferredDirectory = PluginDatabase::isPreferredPluginDirectory(parentDirectory());
92     bool BisInPreferredDirectory = PluginDatabase::isPreferredPluginDirectory(compareTo.parentDirectory());
93     if (AisInPreferredDirectory != BisInPreferredDirectory)
94         return AisInPreferredDirectory ? -1 : 1;
95 
96     int diff = strcmp(name().utf8().data(), compareTo.name().utf8().data());
97     if (diff)
98         return diff;
99 
100     if (diff = compareFileVersion(compareTo.version()))
101         return diff;
102 
103     return strcmp(parentDirectory().utf8().data(), compareTo.parentDirectory().utf8().data());
104 }
105 
PluginPackage(const String & path,const time_t & lastModified)106 PluginPackage::PluginPackage(const String& path, const time_t& lastModified)
107     : m_isLoaded(false)
108     , m_loadCount(0)
109     , m_path(path)
110     , m_moduleVersion(0)
111     , m_module(0)
112     , m_lastModified(lastModified)
113     , m_freeLibraryTimer(this, &PluginPackage::freeLibraryTimerFired)
114 {
115     m_fileName = pathGetFileName(m_path);
116     m_parentDirectory = m_path.left(m_path.length() - m_fileName.length() - 1);
117 }
118 
unload()119 void PluginPackage::unload()
120 {
121     if (!m_isLoaded)
122         return;
123 
124     if (--m_loadCount > 0)
125         return;
126 
127     m_NPP_Shutdown();
128 
129     unloadWithoutShutdown();
130 }
131 
unloadWithoutShutdown()132 void PluginPackage::unloadWithoutShutdown()
133 {
134     if (!m_isLoaded)
135         return;
136 
137     ASSERT(m_loadCount == 0);
138     ASSERT(m_module);
139 
140 #if defined(ANDROID_PLUGINS)
141     // Remove the Java object from PluginList.
142     unregisterPluginObject();
143 #endif
144 
145     // <rdar://5530519>: Crash when closing tab with pdf file (Reader 7 only)
146     // If the plugin has subclassed its parent window, as with Reader 7, we may have
147     // gotten here by way of the plugin's internal window proc forwarding a message to our
148     // original window proc. If we free the plugin library from here, we will jump back
149     // to code we just freed when we return, so delay calling FreeLibrary at least until
150     // the next message loop
151     freeLibrarySoon();
152 
153     m_isLoaded = false;
154 }
155 
createPackage(const String & path,const time_t & lastModified)156 PassRefPtr<PluginPackage> PluginPackage::createPackage(const String& path, const time_t& lastModified)
157 {
158     RefPtr<PluginPackage> package = adoptRef(new PluginPackage(path, lastModified));
159 
160     if (!package->fetchInfo())
161         return 0;
162 
163     return package.release();
164 }
165 
166 #if defined(XP_UNIX)
determineQuirks(const String & mimeType)167 void PluginPackage::determineQuirks(const String& mimeType)
168 {
169     if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType)) {
170         // Because a single process cannot create multiple VMs, and we cannot reliably unload a
171         // Java VM, we cannot unload the Java plugin, or we'll lose reference to our only VM
172         m_quirks.add(PluginQuirkDontUnloadPlugin);
173 
174         // Setting the window region to an empty region causes bad scrolling repaint problems
175         // with the Java plug-in.
176         m_quirks.add(PluginQuirkDontClipToZeroRectWhenScrolling);
177         return;
178     }
179 
180     if (mimeType == "application/x-shockwave-flash") {
181         static const PlatformModuleVersion flashTenVersion(0x0a000000);
182 
183         if (compareFileVersion(flashTenVersion) >= 0) {
184             // Flash 10.0 b218 doesn't like having a NULL window handle
185             m_quirks.add(PluginQuirkDontSetNullWindowHandleOnDestroy);
186 #if PLATFORM(QT)
187             m_quirks.add(PluginQuirkRequiresGtkToolKit);
188 #endif
189         } else {
190             // Flash 9 and older requests windowless plugins if we return a mozilla user agent
191             m_quirks.add(PluginQuirkWantsMozillaUserAgent);
192         }
193 
194         m_quirks.add(PluginQuirkThrottleInvalidate);
195         m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages);
196         m_quirks.add(PluginQuirkFlashURLNotifyBug);
197     }
198 }
199 #endif
200 
201 #if !PLATFORM(WIN_OS)
determineModuleVersionFromDescription()202 void PluginPackage::determineModuleVersionFromDescription()
203 {
204     // It's a bit lame to detect the plugin version by parsing it
205     // from the plugin description string, but it doesn't seem that
206     // version information is available in any standardized way at
207     // the module level, like in Windows
208 
209     if (m_description.isEmpty())
210         return;
211 
212     if (m_description.startsWith("Shockwave Flash") && m_description.length() >= 19) {
213         // The flash version as a PlatformModuleVersion differs on Unix from Windows
214         // since the revision can be larger than a 8 bits, so we allow it 16 here and
215         // push the major/minor up 8 bits. Thus on Unix, Flash's version may be
216         // 0x0a000000 instead of 0x000a0000.
217 
218         Vector<String> versionParts;
219         m_description.substring(16).split(' ', /*allowEmptyEntries =*/ false, versionParts);
220         if (versionParts.isEmpty())
221             return;
222 
223         if (versionParts.size() >= 1) {
224             Vector<String> majorMinorParts;
225             versionParts[0].split('.', majorMinorParts);
226             if (majorMinorParts.size() >= 1) {
227                 bool converted = false;
228                 unsigned major = majorMinorParts[0].toUInt(&converted);
229                 if (converted)
230                     m_moduleVersion = (major & 0xff) << 24;
231             }
232             if (majorMinorParts.size() == 2) {
233                 bool converted = false;
234                 unsigned minor = majorMinorParts[1].toUInt(&converted);
235                 if (converted)
236                     m_moduleVersion |= (minor & 0xff) << 16;
237             }
238         }
239 
240         if (versionParts.size() >= 2) {
241             String revision = versionParts[1];
242             if (revision.length() > 1 && (revision[0] == 'r' || revision[0] == 'b')) {
243                 revision.remove(0, 1);
244                 m_moduleVersion |= revision.toInt() & 0xffff;
245             }
246         }
247     }
248 }
249 #endif
250 
251 }
252