LCOV - code coverage report
Current view: directory - extensions/gnomevfs - nsGnomeVFSProtocolHandler.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 337 33 9.8 %
Date: 2012-06-02 Functions: 42 10 23.8 %

       1                 : /* vim:set ts=2 sw=2 et cindent: */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is the Mozilla gnome-vfs extension.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is IBM Corporation.
      18                 :  * Portions created by IBM Corporation are Copyright (C) 2004
      19                 :  * IBM Corporation. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Darin Fisher <darin@meer.net>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : // GnomeVFS v2.2.2 is missing G_BEGIN_DECLS in gnome-vfs-module-callback.h
      39                 : extern "C" {
      40                 : #include <libgnomevfs/gnome-vfs.h>
      41                 : #include <libgnomevfs/gnome-vfs-standard-callbacks.h>
      42                 : #include <libgnomevfs/gnome-vfs-mime-utils.h>
      43                 : }
      44                 : 
      45                 : #include "nsServiceManagerUtils.h"
      46                 : #include "nsComponentManagerUtils.h"
      47                 : #include "mozilla/ModuleUtils.h"
      48                 : #include "nsIInterfaceRequestorUtils.h"
      49                 : #include "nsIPrefService.h"
      50                 : #include "nsIPrefBranch.h"
      51                 : #include "nsIObserver.h"
      52                 : #include "nsThreadUtils.h"
      53                 : #include "nsProxyRelease.h"
      54                 : #include "nsIAuthPrompt.h"
      55                 : #include "nsIStringBundle.h"
      56                 : #include "nsIStandardURL.h"
      57                 : #include "nsIURL.h"
      58                 : #include "nsMimeTypes.h"
      59                 : #include "nsNetUtil.h"
      60                 : #include "nsINetUtil.h"
      61                 : #include "nsAutoPtr.h"
      62                 : #include "nsError.h"
      63                 : #include "prlog.h"
      64                 : #include "prtime.h"
      65                 : #include "prprf.h"
      66                 : #include "plstr.h"
      67                 : 
      68                 : #define MOZ_GNOMEVFS_SCHEME              "moz-gnomevfs"
      69                 : #define MOZ_GNOMEVFS_SUPPORTED_PROTOCOLS "network.gnomevfs.supported-protocols"
      70                 : 
      71                 : //-----------------------------------------------------------------------------
      72                 : 
      73                 : // NSPR_LOG_MODULES=gnomevfs:5
      74                 : #ifdef PR_LOGGING
      75                 : static PRLogModuleInfo *sGnomeVFSLog;
      76                 : #define LOG(args) PR_LOG(sGnomeVFSLog, PR_LOG_DEBUG, args)
      77                 : #else
      78                 : #define LOG(args)
      79                 : #endif
      80                 : 
      81                 : //-----------------------------------------------------------------------------
      82                 : 
      83                 : static nsresult
      84               0 : MapGnomeVFSResult(GnomeVFSResult result)
      85                 : {
      86               0 :   switch (result)
      87                 :   {
      88               0 :     case GNOME_VFS_OK:                           return NS_OK;
      89               0 :     case GNOME_VFS_ERROR_NOT_FOUND:              return NS_ERROR_FILE_NOT_FOUND;
      90               0 :     case GNOME_VFS_ERROR_INTERNAL:               return NS_ERROR_UNEXPECTED;
      91               0 :     case GNOME_VFS_ERROR_BAD_PARAMETERS:         return NS_ERROR_INVALID_ARG;
      92               0 :     case GNOME_VFS_ERROR_NOT_SUPPORTED:          return NS_ERROR_NOT_AVAILABLE;
      93               0 :     case GNOME_VFS_ERROR_CORRUPTED_DATA:         return NS_ERROR_FILE_CORRUPTED;
      94               0 :     case GNOME_VFS_ERROR_TOO_BIG:                return NS_ERROR_FILE_TOO_BIG;
      95               0 :     case GNOME_VFS_ERROR_NO_SPACE:               return NS_ERROR_FILE_NO_DEVICE_SPACE;
      96                 :     case GNOME_VFS_ERROR_READ_ONLY:
      97               0 :     case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM:  return NS_ERROR_FILE_READ_ONLY;
      98                 :     case GNOME_VFS_ERROR_INVALID_URI:
      99               0 :     case GNOME_VFS_ERROR_INVALID_HOST_NAME:      return NS_ERROR_MALFORMED_URI;
     100                 :     case GNOME_VFS_ERROR_ACCESS_DENIED:
     101                 :     case GNOME_VFS_ERROR_NOT_PERMITTED:
     102               0 :     case GNOME_VFS_ERROR_LOGIN_FAILED:           return NS_ERROR_FILE_ACCESS_DENIED;
     103               0 :     case GNOME_VFS_ERROR_EOF:                    return NS_BASE_STREAM_CLOSED;
     104               0 :     case GNOME_VFS_ERROR_NOT_A_DIRECTORY:        return NS_ERROR_FILE_NOT_DIRECTORY;
     105               0 :     case GNOME_VFS_ERROR_IN_PROGRESS:            return NS_ERROR_IN_PROGRESS;
     106               0 :     case GNOME_VFS_ERROR_FILE_EXISTS:            return NS_ERROR_FILE_ALREADY_EXISTS;
     107               0 :     case GNOME_VFS_ERROR_IS_DIRECTORY:           return NS_ERROR_FILE_IS_DIRECTORY;
     108               0 :     case GNOME_VFS_ERROR_NO_MEMORY:              return NS_ERROR_OUT_OF_MEMORY;
     109                 :     case GNOME_VFS_ERROR_HOST_NOT_FOUND:
     110               0 :     case GNOME_VFS_ERROR_HOST_HAS_NO_ADDRESS:    return NS_ERROR_UNKNOWN_HOST;
     111                 :     case GNOME_VFS_ERROR_CANCELLED:
     112               0 :     case GNOME_VFS_ERROR_INTERRUPTED:            return NS_ERROR_ABORT;
     113               0 :     case GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY:    return NS_ERROR_FILE_DIR_NOT_EMPTY;
     114               0 :     case GNOME_VFS_ERROR_NAME_TOO_LONG:          return NS_ERROR_FILE_NAME_TOO_LONG;
     115               0 :     case GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE:  return NS_ERROR_UNKNOWN_PROTOCOL;
     116                 : 
     117                 :     /* No special mapping for these error codes...
     118                 : 
     119                 :     case GNOME_VFS_ERROR_GENERIC:
     120                 :     case GNOME_VFS_ERROR_IO:
     121                 :     case GNOME_VFS_ERROR_WRONG_FORMAT:
     122                 :     case GNOME_VFS_ERROR_BAD_FILE:
     123                 :     case GNOME_VFS_ERROR_NOT_OPEN:
     124                 :     case GNOME_VFS_ERROR_INVALID_OPEN_MODE:
     125                 :     case GNOME_VFS_ERROR_TOO_MANY_OPEN_FILES:
     126                 :     case GNOME_VFS_ERROR_LOOP:
     127                 :     case GNOME_VFS_ERROR_DIRECTORY_BUSY:
     128                 :     case GNOME_VFS_ERROR_TOO_MANY_LINKS:
     129                 :     case GNOME_VFS_ERROR_NOT_SAME_FILE_SYSTEM:
     130                 :     case GNOME_VFS_ERROR_SERVICE_OBSOLETE:
     131                 :     case GNOME_VFS_ERROR_PROTOCOL_ERROR:
     132                 :     case GNOME_VFS_ERROR_NO_MASTER_BROWSER:
     133                 : 
     134                 :     */
     135                 : 
     136                 :     // Make GCC happy
     137                 :     default:
     138               0 :       return NS_ERROR_FAILURE;
     139                 :   }
     140                 : 
     141                 :   return NS_ERROR_FAILURE;
     142                 : }
     143                 : 
     144                 : //-----------------------------------------------------------------------------
     145                 : 
     146                 : static void
     147               0 : ProxiedAuthCallback(gconstpointer in,
     148                 :                     gsize         in_size,
     149                 :                     gpointer      out,
     150                 :                     gsize         out_size,
     151                 :                     gpointer      callback_data)
     152                 : {
     153                 :   GnomeVFSModuleCallbackAuthenticationIn *authIn =
     154               0 :       (GnomeVFSModuleCallbackAuthenticationIn *) in;
     155                 :   GnomeVFSModuleCallbackAuthenticationOut *authOut =
     156               0 :       (GnomeVFSModuleCallbackAuthenticationOut *) out;
     157                 : 
     158               0 :   LOG(("gnomevfs: ProxiedAuthCallback [uri=%s]\n", authIn->uri));
     159                 : 
     160                 :   // Without a channel, we have no way of getting a prompter.
     161               0 :   nsIChannel *channel = (nsIChannel *) callback_data;
     162               0 :   if (!channel)
     163               0 :     return;
     164                 : 
     165               0 :   nsCOMPtr<nsIAuthPrompt> prompt;
     166               0 :   NS_QueryNotificationCallbacks(channel, prompt);
     167                 : 
     168                 :   // If no auth prompt, then give up.  We could failover to using the
     169                 :   // WindowWatcher service, but that might defeat a consumer's purposeful
     170                 :   // attempt to disable authentication (for whatever reason).
     171               0 :   if (!prompt)
     172                 :     return;
     173                 : 
     174                 :   // Parse out the host and port...
     175               0 :   nsCOMPtr<nsIURI> uri;
     176               0 :   channel->GetURI(getter_AddRefs(uri));
     177               0 :   if (!uri)
     178                 :     return;
     179                 : 
     180                 : #ifdef DEBUG
     181                 :   {
     182                 :     //
     183                 :     // Make sure authIn->uri is consistent with the channel's URI.
     184                 :     //
     185                 :     // XXX This check is probably not IDN safe, and it might incorrectly
     186                 :     //     fire as a result of escaping differences.  It's unclear what
     187                 :     //     kind of transforms GnomeVFS might have applied to the URI spec
     188                 :     //     that we originally gave to it.  In spite of the likelihood of
     189                 :     //     false hits, this check is probably still valuable.
     190                 :     //
     191               0 :     nsCAutoString spec;
     192               0 :     uri->GetSpec(spec);
     193               0 :     int uriLen = strlen(authIn->uri);
     194               0 :     if (!StringHead(spec, uriLen).Equals(nsDependentCString(authIn->uri, uriLen)))
     195                 :     {
     196               0 :       LOG(("gnomevfs: [spec=%s authIn->uri=%s]\n", spec.get(), authIn->uri));
     197               0 :       NS_ERROR("URI mismatch");
     198                 :     }
     199                 :   }
     200                 : #endif
     201                 : 
     202               0 :   nsCAutoString scheme, hostPort;
     203               0 :   uri->GetScheme(scheme);
     204               0 :   uri->GetHostPort(hostPort);
     205                 : 
     206                 :   // It doesn't make sense for either of these strings to be empty.  What kind
     207                 :   // of funky URI is this?
     208               0 :   if (scheme.IsEmpty() || hostPort.IsEmpty())
     209                 :     return;
     210                 : 
     211                 :   // Construct the single signon key.  Altering the value of this key will
     212                 :   // cause people's remembered passwords to be forgotten.  Think carefully
     213                 :   // before changing the way this key is constructed.
     214               0 :   nsAutoString key, realm;
     215                 : 
     216               0 :   NS_ConvertUTF8toUTF16 dispHost(scheme);
     217               0 :   dispHost.Append(NS_LITERAL_STRING("://"));
     218               0 :   dispHost.Append(NS_ConvertUTF8toUTF16(hostPort));
     219                 : 
     220               0 :   key = dispHost;
     221               0 :   if (authIn->realm)
     222                 :   {
     223                 :     // We assume the realm string is ASCII.  That might be a bogus assumption,
     224                 :     // but we have no idea what encoding GnomeVFS is using, so for now we'll
     225                 :     // limit ourselves to ISO-Latin-1.  XXX What is a better solution?
     226               0 :     realm.Append('"');
     227               0 :     realm.Append(NS_ConvertASCIItoUTF16(authIn->realm));
     228               0 :     realm.Append('"');
     229               0 :     key.Append(' ');
     230               0 :     key.Append(realm);
     231                 :   }
     232                 : 
     233                 :   // Construct the message string...
     234                 :   //
     235                 :   // We use Necko's string bundle here.  This code really should be encapsulated
     236                 :   // behind some Necko API, after all this code is based closely on the code in
     237                 :   // nsHttpChannel.cpp.
     238                 : 
     239                 :   nsCOMPtr<nsIStringBundleService> bundleSvc =
     240               0 :       do_GetService(NS_STRINGBUNDLE_CONTRACTID);
     241               0 :   if (!bundleSvc)
     242                 :     return;
     243                 : 
     244               0 :   nsCOMPtr<nsIStringBundle> bundle;
     245               0 :   bundleSvc->CreateBundle("chrome://global/locale/commonDialogs.properties",
     246               0 :                           getter_AddRefs(bundle));
     247               0 :   if (!bundle)
     248                 :     return;
     249                 : 
     250               0 :   nsString message;
     251               0 :   if (!realm.IsEmpty())
     252                 :   {
     253               0 :     const PRUnichar *strings[] = { realm.get(), dispHost.get() };
     254               0 :     bundle->FormatStringFromName(NS_LITERAL_STRING("EnterUserPasswordForRealm").get(),
     255               0 :                                  strings, 2, getter_Copies(message));
     256                 :   }
     257                 :   else
     258                 :   {
     259               0 :     const PRUnichar *strings[] = { dispHost.get() };
     260               0 :     bundle->FormatStringFromName(NS_LITERAL_STRING("EnterUserPasswordFor").get(),
     261               0 :                                  strings, 1, getter_Copies(message));
     262                 :   }
     263               0 :   if (message.IsEmpty())
     264                 :     return;
     265                 : 
     266                 :   // Prompt the user...
     267                 :   nsresult rv;
     268               0 :   bool retval = false;
     269               0 :   PRUnichar *user = nsnull, *pass = nsnull;
     270                 : 
     271               0 :   rv = prompt->PromptUsernameAndPassword(nsnull, message.get(),
     272                 :                                          key.get(),
     273                 :                                          nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY,
     274               0 :                                          &user, &pass, &retval);
     275               0 :   if (NS_FAILED(rv))
     276                 :     return;
     277               0 :   if (!retval || !user || !pass)
     278                 :     return;
     279                 : 
     280                 :   // XXX We need to convert the UTF-16 username and password from our dialog to
     281                 :   // strings that GnomeVFS can understand.  It's unclear what encoding GnomeVFS
     282                 :   // expects, so for now we assume 7-bit ASCII.  Hopefully, we can get a better
     283                 :   // solution at some point.
     284                 : 
     285                 :   // One copy is never enough...
     286               0 :   authOut->username = g_strdup(NS_LossyConvertUTF16toASCII(user).get());
     287               0 :   authOut->password = g_strdup(NS_LossyConvertUTF16toASCII(pass).get());
     288                 : 
     289               0 :   nsMemory::Free(user);
     290               0 :   nsMemory::Free(pass);
     291                 : }
     292                 : 
     293                 : struct nsGnomeVFSAuthCallbackEvent : public nsRunnable
     294               0 : {
     295                 :   gconstpointer in;
     296                 :   gsize         in_size;
     297                 :   gpointer      out;
     298                 :   gsize         out_size;
     299                 :   gpointer      callback_data;
     300                 : 
     301               0 :   NS_IMETHOD Run() {
     302               0 :     ProxiedAuthCallback(in, in_size, out, out_size, callback_data);
     303               0 :     return NS_OK;
     304                 :   }
     305                 : };
     306                 : 
     307                 : static void
     308               0 : AuthCallback(gconstpointer in,
     309                 :              gsize         in_size,
     310                 :              gpointer      out,
     311                 :              gsize         out_size,
     312                 :              gpointer      callback_data)
     313                 : {
     314                 :   // Need to proxy this callback over to the main thread.  Synchronous dispatch
     315                 :   // is required in order to provide data to the GnomeVFS callback.
     316                 : 
     317               0 :   nsRefPtr<nsGnomeVFSAuthCallbackEvent> ev = new nsGnomeVFSAuthCallbackEvent();
     318               0 :   if (!ev)
     319                 :     return;  // OOM
     320                 : 
     321               0 :   ev->in = in;
     322               0 :   ev->in_size = in_size;
     323               0 :   ev->out = out;
     324               0 :   ev->out_size = out_size;
     325               0 :   ev->callback_data = callback_data;
     326                 : 
     327               0 :   NS_DispatchToMainThread(ev, NS_DISPATCH_SYNC);
     328                 : }
     329                 : 
     330                 : //-----------------------------------------------------------------------------
     331                 : 
     332                 : static gint
     333               0 : FileInfoComparator(gconstpointer a, gconstpointer b)
     334                 : {
     335               0 :   const GnomeVFSFileInfo *ia = (const GnomeVFSFileInfo *) a;
     336               0 :   const GnomeVFSFileInfo *ib = (const GnomeVFSFileInfo *) b;
     337                 : 
     338               0 :   return strcasecmp(ia->name, ib->name);
     339                 : }
     340                 : 
     341                 : //-----------------------------------------------------------------------------
     342                 : 
     343                 : class nsGnomeVFSInputStream : public nsIInputStream
     344                 : {
     345                 :   public:
     346                 :     NS_DECL_ISUPPORTS
     347                 :     NS_DECL_NSIINPUTSTREAM
     348                 : 
     349               0 :     nsGnomeVFSInputStream(const nsCString &uriSpec)
     350                 :       : mSpec(uriSpec)
     351                 :       , mChannel(nsnull)
     352                 :       , mHandle(nsnull)
     353                 :       , mBytesRemaining(PR_UINT32_MAX)
     354                 :       , mStatus(NS_OK)
     355                 :       , mDirList(nsnull)
     356                 :       , mDirListPtr(nsnull)
     357                 :       , mDirBufCursor(0)
     358               0 :       , mDirOpen(false) {}
     359                 : 
     360               0 :    ~nsGnomeVFSInputStream() { Close(); }
     361                 : 
     362               0 :     void SetChannel(nsIChannel *channel)
     363                 :     {
     364                 :       // We need to hold an owning reference to our channel.  This is done
     365                 :       // so we can access the channel's notification callbacks to acquire
     366                 :       // a reference to a nsIAuthPrompt if we need to handle a GnomeVFS
     367                 :       // authentication callback.
     368                 :       //
     369                 :       // However, the channel can only be accessed on the main thread, so
     370                 :       // we have to be very careful with ownership.  Moreover, it doesn't
     371                 :       // support threadsafe addref/release, so proxying is the answer.
     372                 :       //
     373                 :       // Also, it's important to note that this likely creates a reference
     374                 :       // cycle since the channel likely owns this stream.  This reference
     375                 :       // cycle is broken in our Close method.
     376                 : 
     377               0 :       NS_ADDREF(mChannel = channel);
     378               0 :     }
     379                 : 
     380                 :   private:
     381                 :     GnomeVFSResult DoOpen();
     382                 :     GnomeVFSResult DoRead(char *aBuf, PRUint32 aCount, PRUint32 *aCountRead);
     383                 :     nsresult       SetContentTypeOfChannel(const char *contentType);
     384                 : 
     385                 :   private:
     386                 :     nsCString                mSpec;
     387                 :     nsIChannel              *mChannel; // manually refcounted
     388                 :     GnomeVFSHandle          *mHandle;
     389                 :     PRUint32                 mBytesRemaining;
     390                 :     nsresult                 mStatus;
     391                 :     GList                   *mDirList;
     392                 :     GList                   *mDirListPtr;
     393                 :     nsCString                mDirBuf;
     394                 :     PRUint32                 mDirBufCursor;
     395                 :     bool                     mDirOpen;
     396                 : };
     397                 : 
     398                 : GnomeVFSResult
     399               0 : nsGnomeVFSInputStream::DoOpen()
     400                 : {
     401                 :   GnomeVFSResult rv;
     402                 : 
     403               0 :   NS_ASSERTION(mHandle == nsnull, "already open");
     404                 : 
     405                 :   // Push a callback handler on the stack for this thread, so we can intercept
     406                 :   // authentication requests from GnomeVFS.  We'll use the channel to get a
     407                 :   // nsIAuthPrompt instance.
     408                 : 
     409                 :   gnome_vfs_module_callback_push(GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION,
     410               0 :                                  AuthCallback, mChannel, NULL);
     411                 : 
     412                 :   // Query the mime type first (this could return NULL). 
     413                 :   //
     414                 :   // XXX We need to do this up-front in order to determine how to open the URI.
     415                 :   //     Unfortunately, the error code GNOME_VFS_ERROR_IS_DIRECTORY is not
     416                 :   //     always returned by gnome_vfs_open when we pass it a URI to a directory!
     417                 :   //     Otherwise, we could have used that as a way to failover to opening the
     418                 :   //     URI as a directory.  Also, it would have been ideal if
     419                 :   //     gnome_vfs_get_file_info_from_handle were actually implemented by the
     420                 :   //     smb:// module, since that would have allowed us to potentially save a
     421                 :   //     round trip to the server to discover the mime type of the document in
     422                 :   //     the case where gnome_vfs_open would have been used.  (Oh well!  /me
     423                 :   //     throws hands up in the air and moves on...)
     424                 : 
     425               0 :   GnomeVFSFileInfo info = {0};
     426                 :   rv = gnome_vfs_get_file_info(mSpec.get(), &info, GnomeVFSFileInfoOptions(
     427                 :                                GNOME_VFS_FILE_INFO_DEFAULT |
     428               0 :                                GNOME_VFS_FILE_INFO_FOLLOW_LINKS));
     429               0 :   if (rv == GNOME_VFS_OK)
     430                 :   {
     431               0 :     if (info.type == GNOME_VFS_FILE_TYPE_DIRECTORY)
     432                 :     {
     433                 :       rv = gnome_vfs_directory_list_load(&mDirList, mSpec.get(),
     434               0 :                                          GNOME_VFS_FILE_INFO_DEFAULT);
     435                 : 
     436               0 :       LOG(("gnomevfs: gnome_vfs_directory_list_load returned %d (%s) [spec=\"%s\"]\n",
     437                 :           rv, gnome_vfs_result_to_string(rv), mSpec.get()));
     438                 :     }
     439                 :     else
     440                 :     {
     441               0 :       rv = gnome_vfs_open(&mHandle, mSpec.get(), GNOME_VFS_OPEN_READ);
     442                 : 
     443               0 :       LOG(("gnomevfs: gnome_vfs_open returned %d (%s) [spec=\"%s\"]\n",
     444                 :           rv, gnome_vfs_result_to_string(rv), mSpec.get()));
     445                 :     }
     446                 :   }
     447                 : 
     448               0 :   gnome_vfs_module_callback_pop(GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION);
     449                 : 
     450               0 :   if (rv == GNOME_VFS_OK)
     451                 :   {
     452               0 :     if (mHandle)
     453                 :     {
     454                 :       // Here we set the content type of the channel to the value of the mime
     455                 :       // type determined by GnomeVFS.  However, if GnomeVFS is telling us that
     456                 :       // the document is binary, we'll ignore that and keep the channel's
     457                 :       // content type unspecified.  That will enable our content type sniffing
     458                 :       // algorithms.  This should provide more consistent mime type handling.
     459                 : 
     460               0 :       if (info.mime_type && (strcmp(info.mime_type, APPLICATION_OCTET_STREAM) != 0))
     461               0 :         SetContentTypeOfChannel(info.mime_type);
     462                 : 
     463                 :       // XXX truncates size from 64-bit to 32-bit
     464               0 :       mBytesRemaining = (PRUint32) info.size;
     465                 : 
     466                 :       // Update the content length attribute on the channel.  We do this
     467                 :       // synchronously without proxying.  This hack is not as bad as it looks!
     468               0 :       if (mBytesRemaining != PR_UINT32_MAX)
     469               0 :         mChannel->SetContentLength(mBytesRemaining);
     470                 :     }
     471                 :     else
     472                 :     {
     473               0 :       mDirOpen = true;
     474                 : 
     475                 :       // Sort mDirList
     476               0 :       mDirList = g_list_sort(mDirList, FileInfoComparator);
     477               0 :       mDirListPtr = mDirList;
     478                 : 
     479                 :       // Write base URL (make sure it ends with a '/')
     480               0 :       mDirBuf.Append("300: ");
     481               0 :       mDirBuf.Append(mSpec);
     482               0 :       if (mSpec.get()[mSpec.Length() - 1] != '/')
     483               0 :         mDirBuf.Append('/');
     484               0 :       mDirBuf.Append('\n');
     485                 : 
     486                 :       // Write column names
     487               0 :       mDirBuf.Append("200: filename content-length last-modified file-type\n");
     488                 : 
     489                 :       // Write charset (assume UTF-8)
     490                 :       // XXX is this correct?
     491               0 :       mDirBuf.Append("301: UTF-8\n");
     492                 : 
     493               0 :       SetContentTypeOfChannel(APPLICATION_HTTP_INDEX_FORMAT);
     494                 :     }
     495                 :   }
     496                 : 
     497               0 :   gnome_vfs_file_info_clear(&info);
     498               0 :   return rv;
     499                 : }
     500                 : 
     501                 : GnomeVFSResult
     502               0 : nsGnomeVFSInputStream::DoRead(char *aBuf, PRUint32 aCount, PRUint32 *aCountRead)
     503                 : {
     504                 :   GnomeVFSResult rv;
     505                 : 
     506               0 :   if (mHandle)
     507                 :   {
     508                 :     GnomeVFSFileSize bytesRead;
     509               0 :     rv = gnome_vfs_read(mHandle, aBuf, aCount, &bytesRead);
     510               0 :     if (rv == GNOME_VFS_OK)
     511                 :     {
     512               0 :       *aCountRead = (PRUint32) bytesRead;
     513               0 :       mBytesRemaining -= *aCountRead;
     514                 :     }
     515                 :   }
     516               0 :   else if (mDirOpen)
     517                 :   {
     518               0 :     rv = GNOME_VFS_OK;
     519                 : 
     520               0 :     while (aCount && rv != GNOME_VFS_ERROR_EOF)
     521                 :     {
     522                 :       // Copy data out of our buffer
     523               0 :       PRUint32 bufLen = mDirBuf.Length() - mDirBufCursor;
     524               0 :       if (bufLen)
     525                 :       {
     526               0 :         PRUint32 n = NS_MIN(bufLen, aCount);
     527               0 :         memcpy(aBuf, mDirBuf.get() + mDirBufCursor, n);
     528               0 :         *aCountRead += n;
     529               0 :         aBuf += n;
     530               0 :         aCount -= n;
     531               0 :         mDirBufCursor += n;
     532                 :       }
     533                 : 
     534               0 :       if (!mDirListPtr)    // Are we at the end of the directory list?
     535                 :       {
     536               0 :         rv = GNOME_VFS_ERROR_EOF;
     537                 :       }
     538               0 :       else if (aCount)     // Do we need more data?
     539                 :       {
     540               0 :         GnomeVFSFileInfo *info = (GnomeVFSFileInfo *) mDirListPtr->data;
     541                 : 
     542                 :         // Prune '.' and '..' from directory listing.
     543               0 :         if (info->name[0] == '.' &&
     544               0 :                (info->name[1] == '\0' ||
     545               0 :                    (info->name[1] == '.' && info->name[2] == '\0')))
     546                 :         {
     547               0 :           mDirListPtr = mDirListPtr->next;
     548               0 :           continue;
     549                 :         }
     550                 : 
     551               0 :         mDirBuf.Assign("201: ");
     552                 : 
     553                 :         // The "filename" field
     554               0 :         nsCString escName;
     555               0 :         nsCOMPtr<nsINetUtil> nu = do_GetService(NS_NETUTIL_CONTRACTID);
     556               0 :         if (nu) {
     557               0 :           nu->EscapeString(nsDependentCString(info->name),
     558               0 :                            nsINetUtil::ESCAPE_URL_PATH, escName);
     559                 : 
     560               0 :           mDirBuf.Append(escName);
     561               0 :           mDirBuf.Append(' ');
     562                 :         }
     563                 : 
     564                 :         // The "content-length" field
     565                 :         // XXX truncates size from 64-bit to 32-bit
     566               0 :         mDirBuf.AppendInt(PRInt32(info->size));
     567               0 :         mDirBuf.Append(' ');
     568                 : 
     569                 :         // The "last-modified" field
     570                 :         // 
     571                 :         // NSPR promises: PRTime is compatible with time_t
     572                 :         // we just need to convert from seconds to microseconds
     573                 :         PRExplodedTime tm;
     574               0 :         PRTime pt = ((PRTime) info->mtime) * 1000000;
     575               0 :         PR_ExplodeTime(pt, PR_GMTParameters, &tm);
     576                 :         {
     577                 :           char buf[64];
     578                 :           PR_FormatTimeUSEnglish(buf, sizeof(buf),
     579               0 :               "%a,%%20%d%%20%b%%20%Y%%20%H:%M:%S%%20GMT ", &tm);
     580               0 :           mDirBuf.Append(buf);
     581                 :         }
     582                 : 
     583                 :         // The "file-type" field
     584               0 :         switch (info->type)
     585                 :         {
     586                 :           case GNOME_VFS_FILE_TYPE_REGULAR:
     587               0 :             mDirBuf.Append("FILE ");
     588               0 :             break;
     589                 :           case GNOME_VFS_FILE_TYPE_DIRECTORY:
     590               0 :             mDirBuf.Append("DIRECTORY ");
     591               0 :             break;
     592                 :           case GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK:
     593               0 :             mDirBuf.Append("SYMBOLIC-LINK ");
     594               0 :             break;
     595                 :           default:
     596               0 :             break;
     597                 :         }
     598                 : 
     599               0 :         mDirBuf.Append('\n');
     600                 : 
     601               0 :         mDirBufCursor = 0;
     602               0 :         mDirListPtr = mDirListPtr->next;
     603                 :       }
     604                 :     }
     605                 :   }
     606                 :   else
     607                 :   {
     608               0 :     NS_NOTREACHED("reading from what?");
     609               0 :     rv = GNOME_VFS_ERROR_GENERIC;
     610                 :   }
     611                 : 
     612               0 :   return rv;
     613                 : }
     614                 : 
     615                 : // This class is used to implement SetContentTypeOfChannel.
     616                 : class nsGnomeVFSSetContentTypeEvent : public nsRunnable
     617               0 : {
     618                 :   public:
     619               0 :     nsGnomeVFSSetContentTypeEvent(nsIChannel *channel, const char *contentType)
     620               0 :       : mChannel(channel), mContentType(contentType)
     621                 :     {
     622                 :       // stash channel reference in mChannel.  no AddRef here!  see note
     623                 :       // in SetContentTypeOfchannel.
     624               0 :     }
     625                 : 
     626               0 :     NS_IMETHOD Run()
     627                 :     {
     628               0 :       mChannel->SetContentType(mContentType);
     629               0 :       return NS_OK;
     630                 :     }
     631                 : 
     632                 :   private: 
     633                 :     nsIChannel *mChannel;
     634                 :     nsCString   mContentType;
     635                 : };
     636                 : 
     637                 : nsresult
     638               0 : nsGnomeVFSInputStream::SetContentTypeOfChannel(const char *contentType)
     639                 : {
     640                 :   // We need to proxy this call over to the main thread.  We post an
     641                 :   // asynchronous event in this case so that we don't delay reading data, and
     642                 :   // we know that this is safe to do since the channel's reference will be
     643                 :   // released asynchronously as well.  We trust the ordering of the main
     644                 :   // thread's event queue to protect us against memory corruption.
     645                 : 
     646                 :   nsresult rv;
     647                 :   nsCOMPtr<nsIRunnable> ev =
     648               0 :       new nsGnomeVFSSetContentTypeEvent(mChannel, contentType);
     649               0 :   if (!ev)
     650                 :   {
     651               0 :     rv = NS_ERROR_OUT_OF_MEMORY;
     652                 :   }
     653                 :   else
     654                 :   {
     655               0 :     rv = NS_DispatchToMainThread(ev);
     656                 :   }
     657               0 :   return rv;
     658                 : }
     659                 : 
     660               0 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsGnomeVFSInputStream, nsIInputStream)
     661                 : 
     662                 : NS_IMETHODIMP
     663               0 : nsGnomeVFSInputStream::Close()
     664                 : {
     665               0 :   if (mHandle)
     666                 :   {
     667               0 :     gnome_vfs_close(mHandle);
     668               0 :     mHandle = nsnull;
     669                 :   }
     670                 : 
     671               0 :   if (mDirList)
     672                 :   {
     673                 :     // Destroy the list of GnomeVFSFileInfo objects...
     674               0 :     g_list_foreach(mDirList, (GFunc) gnome_vfs_file_info_unref, nsnull);
     675               0 :     g_list_free(mDirList);
     676               0 :     mDirList = nsnull;
     677               0 :     mDirListPtr = nsnull;
     678                 :   }
     679                 : 
     680               0 :   if (mChannel)
     681                 :   {
     682               0 :     nsresult rv = NS_OK;
     683                 : 
     684               0 :     nsCOMPtr<nsIThread> thread = do_GetMainThread();
     685               0 :     if (thread)
     686               0 :       rv = NS_ProxyRelease(thread, mChannel);
     687                 : 
     688               0 :     NS_ASSERTION(thread && NS_SUCCEEDED(rv), "leaking channel reference");
     689               0 :     mChannel = nsnull;
     690                 :   }
     691                 : 
     692               0 :   mSpec.Truncate(); // free memory
     693                 : 
     694                 :   // Prevent future reads from re-opening the handle.
     695               0 :   if (NS_SUCCEEDED(mStatus))
     696               0 :     mStatus = NS_BASE_STREAM_CLOSED;
     697                 : 
     698               0 :   return NS_OK;
     699                 : }
     700                 : 
     701                 : NS_IMETHODIMP
     702               0 : nsGnomeVFSInputStream::Available(PRUint32 *aResult)
     703                 : {
     704               0 :   if (NS_FAILED(mStatus))
     705               0 :     return mStatus;
     706                 : 
     707               0 :   *aResult = mBytesRemaining;
     708               0 :   return NS_OK;
     709                 : }
     710                 : 
     711                 : NS_IMETHODIMP
     712               0 : nsGnomeVFSInputStream::Read(char *aBuf,
     713                 :                             PRUint32 aCount,
     714                 :                             PRUint32 *aCountRead)
     715                 : {
     716               0 :   *aCountRead = 0;
     717                 : 
     718               0 :   if (mStatus == NS_BASE_STREAM_CLOSED)
     719               0 :     return NS_OK;
     720               0 :   if (NS_FAILED(mStatus))
     721               0 :     return mStatus;
     722                 : 
     723               0 :   GnomeVFSResult rv = GNOME_VFS_OK;
     724                 : 
     725                 :   // If this is our first-time through here, then open the URI.
     726               0 :   if (!mHandle && !mDirOpen)
     727               0 :     rv = DoOpen();
     728                 :   
     729               0 :   if (rv == GNOME_VFS_OK)
     730               0 :     rv = DoRead(aBuf, aCount, aCountRead);
     731                 : 
     732               0 :   if (rv != GNOME_VFS_OK)
     733                 :   {
     734                 :     // If we reach here, we hit some kind of error.  EOF is not an error.
     735               0 :     mStatus = MapGnomeVFSResult(rv);
     736               0 :     if (mStatus == NS_BASE_STREAM_CLOSED)
     737               0 :       return NS_OK;
     738                 : 
     739               0 :     LOG(("gnomevfs: result %d [%s] mapped to 0x%x\n",
     740                 :         rv, gnome_vfs_result_to_string(rv), mStatus));
     741                 :   }
     742               0 :   return mStatus;
     743                 : }
     744                 : 
     745                 : NS_IMETHODIMP
     746               0 : nsGnomeVFSInputStream::ReadSegments(nsWriteSegmentFun aWriter,
     747                 :                                     void *aClosure,
     748                 :                                     PRUint32 aCount,
     749                 :                                     PRUint32 *aResult)
     750                 : {
     751                 :   // There is no way to implement this using GnomeVFS, but fortunately
     752                 :   // that doesn't matter.  Because we are a blocking input stream, Necko
     753                 :   // isn't going to call our ReadSegments method.
     754               0 :   NS_NOTREACHED("nsGnomeVFSInputStream::ReadSegments");
     755               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     756                 : }
     757                 : 
     758                 : NS_IMETHODIMP
     759               0 : nsGnomeVFSInputStream::IsNonBlocking(bool *aResult)
     760                 : {
     761               0 :   *aResult = false;
     762               0 :   return NS_OK;
     763                 : }
     764                 : 
     765                 : //-----------------------------------------------------------------------------
     766                 : 
     767                 : class nsGnomeVFSProtocolHandler : public nsIProtocolHandler
     768                 :                                 , public nsIObserver
     769              26 : {
     770                 :   public:
     771                 :     NS_DECL_ISUPPORTS
     772                 :     NS_DECL_NSIPROTOCOLHANDLER
     773                 :     NS_DECL_NSIOBSERVER
     774                 : 
     775                 :     nsresult Init();
     776                 : 
     777                 :   private:
     778                 :     void   InitSupportedProtocolsPref(nsIPrefBranch *prefs);
     779                 :     bool IsSupportedProtocol(const nsCString &spec);
     780                 : 
     781                 :     nsCString mSupportedProtocols;
     782                 : };
     783                 : 
     784            1240 : NS_IMPL_ISUPPORTS2(nsGnomeVFSProtocolHandler, nsIProtocolHandler, nsIObserver)
     785                 : 
     786                 : nsresult
     787              13 : nsGnomeVFSProtocolHandler::Init()
     788                 : {
     789                 : #ifdef PR_LOGGING
     790              13 :   sGnomeVFSLog = PR_NewLogModule("gnomevfs");
     791                 : #endif
     792                 : 
     793              13 :   if (!gnome_vfs_initialized())
     794                 :   {
     795              12 :     if (!gnome_vfs_init())
     796                 :     {
     797               0 :       NS_WARNING("gnome_vfs_init failed");
     798               0 :       return NS_ERROR_UNEXPECTED;
     799                 :     }
     800                 :   }
     801                 : 
     802              26 :   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     803              13 :   if (prefs)
     804                 :   {
     805              13 :     InitSupportedProtocolsPref(prefs);
     806              13 :     prefs->AddObserver(MOZ_GNOMEVFS_SUPPORTED_PROTOCOLS, this, false);
     807                 :   }
     808                 : 
     809              13 :   return NS_OK;
     810                 : }
     811                 : 
     812                 : void
     813              13 : nsGnomeVFSProtocolHandler::InitSupportedProtocolsPref(nsIPrefBranch *prefs)
     814                 : {
     815                 :   // read preferences
     816                 :   nsresult rv = prefs->GetCharPref(MOZ_GNOMEVFS_SUPPORTED_PROTOCOLS,
     817              13 :                                    getter_Copies(mSupportedProtocols));
     818              13 :   if (NS_SUCCEEDED(rv)) {
     819               0 :     mSupportedProtocols.StripWhitespace();
     820               0 :     ToLowerCase(mSupportedProtocols);
     821                 :   }
     822                 :   else
     823              13 :     mSupportedProtocols.Assign("smb:,sftp:"); // use defaults
     824                 : 
     825              13 :   LOG(("gnomevfs: supported protocols \"%s\"\n", mSupportedProtocols.get()));
     826              13 : }
     827                 : 
     828                 : bool
     829             209 : nsGnomeVFSProtocolHandler::IsSupportedProtocol(const nsCString &aSpec)
     830                 : {
     831             209 :   const char *specString = aSpec.get();
     832             209 :   const char *colon = strchr(specString, ':');
     833             209 :   if (!colon)
     834               0 :     return false;
     835                 : 
     836             209 :   PRUint32 length = colon - specString + 1;
     837                 : 
     838                 :   // <scheme> + ':'
     839             418 :   nsCString scheme(specString, length);
     840                 : 
     841             209 :   char *found = PL_strcasestr(mSupportedProtocols.get(), scheme.get());
     842             209 :   if (!found)
     843             209 :     return false;
     844                 : 
     845               0 :   if (found[length] != ',' && found[length] != '\0')
     846               0 :     return false;
     847                 : 
     848               0 :   return true;
     849                 : }
     850                 : 
     851                 : NS_IMETHODIMP
     852               0 : nsGnomeVFSProtocolHandler::GetScheme(nsACString &aScheme)
     853                 : {
     854               0 :   aScheme.Assign(MOZ_GNOMEVFS_SCHEME);
     855               0 :   return NS_OK;
     856                 : }
     857                 : 
     858                 : NS_IMETHODIMP
     859               0 : nsGnomeVFSProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort)
     860                 : {
     861               0 :   *aDefaultPort = -1;
     862               0 :   return NS_OK;
     863                 : }
     864                 : 
     865                 : NS_IMETHODIMP
     866               0 : nsGnomeVFSProtocolHandler::GetProtocolFlags(PRUint32 *aProtocolFlags)
     867                 : {
     868                 :   // Is URI_STD true of all GnomeVFS URI types?
     869               0 :   *aProtocolFlags = URI_STD | URI_DANGEROUS_TO_LOAD;
     870               0 :   return NS_OK;
     871                 : }
     872                 : 
     873                 : NS_IMETHODIMP
     874             209 : nsGnomeVFSProtocolHandler::NewURI(const nsACString &aSpec,
     875                 :                                   const char *aOriginCharset,
     876                 :                                   nsIURI *aBaseURI,
     877                 :                                   nsIURI **aResult)
     878                 : {
     879             418 :   const nsCString flatSpec(aSpec);
     880             209 :   LOG(("gnomevfs: NewURI [spec=%s]\n", flatSpec.get()));
     881                 : 
     882             209 :   if (!aBaseURI)
     883                 :   {
     884                 :     //
     885                 :     // XXX This check is used to limit the gnome-vfs protocols we support.  For
     886                 :     //     security reasons, it is best that we limit the protocols we support to
     887                 :     //     those with known characteristics.  We might want to lessen this
     888                 :     //     restriction if it proves to be too heavy handed.  A black list of
     889                 :     //     protocols we don't want to support might be better.  For example, we
     890                 :     //     probably don't want to try to load "start-here:" inside the browser.
     891                 :     //     There are others that fall into this category, which are best handled
     892                 :     //     externally by Nautilus (or another app like it).
     893                 :     //
     894             209 :     if (!IsSupportedProtocol(flatSpec))
     895             209 :       return NS_ERROR_UNKNOWN_PROTOCOL;
     896                 : 
     897                 :     // Verify that GnomeVFS supports this URI scheme.
     898               0 :     GnomeVFSURI *uri = gnome_vfs_uri_new(flatSpec.get());
     899               0 :     if (!uri)
     900               0 :       return NS_ERROR_UNKNOWN_PROTOCOL;
     901                 :   }
     902                 : 
     903                 :   //
     904                 :   // XXX Can we really assume that all gnome-vfs URIs can be parsed using
     905                 :   //     nsStandardURL?  We probably really need to implement nsIURI/nsIURL
     906                 :   //     in terms of the gnome_vfs_uri_XXX methods, but at least this works
     907                 :   //     correctly for smb:// URLs ;-)
     908                 :   //
     909                 :   //     Also, it might not be possible to fully implement nsIURI/nsIURL in
     910                 :   //     terms of GnomeVFSURI since some Necko methods have no GnomeVFS
     911                 :   //     equivalent.
     912                 :   //
     913                 :   nsresult rv;
     914                 :   nsCOMPtr<nsIStandardURL> url =
     915               0 :       do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
     916               0 :   if (NS_FAILED(rv))
     917               0 :     return rv;
     918                 : 
     919               0 :   rv = url->Init(nsIStandardURL::URLTYPE_STANDARD, -1, flatSpec,
     920               0 :                  aOriginCharset, aBaseURI);
     921               0 :   if (NS_SUCCEEDED(rv))
     922               0 :     rv = CallQueryInterface(url, aResult);
     923                 : 
     924               0 :   return rv;
     925                 : }
     926                 : 
     927                 : NS_IMETHODIMP
     928               0 : nsGnomeVFSProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **aResult)
     929                 : {
     930               0 :   NS_ENSURE_ARG_POINTER(aURI);
     931                 :   nsresult rv;
     932                 : 
     933               0 :   nsCAutoString spec;
     934               0 :   rv = aURI->GetSpec(spec);
     935               0 :   if (NS_FAILED(rv))
     936               0 :     return rv;
     937                 : 
     938               0 :   nsRefPtr<nsGnomeVFSInputStream> stream = new nsGnomeVFSInputStream(spec);
     939               0 :   if (!stream)
     940                 :   {
     941               0 :     rv = NS_ERROR_OUT_OF_MEMORY;
     942                 :   }
     943                 :   else
     944                 :   {
     945                 :     // start out assuming an unknown content-type.  we'll set the content-type
     946                 :     // to something better once we open the URI.
     947                 :     rv = NS_NewInputStreamChannel(aResult, aURI, stream,
     948               0 :                                   NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE));
     949               0 :     if (NS_SUCCEEDED(rv))
     950               0 :       stream->SetChannel(*aResult);
     951                 :   }
     952               0 :   return rv;
     953                 : }
     954                 : 
     955                 : NS_IMETHODIMP
     956               0 : nsGnomeVFSProtocolHandler::AllowPort(PRInt32 aPort,
     957                 :                                      const char *aScheme,
     958                 :                                      bool *aResult)
     959                 : {
     960                 :   // Don't override anything.
     961               0 :   *aResult = false; 
     962               0 :   return NS_OK;
     963                 : }
     964                 : 
     965                 : NS_IMETHODIMP
     966               0 : nsGnomeVFSProtocolHandler::Observe(nsISupports *aSubject,
     967                 :                                    const char *aTopic,
     968                 :                                    const PRUnichar *aData)
     969                 : {
     970               0 :   if (strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
     971               0 :     nsCOMPtr<nsIPrefBranch> prefs = do_QueryInterface(aSubject);
     972               0 :     InitSupportedProtocolsPref(prefs);
     973                 :   }
     974               0 :   return NS_OK;
     975                 : }
     976                 : 
     977                 : //-----------------------------------------------------------------------------
     978                 : 
     979                 : #define NS_GNOMEVFSPROTOCOLHANDLER_CID               \
     980                 : { /* 9b6dc177-a2e4-49e1-9c98-0a8384de7f6c */         \
     981                 :     0x9b6dc177,                                      \
     982                 :     0xa2e4,                                          \
     983                 :     0x49e1,                                          \
     984                 :     {0x9c, 0x98, 0x0a, 0x83, 0x84, 0xde, 0x7f, 0x6c} \
     985                 : }
     986                 : 
     987              26 : NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGnomeVFSProtocolHandler, Init)
     988                 : NS_DEFINE_NAMED_CID(NS_GNOMEVFSPROTOCOLHANDLER_CID);
     989                 : 
     990                 : static const mozilla::Module::CIDEntry kVFSCIDs[] = {
     991                 :   { &kNS_GNOMEVFSPROTOCOLHANDLER_CID, false, NULL, nsGnomeVFSProtocolHandlerConstructor },
     992                 :   { NULL }
     993                 : };
     994                 : 
     995                 : static const mozilla::Module::ContractIDEntry kVFSContracts[] = {
     996                 :   { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX MOZ_GNOMEVFS_SCHEME, &kNS_GNOMEVFSPROTOCOLHANDLER_CID },
     997                 :   { NULL }
     998                 : };
     999                 : 
    1000                 : static const mozilla::Module kVFSModule = {
    1001                 :   mozilla::Module::kVersion,
    1002                 :   kVFSCIDs,
    1003                 :   kVFSContracts
    1004                 : };
    1005                 : 
    1006                 : NSMODULE_DEFN(nsGnomeVFSModule) = &kVFSModule;

Generated by: LCOV version 1.7