webengine/osswebengine/WebKit/Plugins/WebPluginDatabase.m
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     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  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    14  *     its contributors may be used to endorse or promote products derived
       
    15  *     from this software without specific prior written permission. 
       
    16  *
       
    17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    27  */
       
    28 
       
    29 #import <WebKit/WebPluginDatabase.h>
       
    30 
       
    31 #import <JavaScriptCore/Assertions.h>
       
    32 #import <WebKit/WebBasePluginPackage.h>
       
    33 #import <WebKit/WebDataSourcePrivate.h>
       
    34 #import <WebKit/WebFrame.h>
       
    35 #import <WebKit/WebFrameViewInternal.h>
       
    36 #import <WebKit/WebHTMLRepresentation.h>
       
    37 #import <WebKit/WebHTMLView.h>
       
    38 #import <WebKit/WebKitLogging.h>
       
    39 #import <WebKit/WebNetscapePluginPackage.h>
       
    40 #import <WebKit/WebPluginPackage.h>
       
    41 #import <WebKit/WebViewPrivate.h>
       
    42 #import <WebKitSystemInterface.h>
       
    43 
       
    44 @interface WebPluginDatabase (Internal)
       
    45 + (NSArray *)_defaultPlugInPaths;
       
    46 - (NSArray *)_plugInPaths;
       
    47 - (void)_addPlugin:(WebBasePluginPackage *)plugin;
       
    48 - (void)_removePlugin:(WebBasePluginPackage *)plugin;
       
    49 - (NSMutableSet *)_scanForNewPlugins;
       
    50 @end
       
    51 
       
    52 @implementation WebPluginDatabase
       
    53 
       
    54 static WebPluginDatabase *sharedDatabase = nil;
       
    55 
       
    56 + (WebPluginDatabase *)sharedDatabase 
       
    57 {
       
    58     if (!sharedDatabase) {
       
    59         sharedDatabase = [[WebPluginDatabase alloc] init];
       
    60         [sharedDatabase setPlugInPaths:[self _defaultPlugInPaths]];
       
    61         [sharedDatabase refresh];
       
    62     }
       
    63     
       
    64     return sharedDatabase;
       
    65 }
       
    66 
       
    67 + (void)closeSharedDatabase 
       
    68 {
       
    69     [sharedDatabase close];
       
    70 }
       
    71 
       
    72 - (WebBasePluginPackage *)pluginForKey:(NSString *)key withEnumeratorSelector:(SEL)enumeratorSelector
       
    73 {
       
    74     WebBasePluginPackage *plugin = nil;
       
    75     WebBasePluginPackage *webPlugin = nil;
       
    76 #ifndef __LP64__
       
    77     WebBasePluginPackage *CFMPlugin = nil;
       
    78     WebBasePluginPackage *machoPlugin = nil;
       
    79 #endif
       
    80     NSEnumerator *pluginEnumerator = [plugins objectEnumerator];
       
    81     key = [key lowercaseString];
       
    82 
       
    83     while ((plugin = [pluginEnumerator nextObject]) != nil) {
       
    84         if ([[[plugin performSelector:enumeratorSelector] allObjects] containsObject:key]) {
       
    85             if ([plugin isKindOfClass:[WebPluginPackage class]]) {
       
    86                 if (!webPlugin)
       
    87                     webPlugin = plugin;
       
    88             } 
       
    89 #ifndef __LP64__
       
    90             else if([plugin isKindOfClass:[WebNetscapePluginPackage class]]) {
       
    91                 WebExecutableType executableType = [(WebNetscapePluginPackage *)plugin executableType];
       
    92                 if (executableType == WebCFMExecutableType) {
       
    93                     if (!CFMPlugin)
       
    94                         CFMPlugin = plugin;
       
    95                 } else if (executableType == WebMachOExecutableType) {
       
    96                     if (!machoPlugin)
       
    97                         machoPlugin = plugin;
       
    98                 } else {
       
    99                     ASSERT_NOT_REACHED();
       
   100                 }
       
   101             } else {
       
   102                 ASSERT_NOT_REACHED();
       
   103             }
       
   104 #endif
       
   105         }
       
   106     }
       
   107 
       
   108     // Allow other plug-ins to win over QT because if the user has installed a plug-in that can handle a type
       
   109     // that the QT plug-in can handle, they probably intended to override QT.
       
   110     if (webPlugin && ![webPlugin isQuickTimePlugIn])
       
   111         return webPlugin;
       
   112     
       
   113 #ifndef __LP64__
       
   114     else if (machoPlugin && ![machoPlugin isQuickTimePlugIn])
       
   115         return machoPlugin;
       
   116     else if (CFMPlugin && ![CFMPlugin isQuickTimePlugIn])
       
   117         return CFMPlugin;
       
   118 #endif
       
   119     else if (webPlugin)
       
   120         return webPlugin;
       
   121 #ifndef __LP64__
       
   122     else if (machoPlugin)
       
   123         return machoPlugin;
       
   124     else if (CFMPlugin)
       
   125         return CFMPlugin;
       
   126 #endif
       
   127     return nil;
       
   128 }
       
   129 
       
   130 - (WebBasePluginPackage *)pluginForMIMEType:(NSString *)MIMEType
       
   131 {
       
   132     return [self pluginForKey:[MIMEType lowercaseString]
       
   133        withEnumeratorSelector:@selector(MIMETypeEnumerator)];
       
   134 }
       
   135 
       
   136 - (WebBasePluginPackage *)pluginForExtension:(NSString *)extension
       
   137 {
       
   138     WebBasePluginPackage *plugin = [self pluginForKey:[extension lowercaseString]
       
   139                                withEnumeratorSelector:@selector(extensionEnumerator)];
       
   140     if (!plugin) {
       
   141         // If no plug-in was found from the extension, attempt to map from the extension to a MIME type
       
   142         // and find the a plug-in from the MIME type. This is done in case the plug-in has not fully specified
       
   143         // an extension <-> MIME type mapping.
       
   144         NSString *MIMEType = WKGetMIMETypeForExtension(extension);
       
   145         if ([MIMEType length] > 0)
       
   146             plugin = [self pluginForMIMEType:MIMEType];
       
   147     }
       
   148     return plugin;
       
   149 }
       
   150 
       
   151 - (NSArray *)plugins
       
   152 {
       
   153     return [plugins allValues];
       
   154 }
       
   155 
       
   156 static NSArray *additionalWebPlugInPaths;
       
   157 
       
   158 + (void)setAdditionalWebPlugInPaths:(NSArray *)additionalPaths
       
   159 {
       
   160     if (additionalPaths == additionalWebPlugInPaths)
       
   161         return;
       
   162     
       
   163     [additionalWebPlugInPaths release];
       
   164     additionalWebPlugInPaths = [additionalPaths copy];
       
   165 
       
   166     // One might be tempted to add additionalWebPlugInPaths to the global WebPluginDatabase here.
       
   167     // For backward compatibility with earlier versions of the +setAdditionalWebPlugInPaths: SPI,
       
   168     // we need to save a copy of the additional paths and not cause a refresh of the plugin DB
       
   169     // at this time.
       
   170     // See Radars 4608487 and 4609047.
       
   171 }
       
   172 
       
   173 - (void)setPlugInPaths:(NSArray *)newPaths
       
   174 {
       
   175     if (plugInPaths == newPaths)
       
   176         return;
       
   177         
       
   178     [plugInPaths release];
       
   179     plugInPaths = [newPaths copy];
       
   180 }
       
   181 
       
   182 - (void)close
       
   183 {
       
   184     NSEnumerator *pluginEnumerator = [[self plugins] objectEnumerator];
       
   185     WebBasePluginPackage *plugin;
       
   186     while ((plugin = [pluginEnumerator nextObject]) != nil)
       
   187         [self _removePlugin:plugin];
       
   188     [plugins release];
       
   189     plugins = nil;
       
   190 }
       
   191 
       
   192 - (id)init
       
   193 {
       
   194     if (!(self = [super init]))
       
   195         return nil;
       
   196         
       
   197     registeredMIMETypes = [[NSMutableSet alloc] init];
       
   198     
       
   199     return self;
       
   200 }
       
   201 
       
   202 - (void)dealloc
       
   203 {
       
   204     [plugInPaths release];
       
   205     [plugins release];
       
   206     [registeredMIMETypes release];
       
   207     
       
   208     [super dealloc];
       
   209 }
       
   210 
       
   211 - (void)refresh
       
   212 {
       
   213     // This method does a bit of autoreleasing, so create an autorelease pool to ensure that calling
       
   214     // -refresh multiple times does not bloat the default pool.
       
   215     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
       
   216     
       
   217     // Create map from plug-in path to WebBasePluginPackage
       
   218     if (!plugins)
       
   219         plugins = [[NSMutableDictionary alloc] initWithCapacity:12];
       
   220 
       
   221     // Find all plug-ins on disk
       
   222     NSMutableSet *newPlugins = [self _scanForNewPlugins];
       
   223 
       
   224     // Find plug-ins to remove from database (i.e., plug-ins that no longer exist on disk)
       
   225     NSMutableSet *pluginsToRemove = [NSMutableSet set];
       
   226     NSEnumerator *pluginEnumerator = [plugins objectEnumerator];
       
   227     WebBasePluginPackage *plugin;
       
   228     while ((plugin = [pluginEnumerator nextObject]) != nil) {
       
   229         // Any plug-ins that were removed from disk since the last refresh should be removed from
       
   230         // the database.
       
   231         if (![newPlugins containsObject:plugin])
       
   232             [pluginsToRemove addObject:plugin];
       
   233             
       
   234         // Remove every member of 'plugins' from 'newPlugins'.  After this loop exits, 'newPlugins'
       
   235         // will be the set of new plug-ins that should be added to the database.
       
   236         [newPlugins removeObject:plugin];
       
   237     }
       
   238 
       
   239 #if !LOG_DISABLED
       
   240     if ([newPlugins count] > 0)
       
   241         LOG(Plugins, "New plugins:\n%@", newPlugins);
       
   242     if ([pluginsToRemove count] > 0)
       
   243         LOG(Plugins, "Removed plugins:\n%@", pluginsToRemove);
       
   244 #endif
       
   245 
       
   246     // Remove plugins from database
       
   247     pluginEnumerator = [pluginsToRemove objectEnumerator];
       
   248     while ((plugin = [pluginEnumerator nextObject]) != nil) 
       
   249         [self _removePlugin:plugin];
       
   250     
       
   251     // Add new plugins to database
       
   252     pluginEnumerator = [newPlugins objectEnumerator];
       
   253     while ((plugin = [pluginEnumerator nextObject]) != nil)
       
   254         [self _addPlugin:plugin];
       
   255 
       
   256     // Build a list of MIME types.
       
   257     NSMutableSet *MIMETypes = [[NSMutableSet alloc] init];
       
   258     pluginEnumerator = [plugins objectEnumerator];
       
   259     while ((plugin = [pluginEnumerator nextObject]) != nil)
       
   260         [MIMETypes addObjectsFromArray:[[plugin MIMETypeEnumerator] allObjects]];
       
   261     
       
   262     // Register plug-in views and representations.
       
   263     NSEnumerator *MIMEEnumerator = [MIMETypes objectEnumerator];
       
   264     NSString *MIMEType;
       
   265     while ((MIMEType = [MIMEEnumerator nextObject]) != nil) {
       
   266         [registeredMIMETypes addObject:MIMEType];
       
   267 
       
   268         if ([WebView canShowMIMETypeAsHTML:MIMEType])
       
   269             // Don't allow plug-ins to override our core HTML types.
       
   270             continue;
       
   271         plugin = [self pluginForMIMEType:MIMEType];
       
   272         if ([plugin isJavaPlugIn])
       
   273             // Don't register the Java plug-in for a document view since Java files should be downloaded when not embedded.
       
   274             continue;
       
   275         if ([plugin isQuickTimePlugIn] && [[WebFrameView _viewTypesAllowImageTypeOmission:NO] objectForKey:MIMEType])
       
   276             // Don't allow the QT plug-in to override any types because it claims many that we can handle ourselves.
       
   277             continue;
       
   278         
       
   279         if (self == sharedDatabase)
       
   280             [WebView registerViewClass:[WebHTMLView class] representationClass:[WebHTMLRepresentation class] forMIMEType:MIMEType];
       
   281     }
       
   282     [MIMETypes release];
       
   283     
       
   284     [pool drain];
       
   285 }
       
   286 
       
   287 - (BOOL)isMIMETypeRegistered:(NSString *)MIMEType
       
   288 {
       
   289     return [registeredMIMETypes containsObject:MIMEType];
       
   290 }
       
   291 
       
   292 @end
       
   293 
       
   294 @implementation WebPluginDatabase (Internal)
       
   295 
       
   296 + (NSArray *)_defaultPlugInPaths
       
   297 {
       
   298     // Plug-ins are found in order of precedence.
       
   299     // If there are duplicates, the first found plug-in is used.
       
   300     // For example, if there is a QuickTime.plugin in the users's home directory
       
   301     // that is used instead of the /Library/Internet Plug-ins version.
       
   302     // The purpose is to allow non-admin users to update their plug-ins.
       
   303     return [NSArray arrayWithObjects:
       
   304         [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Internet Plug-Ins"],
       
   305         @"/Library/Internet Plug-Ins",
       
   306         [[NSBundle mainBundle] builtInPlugInsPath],
       
   307         nil];
       
   308 }
       
   309 
       
   310 - (NSArray *)_plugInPaths
       
   311 {
       
   312     if (self == sharedDatabase && additionalWebPlugInPaths) {
       
   313         // Add additionalWebPlugInPaths to the global WebPluginDatabase.  We do this here for
       
   314         // backward compatibility with earlier versions of the +setAdditionalWebPlugInPaths: SPI,
       
   315         // which simply saved a copy of the additional paths and did not cause the plugin DB to 
       
   316         // refresh.  See Radars 4608487 and 4609047.
       
   317         NSMutableArray *modifiedPlugInPaths = [[plugInPaths mutableCopy] autorelease];
       
   318         [modifiedPlugInPaths addObjectsFromArray:additionalWebPlugInPaths];
       
   319         return modifiedPlugInPaths;
       
   320     } else
       
   321         return plugInPaths;
       
   322 }
       
   323 
       
   324 - (void)_addPlugin:(WebBasePluginPackage *)plugin
       
   325 {
       
   326     ASSERT(plugin);
       
   327     NSString *pluginPath = [plugin path];
       
   328     ASSERT(pluginPath);
       
   329     [plugins setObject:plugin forKey:pluginPath];
       
   330     [plugin wasAddedToPluginDatabase:self];
       
   331 }
       
   332 
       
   333 - (void)_removePlugin:(WebBasePluginPackage *)plugin
       
   334 {    
       
   335     ASSERT(plugin);
       
   336 
       
   337     // Unregister plug-in's MIME type registrations
       
   338     NSEnumerator *MIMETypeEnumerator = [plugin MIMETypeEnumerator];
       
   339     NSString *MIMEType;
       
   340     while ((MIMEType = [MIMETypeEnumerator nextObject])) {
       
   341         if ([registeredMIMETypes containsObject:MIMEType]) {
       
   342             if (self == sharedDatabase)
       
   343                 [WebView _unregisterViewClassAndRepresentationClassForMIMEType:MIMEType];
       
   344             [registeredMIMETypes removeObject:MIMEType];
       
   345         }
       
   346     }
       
   347 
       
   348     // Remove plug-in from database
       
   349     NSString *pluginPath = [plugin path];
       
   350     ASSERT(pluginPath);
       
   351     [plugin retain];
       
   352     [plugins removeObjectForKey:pluginPath];
       
   353     [plugin wasRemovedFromPluginDatabase:self];
       
   354     [plugin release];
       
   355 }
       
   356 
       
   357 - (NSMutableSet *)_scanForNewPlugins
       
   358 {
       
   359     NSMutableSet *newPlugins = [NSMutableSet set];
       
   360     NSEnumerator *directoryEnumerator = [[self _plugInPaths] objectEnumerator];
       
   361     NSMutableSet *uniqueFilenames = [[NSMutableSet alloc] init];
       
   362     NSFileManager *fileManager = [NSFileManager defaultManager];
       
   363     NSString *pluginDirectory;
       
   364     while ((pluginDirectory = [directoryEnumerator nextObject]) != nil) {
       
   365         // Get contents of each plug-in directory
       
   366         NSEnumerator *filenameEnumerator = [[fileManager directoryContentsAtPath:pluginDirectory] objectEnumerator];
       
   367         NSString *filename;
       
   368         while ((filename = [filenameEnumerator nextObject]) != nil) {
       
   369             // Unique plug-ins by filename
       
   370             if ([uniqueFilenames containsObject:filename])
       
   371                 continue;
       
   372             [uniqueFilenames addObject:filename];
       
   373             
       
   374             // Create a plug-in package for this path
       
   375             NSString *pluginPath = [pluginDirectory stringByAppendingPathComponent:filename];
       
   376             WebBasePluginPackage *pluginPackage = [plugins objectForKey:pluginPath];
       
   377             if (!pluginPackage)
       
   378                 pluginPackage = [WebBasePluginPackage pluginWithPath:pluginPath];
       
   379             if (pluginPackage)
       
   380                 [newPlugins addObject:pluginPackage];
       
   381         }
       
   382     }
       
   383     [uniqueFilenames release];
       
   384     
       
   385     return newPlugins;
       
   386 }
       
   387 
       
   388 @end