netwerk/protocol/res/nsResProtocolHandler.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/chrome/RegistryMessageUtils.h"
     8 #include "nsResProtocolHandler.h"
     9 #include "nsIIOService.h"
    10 #include "nsIFile.h"
    11 #include "nsNetUtil.h"
    12 #include "nsURLHelper.h"
    13 #include "nsEscape.h"
    15 #include "mozilla/Omnijar.h"
    17 static NS_DEFINE_CID(kResURLCID, NS_RESURL_CID);
    19 static nsResProtocolHandler *gResHandler = nullptr;
    21 #if defined(PR_LOGGING)
    22 //
    23 // Log module for Resource Protocol logging...
    24 //
    25 // To enable logging (see prlog.h for full details):
    26 //
    27 //    set NSPR_LOG_MODULES=nsResProtocol:5
    28 //    set NSPR_LOG_FILE=log.txt
    29 //
    30 // this enables PR_LOG_ALWAYS level information and places all output in
    31 // the file log.txt
    32 //
    33 static PRLogModuleInfo *gResLog;
    34 #endif
    36 #define kAPP           NS_LITERAL_CSTRING("app")
    37 #define kGRE           NS_LITERAL_CSTRING("gre")
    39 //----------------------------------------------------------------------------
    40 // nsResURL : overrides nsStandardURL::GetFile to provide nsIFile resolution
    41 //----------------------------------------------------------------------------
    43 nsresult
    44 nsResURL::EnsureFile()
    45 {
    46     nsresult rv;
    48     NS_ENSURE_TRUE(gResHandler, NS_ERROR_NOT_AVAILABLE);
    50     nsAutoCString spec;
    51     rv = gResHandler->ResolveURI(this, spec);
    52     if (NS_FAILED(rv))
    53         return rv;
    55     nsAutoCString scheme;
    56     rv = net_ExtractURLScheme(spec, nullptr, nullptr, &scheme);
    57     if (NS_FAILED(rv))
    58         return rv;
    60     // Bug 585869:
    61     // In most cases, the scheme is jar if it's not file.
    62     // Regardless, net_GetFileFromURLSpec should be avoided
    63     // when the scheme isn't file.
    64     if (!scheme.Equals(NS_LITERAL_CSTRING("file")))
    65         return NS_ERROR_NO_INTERFACE;
    67     rv = net_GetFileFromURLSpec(spec, getter_AddRefs(mFile));
    68 #ifdef DEBUG_bsmedberg
    69     if (NS_SUCCEEDED(rv)) {
    70         bool exists = true;
    71         mFile->Exists(&exists);
    72         if (!exists) {
    73             printf("resource %s doesn't exist!\n", spec.get());
    74         }
    75     }
    76 #endif
    78     return rv;
    79 }
    81 /* virtual */ nsStandardURL*
    82 nsResURL::StartClone()
    83 {
    84     nsResURL *clone = new nsResURL();
    85     return clone;
    86 }
    88 NS_IMETHODIMP 
    89 nsResURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
    90 {
    91     *aClassIDNoAlloc = kResURLCID;
    92     return NS_OK;
    93 }
    95 //----------------------------------------------------------------------------
    96 // nsResProtocolHandler <public>
    97 //----------------------------------------------------------------------------
    99 nsResProtocolHandler::nsResProtocolHandler()
   100     : mSubstitutions(32)
   101 {
   102 #if defined(PR_LOGGING)
   103     gResLog = PR_NewLogModule("nsResProtocol");
   104 #endif
   106     NS_ASSERTION(!gResHandler, "res handler already created!");
   107     gResHandler = this;
   108 }
   110 nsResProtocolHandler::~nsResProtocolHandler()
   111 {
   112     gResHandler = nullptr;
   113 }
   115 nsresult
   116 nsResProtocolHandler::Init()
   117 {
   118     nsresult rv;
   120     mIOService = do_GetIOService(&rv);
   121     NS_ENSURE_SUCCESS(rv, rv);
   123     nsAutoCString appURI, greURI;
   124     rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::APP, appURI);
   125     NS_ENSURE_SUCCESS(rv, rv);
   126     rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::GRE, greURI);
   127     NS_ENSURE_SUCCESS(rv, rv);
   129     //
   130     // make resource:/// point to the application directory or omnijar
   131     //
   132     nsCOMPtr<nsIURI> uri;
   133     rv = NS_NewURI(getter_AddRefs(uri), appURI.Length() ? appURI : greURI);
   134     NS_ENSURE_SUCCESS(rv, rv);
   136     rv = SetSubstitution(EmptyCString(), uri);
   137     NS_ENSURE_SUCCESS(rv, rv);
   139     //
   140     // make resource://app/ point to the application directory or omnijar
   141     //
   142     rv = SetSubstitution(kAPP, uri);
   143     NS_ENSURE_SUCCESS(rv, rv);
   145     //
   146     // make resource://gre/ point to the GRE directory
   147     //
   148     if (appURI.Length()) { // We already have greURI in uri if appURI.Length() is 0.
   149         rv = NS_NewURI(getter_AddRefs(uri), greURI);
   150         NS_ENSURE_SUCCESS(rv, rv);
   151     }
   153     rv = SetSubstitution(kGRE, uri);
   154     NS_ENSURE_SUCCESS(rv, rv);
   156     //XXXbsmedberg Neil wants a resource://pchrome/ for the profile chrome dir...
   157     // but once I finish multiple chrome registration I'm not sure that it is needed
   159     // XXX dveditz: resource://pchrome/ defeats profile directory salting
   160     // if web content can load it. Tread carefully.
   162     return rv;
   163 }
   165 static PLDHashOperator
   166 EnumerateSubstitution(const nsACString& aKey,
   167                       nsIURI* aURI,
   168                       void* aArg)
   169 {
   170     nsTArray<ResourceMapping>* resources =
   171             static_cast<nsTArray<ResourceMapping>*>(aArg);
   172     SerializedURI uri;
   173     if (aURI) {
   174         aURI->GetSpec(uri.spec);
   175         aURI->GetOriginCharset(uri.charset);
   176     }
   178     ResourceMapping resource = {
   179         nsCString(aKey), uri
   180     };
   181     resources->AppendElement(resource);
   182     return (PLDHashOperator)PL_DHASH_NEXT;
   183 }
   185 void
   186 nsResProtocolHandler::CollectSubstitutions(InfallibleTArray<ResourceMapping>& aResources)
   187 {
   188     mSubstitutions.EnumerateRead(&EnumerateSubstitution, &aResources);
   189 }
   191 //----------------------------------------------------------------------------
   192 // nsResProtocolHandler::nsISupports
   193 //----------------------------------------------------------------------------
   195 NS_IMPL_ISUPPORTS(nsResProtocolHandler,
   196                   nsIResProtocolHandler,
   197                   nsIProtocolHandler,
   198                   nsISupportsWeakReference)
   200 //----------------------------------------------------------------------------
   201 // nsResProtocolHandler::nsIProtocolHandler
   202 //----------------------------------------------------------------------------
   204 NS_IMETHODIMP
   205 nsResProtocolHandler::GetScheme(nsACString &result)
   206 {
   207     result.AssignLiteral("resource");
   208     return NS_OK;
   209 }
   211 NS_IMETHODIMP
   212 nsResProtocolHandler::GetDefaultPort(int32_t *result)
   213 {
   214     *result = -1;        // no port for res: URLs
   215     return NS_OK;
   216 }
   218 NS_IMETHODIMP
   219 nsResProtocolHandler::GetProtocolFlags(uint32_t *result)
   220 {
   221     // XXXbz Is this really true for all resource: URIs?  Could we
   222     // somehow give different flags to some of them?
   223     *result = URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE;
   224     return NS_OK;
   225 }
   227 NS_IMETHODIMP
   228 nsResProtocolHandler::NewURI(const nsACString &aSpec,
   229                              const char *aCharset,
   230                              nsIURI *aBaseURI,
   231                              nsIURI **result)
   232 {
   233     nsresult rv;
   235     nsResURL *resURL = new nsResURL();
   236     if (!resURL)
   237         return NS_ERROR_OUT_OF_MEMORY;
   238     NS_ADDREF(resURL);
   240     // unescape any %2f and %2e to make sure nsStandardURL coalesces them.
   241     // Later net_GetFileFromURLSpec() will do a full unescape and we want to
   242     // treat them the same way the file system will. (bugs 380994, 394075)
   243     nsAutoCString spec;
   244     const char *src = aSpec.BeginReading();
   245     const char *end = aSpec.EndReading();
   246     const char *last = src;
   248     spec.SetCapacity(aSpec.Length()+1);
   249     for ( ; src < end; ++src) {
   250         if (*src == '%' && (src < end-2) && *(src+1) == '2') {
   251            char ch = '\0';
   252            if (*(src+2) == 'f' || *(src+2) == 'F')
   253              ch = '/';
   254            else if (*(src+2) == 'e' || *(src+2) == 'E')
   255              ch = '.';
   257            if (ch) {
   258              if (last < src)
   259                spec.Append(last, src-last);
   260              spec.Append(ch);
   261              src += 2;
   262              last = src+1; // src will be incremented by the loop
   263            }
   264         }
   265     }
   266     if (last < src)
   267       spec.Append(last, src-last);
   269     rv = resURL->Init(nsIStandardURL::URLTYPE_STANDARD, -1, spec, aCharset, aBaseURI);
   270     if (NS_SUCCEEDED(rv))
   271         rv = CallQueryInterface(resURL, result);
   272     NS_RELEASE(resURL);
   273     return rv;
   274 }
   276 NS_IMETHODIMP
   277 nsResProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
   278 {
   279     NS_ENSURE_ARG_POINTER(uri);
   280     nsresult rv;
   281     nsAutoCString spec;
   283     rv = ResolveURI(uri, spec);
   284     if (NS_FAILED(rv)) return rv;
   286     rv = mIOService->NewChannel(spec, nullptr, nullptr, result);
   287     if (NS_FAILED(rv)) return rv;
   289     nsLoadFlags loadFlags = 0;
   290     (*result)->GetLoadFlags(&loadFlags);
   291     (*result)->SetLoadFlags(loadFlags & ~nsIChannel::LOAD_REPLACE);
   292     return (*result)->SetOriginalURI(uri);
   293 }
   295 NS_IMETHODIMP 
   296 nsResProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
   297 {
   298     // don't override anything.  
   299     *_retval = false;
   300     return NS_OK;
   301 }
   303 //----------------------------------------------------------------------------
   304 // nsResProtocolHandler::nsIResProtocolHandler
   305 //----------------------------------------------------------------------------
   307 NS_IMETHODIMP
   308 nsResProtocolHandler::SetSubstitution(const nsACString& root, nsIURI *baseURI)
   309 {
   310     if (!baseURI) {
   311         mSubstitutions.Remove(root);
   312         return NS_OK;
   313     }
   315     // If baseURI isn't a resource URI, we can set the substitution immediately.
   316     nsAutoCString scheme;
   317     nsresult rv = baseURI->GetScheme(scheme);
   318     NS_ENSURE_SUCCESS(rv, rv);
   319     if (!scheme.Equals(NS_LITERAL_CSTRING("resource"))) {
   320         mSubstitutions.Put(root, baseURI);
   321         return NS_OK;
   322     }
   324     // baseURI is a resource URI, let's resolve it first.
   325     nsAutoCString newBase;
   326     rv = ResolveURI(baseURI, newBase);
   327     NS_ENSURE_SUCCESS(rv, rv);
   329     nsCOMPtr<nsIURI> newBaseURI;
   330     rv = mIOService->NewURI(newBase, nullptr, nullptr,
   331                             getter_AddRefs(newBaseURI));
   332     NS_ENSURE_SUCCESS(rv, rv);
   334     mSubstitutions.Put(root, newBaseURI);
   335     return NS_OK;
   336 }
   338 NS_IMETHODIMP
   339 nsResProtocolHandler::GetSubstitution(const nsACString& root, nsIURI **result)
   340 {
   341     NS_ENSURE_ARG_POINTER(result);
   343     if (mSubstitutions.Get(root, result))
   344         return NS_OK;
   346     // try invoking the directory service for "resource:root"
   348     nsAutoCString key;
   349     key.AssignLiteral("resource:");
   350     key.Append(root);
   352     nsCOMPtr<nsIFile> file;
   353     nsresult rv = NS_GetSpecialDirectory(key.get(), getter_AddRefs(file));
   354     if (NS_FAILED(rv))
   355         return NS_ERROR_NOT_AVAILABLE;
   357     rv = mIOService->NewFileURI(file, result);
   358     if (NS_FAILED(rv))
   359         return NS_ERROR_NOT_AVAILABLE;
   361     return NS_OK;
   362 }
   364 NS_IMETHODIMP
   365 nsResProtocolHandler::HasSubstitution(const nsACString& root, bool *result)
   366 {
   367     NS_ENSURE_ARG_POINTER(result);
   369     *result = mSubstitutions.Get(root, nullptr);
   370     return NS_OK;
   371 }
   373 NS_IMETHODIMP
   374 nsResProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result)
   375 {
   376     nsresult rv;
   378     nsAutoCString host;
   379     nsAutoCString path;
   381     rv = uri->GetAsciiHost(host);
   382     if (NS_FAILED(rv)) return rv;
   384     rv = uri->GetPath(path);
   385     if (NS_FAILED(rv)) return rv;
   387     // Unescape the path so we can perform some checks on it.
   388     nsAutoCString unescapedPath(path);
   389     NS_UnescapeURL(unescapedPath);
   391     // Don't misinterpret the filepath as an absolute URI.
   392     if (unescapedPath.FindChar(':') != -1)
   393         return NS_ERROR_MALFORMED_URI;
   395     if (unescapedPath.FindChar('\\') != -1)
   396         return NS_ERROR_MALFORMED_URI;
   398     const char *p = path.get() + 1; // path always starts with a slash
   399     NS_ASSERTION(*(p-1) == '/', "Path did not begin with a slash!");
   401     if (*p == '/')
   402         return NS_ERROR_MALFORMED_URI;
   404     nsCOMPtr<nsIURI> baseURI;
   405     rv = GetSubstitution(host, getter_AddRefs(baseURI));
   406     if (NS_FAILED(rv)) return rv;
   408     rv = baseURI->Resolve(nsDependentCString(p, path.Length()-1), result);
   410 #if defined(PR_LOGGING)
   411     if (PR_LOG_TEST(gResLog, PR_LOG_DEBUG)) {
   412         nsAutoCString spec;
   413         uri->GetAsciiSpec(spec);
   414         PR_LOG(gResLog, PR_LOG_DEBUG,
   415                ("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get()));
   416     }
   417 #endif
   418     return rv;
   419 }

mercurial