image/decoders/icon/nsIconURI.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "mozilla/ArrayUtils.h"
     9 #include "nsIconURI.h"
    10 #include "nsNetUtil.h"
    11 #include "nsIIOService.h"
    12 #include "nsIURL.h"
    13 #include "prprf.h"
    14 #include "plstr.h"
    15 #include <stdlib.h>
    17 using namespace mozilla;
    19 #define DEFAULT_IMAGE_SIZE 16
    21 #if defined(MAX_PATH)
    22 #define SANE_FILE_NAME_LEN MAX_PATH
    23 #elif defined(PATH_MAX)
    24 #define SANE_FILE_NAME_LEN PATH_MAX
    25 #else
    26 #define SANE_FILE_NAME_LEN 1024
    27 #endif
    29 // helper function for parsing out attributes like size, and contentType
    30 // from the icon url.
    31 static void extractAttributeValue(const char * searchString, const char * attributeName, nsCString& aResult);
    33 static const char *kSizeStrings[] =
    34 {
    35   "button",
    36   "toolbar",
    37   "toolbarsmall",
    38   "menu",
    39   "dnd",
    40   "dialog"
    41 };
    43 static const char *kStateStrings[] =
    44 {
    45   "normal",
    46   "disabled"
    47 };
    49 ////////////////////////////////////////////////////////////////////////////////
    51 nsMozIconURI::nsMozIconURI()
    52   : mSize(DEFAULT_IMAGE_SIZE),
    53     mIconSize(-1),
    54     mIconState(-1)
    55 {
    56 }
    58 nsMozIconURI::~nsMozIconURI()
    59 {
    60 }
    62 NS_IMPL_ISUPPORTS(nsMozIconURI, nsIMozIconURI, nsIURI)
    64 #define MOZICON_SCHEME "moz-icon:"
    65 #define MOZICON_SCHEME_LEN (sizeof(MOZICON_SCHEME) - 1)
    67 ////////////////////////////////////////////////////////////////////////////////
    68 // nsIURI methods:
    70 NS_IMETHODIMP
    71 nsMozIconURI::GetSpec(nsACString &aSpec)
    72 {
    73   aSpec = MOZICON_SCHEME;
    75   if (mIconURL)
    76   {
    77     nsAutoCString fileIconSpec;
    78     nsresult rv = mIconURL->GetSpec(fileIconSpec);
    79     NS_ENSURE_SUCCESS(rv, rv);
    80     aSpec += fileIconSpec;
    81   }
    82   else if (!mStockIcon.IsEmpty())
    83   {
    84     aSpec += "//stock/";
    85     aSpec += mStockIcon;
    86   }
    87   else
    88   {
    89     aSpec += "//";
    90     aSpec += mFileName;
    91   }
    93   aSpec += "?size=";
    94   if (mIconSize >= 0)
    95   {
    96     aSpec += kSizeStrings[mIconSize];
    97   }
    98   else
    99   {
   100     char buf[20];
   101     PR_snprintf(buf, sizeof(buf), "%d", mSize);
   102     aSpec.Append(buf);
   103   }
   105   if (mIconState >= 0) {
   106     aSpec += "&state=";
   107     aSpec += kStateStrings[mIconState];
   108   }
   110   if (!mContentType.IsEmpty())
   111   {
   112     aSpec += "&contentType=";
   113     aSpec += mContentType.get();
   114   }
   116   return NS_OK;
   117 }
   119 NS_IMETHODIMP
   120 nsMozIconURI::GetSpecIgnoringRef(nsACString &result)
   121 {
   122   return GetSpec(result);
   123 }
   125 NS_IMETHODIMP
   126 nsMozIconURI::GetHasRef(bool *result)
   127 {
   128   *result = false;
   129   return NS_OK;
   130 }
   132 // takes a string like ?size=32&contentType=text/html and returns a new string 
   133 // containing just the attribute value. i.e you could pass in this string with
   134 // an attribute name of 'size=', this will return 32
   135 // Assumption: attribute pairs in the string are separated by '&'.
   136 void extractAttributeValue(const char * searchString, const char * attributeName, nsCString& result)
   137 {
   138   //NS_ENSURE_ARG_POINTER(extractAttributeValue);
   140   result.Truncate();
   142   if (searchString && attributeName)
   143   {
   144     // search the string for attributeName
   145     uint32_t attributeNameSize = strlen(attributeName);
   146     const char * startOfAttribute = PL_strcasestr(searchString, attributeName);
   147     if (startOfAttribute &&
   148        ( *(startOfAttribute-1) == '?' || *(startOfAttribute-1) == '&') )
   149     {
   150       startOfAttribute += attributeNameSize; // skip over the attributeName
   151       if (*startOfAttribute) // is there something after the attribute name
   152       {
   153         const char * endofAttribute = strchr(startOfAttribute, '&');
   154         if (endofAttribute)
   155           result.Assign(Substring(startOfAttribute, endofAttribute));
   156         else
   157           result.Assign(startOfAttribute);
   158       } // if we have a attribute value
   159     } // if we have a attribute name
   160   } // if we got non-null search string and attribute name values
   161 }
   163 NS_IMETHODIMP
   164 nsMozIconURI::SetSpec(const nsACString &aSpec)
   165 {
   166   // Reset everything to default values.
   167   mIconURL = nullptr;
   168   mSize = DEFAULT_IMAGE_SIZE;
   169   mContentType.Truncate();
   170   mFileName.Truncate();
   171   mStockIcon.Truncate();
   172   mIconSize = -1;
   173   mIconState = -1;
   175   nsAutoCString iconSpec(aSpec);
   176   if (!Substring(iconSpec, 0, MOZICON_SCHEME_LEN).EqualsLiteral(MOZICON_SCHEME))
   177     return NS_ERROR_MALFORMED_URI;
   179   int32_t questionMarkPos = iconSpec.Find("?");
   180   if (questionMarkPos != -1 && static_cast<int32_t>(iconSpec.Length()) > (questionMarkPos + 1))
   181   {
   182     extractAttributeValue(iconSpec.get(), "contentType=", mContentType);
   184     nsAutoCString sizeString;
   185     extractAttributeValue(iconSpec.get(), "size=", sizeString);
   186     if (!sizeString.IsEmpty())
   187     {      
   188       const char *sizeStr = sizeString.get();
   189       for (uint32_t i = 0; i < ArrayLength(kSizeStrings); i++)
   190       {
   191         if (PL_strcasecmp(sizeStr, kSizeStrings[i]) == 0)
   192         {
   193           mIconSize = i;
   194           break;
   195         }
   196       }
   198       int32_t sizeValue = atoi(sizeString.get());
   199       if (sizeValue)
   200         mSize = sizeValue;
   201     }
   203     nsAutoCString stateString;
   204     extractAttributeValue(iconSpec.get(), "state=", stateString);
   205     if (!stateString.IsEmpty())
   206     {
   207       const char *stateStr = stateString.get();
   208       for (uint32_t i = 0; i < ArrayLength(kStateStrings); i++)
   209       {
   210         if (PL_strcasecmp(stateStr, kStateStrings[i]) == 0)
   211         {
   212           mIconState = i;
   213           break;
   214         }
   215       }
   216     }
   217   }
   219   int32_t pathLength = iconSpec.Length() - MOZICON_SCHEME_LEN;
   220   if (questionMarkPos != -1)
   221     pathLength = questionMarkPos - MOZICON_SCHEME_LEN;
   222   if (pathLength < 3)
   223     return NS_ERROR_MALFORMED_URI;
   225   nsAutoCString iconPath(Substring(iconSpec, MOZICON_SCHEME_LEN, pathLength));
   227   // Icon URI path can have three forms:
   228   // (1) //stock/<icon-identifier>
   229   // (2) //<some dummy file with an extension>
   230   // (3) a valid URL
   232   if (!strncmp("//stock/", iconPath.get(), 8))
   233   {
   234     mStockIcon.Assign(Substring(iconPath, 8));
   235     // An icon identifier must always be specified.
   236     if (mStockIcon.IsEmpty())
   237       return NS_ERROR_MALFORMED_URI;
   238     return NS_OK;
   239   }
   241   if (StringBeginsWith(iconPath, NS_LITERAL_CSTRING("//")))
   242   {
   243     // Sanity check this supposed dummy file name.
   244     if (iconPath.Length() > SANE_FILE_NAME_LEN)
   245       return NS_ERROR_MALFORMED_URI;
   246     iconPath.Cut(0, 2);
   247     mFileName.Assign(iconPath);
   248   }
   250   nsresult rv;
   251   nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
   252   NS_ENSURE_SUCCESS(rv, rv);
   254   nsCOMPtr<nsIURI> uri;
   255   ioService->NewURI(iconPath, nullptr, nullptr, getter_AddRefs(uri));
   256   mIconURL = do_QueryInterface(uri);
   257   if (mIconURL)
   258     mFileName.Truncate();
   259   else if (mFileName.IsEmpty())
   260     return NS_ERROR_MALFORMED_URI;
   262   return NS_OK;
   263 }
   265 NS_IMETHODIMP
   266 nsMozIconURI::GetPrePath(nsACString &prePath)
   267 {
   268   prePath = MOZICON_SCHEME;
   269   return NS_OK;
   270 }
   272 NS_IMETHODIMP
   273 nsMozIconURI::GetScheme(nsACString &aScheme)
   274 {
   275   aScheme = "moz-icon";
   276   return NS_OK;
   277 }
   279 NS_IMETHODIMP
   280 nsMozIconURI::SetScheme(const nsACString &aScheme)
   281 {
   282   // doesn't make sense to set the scheme of a moz-icon URL
   283   return NS_ERROR_FAILURE;
   284 }
   286 NS_IMETHODIMP
   287 nsMozIconURI::GetUsername(nsACString &aUsername)
   288 {
   289   return NS_ERROR_FAILURE;
   290 }
   292 NS_IMETHODIMP
   293 nsMozIconURI::SetUsername(const nsACString &aUsername)
   294 {
   295   return NS_ERROR_FAILURE;
   296 }
   298 NS_IMETHODIMP
   299 nsMozIconURI::GetPassword(nsACString &aPassword)
   300 {
   301   return NS_ERROR_FAILURE;
   302 }
   304 NS_IMETHODIMP
   305 nsMozIconURI::SetPassword(const nsACString &aPassword)
   306 {
   307   return NS_ERROR_FAILURE;
   308 }
   310 NS_IMETHODIMP
   311 nsMozIconURI::GetUserPass(nsACString &aUserPass)
   312 {
   313   return NS_ERROR_FAILURE;
   314 }
   316 NS_IMETHODIMP
   317 nsMozIconURI::SetUserPass(const nsACString &aUserPass)
   318 {
   319   return NS_ERROR_FAILURE;
   320 }
   322 NS_IMETHODIMP
   323 nsMozIconURI::GetHostPort(nsACString &aHostPort)
   324 {
   325   return NS_ERROR_FAILURE;
   326 }
   328 NS_IMETHODIMP
   329 nsMozIconURI::SetHostPort(const nsACString &aHostPort)
   330 {
   331   return NS_ERROR_FAILURE;
   332 }
   334 NS_IMETHODIMP
   335 nsMozIconURI::GetHost(nsACString &aHost)
   336 {
   337   return NS_ERROR_FAILURE;
   338 }
   340 NS_IMETHODIMP
   341 nsMozIconURI::SetHost(const nsACString &aHost)
   342 {
   343   return NS_ERROR_FAILURE;
   344 }
   346 NS_IMETHODIMP
   347 nsMozIconURI::GetPort(int32_t *aPort)
   348 {
   349   return NS_ERROR_FAILURE;
   350 }
   352 NS_IMETHODIMP
   353 nsMozIconURI::SetPort(int32_t aPort)
   354 {
   355   return NS_ERROR_FAILURE;
   356 }
   358 NS_IMETHODIMP
   359 nsMozIconURI::GetPath(nsACString &aPath)
   360 {
   361   aPath.Truncate();
   362   return NS_OK;
   363 }
   365 NS_IMETHODIMP
   366 nsMozIconURI::SetPath(const nsACString &aPath)
   367 {
   368   return NS_ERROR_FAILURE;
   369 }
   371 NS_IMETHODIMP
   372 nsMozIconURI::GetRef(nsACString &aRef)
   373 {
   374   aRef.Truncate();
   375   return NS_OK;
   376 }
   378 NS_IMETHODIMP
   379 nsMozIconURI::SetRef(const nsACString &aRef)
   380 {
   381   return NS_ERROR_FAILURE;
   382 }
   384 NS_IMETHODIMP
   385 nsMozIconURI::Equals(nsIURI *other, bool *result)
   386 {
   387   NS_ENSURE_ARG_POINTER(other);
   388   NS_PRECONDITION(result, "null pointer");
   390   nsAutoCString spec1;
   391   nsAutoCString spec2;
   393   other->GetSpec(spec2);
   394   GetSpec(spec1);
   395   if (!PL_strcasecmp(spec1.get(), spec2.get()))
   396     *result = true;
   397   else
   398     *result = false;
   399   return NS_OK;
   400 }
   402 NS_IMETHODIMP
   403 nsMozIconURI::EqualsExceptRef(nsIURI *other, bool *result)
   404 {
   405   // GetRef/SetRef not supported by nsMozIconURI, so
   406   // EqualsExceptRef() is the same as Equals().
   407   return Equals(other, result);
   408 }
   410 NS_IMETHODIMP
   411 nsMozIconURI::SchemeIs(const char *i_Scheme, bool *o_Equals)
   412 {
   413   NS_ENSURE_ARG_POINTER(o_Equals);
   414   if (!i_Scheme) return NS_ERROR_INVALID_ARG;
   416   *o_Equals = PL_strcasecmp("moz-icon", i_Scheme) ? false : true;
   417   return NS_OK;
   418 }
   420 NS_IMETHODIMP
   421 nsMozIconURI::Clone(nsIURI **result)
   422 {
   423   nsCOMPtr<nsIURL> newIconURL;
   424   if (mIconURL)
   425   {
   426     nsCOMPtr<nsIURI> newURI;
   427     nsresult rv = mIconURL->Clone(getter_AddRefs(newURI));
   428     if (NS_FAILED(rv))
   429       return rv;
   430     newIconURL = do_QueryInterface(newURI, &rv);
   431     if (NS_FAILED(rv))
   432       return rv;
   433   }
   435   nsMozIconURI *uri = new nsMozIconURI();
   436   newIconURL.swap(uri->mIconURL);
   437   uri->mSize = mSize;
   438   uri->mContentType = mContentType;
   439   uri->mFileName = mFileName;
   440   uri->mStockIcon = mStockIcon;
   441   uri->mIconSize = mIconSize;
   442   uri->mIconState = mIconState;
   443   NS_ADDREF(*result = uri);
   445   return NS_OK;
   446 }
   448 NS_IMETHODIMP
   449 nsMozIconURI::CloneIgnoringRef(nsIURI **result)
   450 {
   451   // GetRef/SetRef not supported by nsMozIconURI, so
   452   // CloneIgnoringRef() is the same as Clone().
   453   return Clone(result);
   454 }
   456 NS_IMETHODIMP
   457 nsMozIconURI::Resolve(const nsACString &relativePath, nsACString &result)
   458 {
   459   return NS_ERROR_NOT_IMPLEMENTED;
   460 }
   462 NS_IMETHODIMP
   463 nsMozIconURI::GetAsciiSpec(nsACString &aSpecA)
   464 {
   465   return GetSpec(aSpecA);
   466 }
   468 NS_IMETHODIMP
   469 nsMozIconURI::GetAsciiHost(nsACString &aHostA)
   470 {
   471   return GetHost(aHostA);
   472 }
   474 NS_IMETHODIMP
   475 nsMozIconURI::GetOriginCharset(nsACString &result)
   476 {
   477   result.Truncate();
   478   return NS_OK;
   479 }
   481 ////////////////////////////////////////////////////////////////////////////////
   482 // nsIIconUri methods:
   484 NS_IMETHODIMP
   485 nsMozIconURI::GetIconURL(nsIURL* * aFileUrl)
   486 {
   487   *aFileUrl = mIconURL;
   488   NS_IF_ADDREF(*aFileUrl);
   489   return NS_OK;
   490 }
   492 NS_IMETHODIMP
   493 nsMozIconURI::SetIconURL(nsIURL* aFileUrl)
   494 {
   495   // this isn't called anywhere, needs to go through SetSpec parsing
   496   return NS_ERROR_NOT_IMPLEMENTED;
   497 }
   499 NS_IMETHODIMP
   500 nsMozIconURI::GetImageSize(uint32_t * aImageSize)  // measured by # of pixels in a row. defaults to 16.
   501 {
   502   *aImageSize = mSize;
   503   return NS_OK;
   504 }
   506 NS_IMETHODIMP
   507 nsMozIconURI::SetImageSize(uint32_t aImageSize)  // measured by # of pixels in a row. defaults to 16.
   508 {
   509   mSize = aImageSize;
   510   return NS_OK;
   511 }
   513 NS_IMETHODIMP
   514 nsMozIconURI::GetContentType(nsACString &aContentType)
   515 {
   516   aContentType = mContentType;
   517   return NS_OK;
   518 }
   520 NS_IMETHODIMP
   521 nsMozIconURI::SetContentType(const nsACString &aContentType) 
   522 {
   523   mContentType = aContentType;
   524   return NS_OK;
   525 }
   527 NS_IMETHODIMP
   528 nsMozIconURI::GetFileExtension(nsACString &aFileExtension)  
   529 {
   530   // First, try to get the extension from mIconURL if we have one
   531   if (mIconURL)
   532   {
   533     nsAutoCString fileExt;
   534     if (NS_SUCCEEDED(mIconURL->GetFileExtension(fileExt)))
   535     {
   536       if (!fileExt.IsEmpty())
   537       {
   538         // unfortunately, this code doesn't give us the required '.' in front of the extension
   539         // so we have to do it ourselves..
   540         aFileExtension.Assign('.');
   541         aFileExtension.Append(fileExt);
   542       }
   543     }
   544     return NS_OK;
   545   }
   547   if (!mFileName.IsEmpty())
   548   {
   549     // truncate the extension out of the file path...
   550     const char * chFileName = mFileName.get(); // get the underlying buffer
   551     const char * fileExt = strrchr(chFileName, '.');
   552     if (!fileExt)
   553       return NS_OK;
   554     aFileExtension = fileExt;
   555   }
   557   return NS_OK;
   558 }
   560 NS_IMETHODIMP
   561 nsMozIconURI::GetStockIcon(nsACString &aStockIcon)
   562 {
   563   aStockIcon = mStockIcon;
   564   return NS_OK;
   565 }
   567 NS_IMETHODIMP
   568 nsMozIconURI::GetIconSize(nsACString &aSize)
   569 {
   570   if (mIconSize >= 0)
   571     aSize = kSizeStrings[mIconSize];
   572   else
   573     aSize.Truncate();
   574   return NS_OK;
   575 }
   577 NS_IMETHODIMP
   578 nsMozIconURI::GetIconState(nsACString &aState)
   579 {
   580   if (mIconState >= 0)
   581     aState = kStateStrings[mIconState];
   582   else
   583     aState.Truncate();
   584   return NS_OK;
   585 }
   586 ////////////////////////////////////////////////////////////////////////////////

mercurial