LCOV - app.info - toolkit/components/url-classifier/nsUrlClassifierUtils.cpp

LCOV - code coverage report
| Current view: | directory - toolkit/components/url-classifier - nsUrlClassifierUtils.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 196 | 153 | 78.1 %
| Date: | 2012-04-21 | Functions: | 19 | 18 | 94.7 %

           1                 : /* ***** BEGIN LICENSE BLOCK *****
           2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           3                 :  *
           4                 :  * The contents of this file are subject to the Mozilla Public License Version
           5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           6                 :  * the License. You may obtain a copy of the License at
           7                 :  * http://www.mozilla.org/MPL/
           8                 :  *
           9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          11                 :  * for the specific language governing rights and limitations under the
          12                 :  * License.
          13                 :  *
          14                 :  * The Original Code is Url Classifier code
          15                 :  *
          16                 :  * The Initial Developer of the Original Code is
          17                 :  * Google Inc.
          18                 :  * Portions created by the Initial Developer are Copyright (C) 2007
          19                 :  * the Initial Developer. All Rights Reserved.
          20                 :  *
          21                 :  * Contributor(s):
          22                 :  *
          23                 :  * Alternatively, the contents of this file may be used under the terms of
          24                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          25                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          26                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          27                 :  * of those above. If you wish to allow use of your version of this file only
          28                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          29                 :  * use your version of this file under the terms of the MPL, indicate your
          30                 :  * decision by deleting the provisions above and replace them with the notice
          31                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          32                 :  * the provisions above, a recipient may use your version of this file under
          33                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          34                 :  *
          35                 :  * ***** END LICENSE BLOCK ***** */
          36                 :
          37                 : #include "nsEscape.h"
          38                 : #include "nsString.h"
          39                 : #include "nsIURI.h"
          40                 : #include "nsNetUtil.h"
          41                 : #include "nsUrlClassifierUtils.h"
          42                 : #include "nsTArray.h"
          43                 : #include "nsReadableUtils.h"
          44                 : #include "plbase64.h"
          45                 : #include "prmem.h"
          46                 : #include "prprf.h"
          47                 :
          48               0 : static char int_to_hex_digit(PRInt32 i)
          49                 : {
          50               0 :   NS_ASSERTION((i >= 0) && (i <= 15), "int too big in int_to_hex_digit");
          51               0 :   return static_cast<char>(((i < 10) ? (i + '0') : ((i - 10) + 'A')));
          52                 : }
          53                 :
          54                 : static bool
          55               9 : IsDecimal(const nsACString & num)
          56                 : {
          57              25 :   for (PRUint32 i = 0; i < num.Length(); i++) {
          58              17 :     if (!isdigit(num[i])) {
          59               1 :       return false;
          60                 :     }
          61                 :   }
          62                 :
          63               8 :   return true;
          64                 : }
          65                 :
          66                 : static bool
          67               1 : IsHex(const nsACString & num)
          68                 : {
          69               1 :   if (num.Length() < 3) {
          70               1 :     return false;
          71                 :   }
          72                 :
          73               0 :   if (num[0] != '0' || !(num[1] == 'x' || num[1] == 'X')) {
          74               0 :     return false;
          75                 :   }
          76                 :
          77               0 :   for (PRUint32 i = 2; i < num.Length(); i++) {
          78               0 :     if (!isxdigit(num[i])) {
          79               0 :       return false;
          80                 :     }
          81                 :   }
          82                 :
          83               0 :   return true;
          84                 : }
          85                 :
          86                 : static bool
          87               9 : IsOctal(const nsACString & num)
          88                 : {
          89               9 :   if (num.Length() < 2) {
          90               5 :     return false;
          91                 :   }
          92                 :
          93               4 :   if (num[0] != '0') {
          94               4 :     return false;
          95                 :   }
          96                 :
          97               0 :   for (PRUint32 i = 1; i < num.Length(); i++) {
          98               0 :     if (!isdigit(num[i]) || num[i] == '8' || num[i] == '9') {
          99               0 :       return false;
         100                 :     }
         101                 :   }
         102                 :
         103               0 :   return true;
         104                 : }
         105                 :
         106               4 : nsUrlClassifierUtils::nsUrlClassifierUtils() : mEscapeCharmap(nsnull)
         107                 : {
         108               4 : }
         109                 :
         110                 : nsresult
         111               4 : nsUrlClassifierUtils::Init()
         112                 : {
         113                 :   // Everything but alpha numerics, - and .
         114                 :   mEscapeCharmap = new Charmap(0xffffffff, 0xfc009fff, 0xf8000001, 0xf8000001,
         115               4 :                                0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
         116               4 :   if (!mEscapeCharmap)
         117               0 :     return NS_ERROR_OUT_OF_MEMORY;
         118               4 :   return NS_OK;
         119                 : }
         120                 :
         121             720 : NS_IMPL_ISUPPORTS1(nsUrlClassifierUtils, nsIUrlClassifierUtils)
         122                 :
         123                 : /////////////////////////////////////////////////////////////////////////////
         124                 : // nsIUrlClassifierUtils
         125                 :
         126                 : NS_IMETHODIMP
         127             140 : nsUrlClassifierUtils::GetKeyForURI(nsIURI * uri, nsACString & _retval)
         128                 : {
         129             280 :   nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(uri);
         130             140 :   if (!innerURI)
         131               0 :     innerURI = uri;
         132                 :
         133             280 :   nsCAutoString host;
         134             140 :   innerURI->GetAsciiHost(host);
         135                 :
         136             140 :   if (host.IsEmpty()) {
         137               0 :     return NS_ERROR_MALFORMED_URI;
         138                 :   }
         139                 :
         140             140 :   nsresult rv = CanonicalizeHostname(host, _retval);
         141             140 :   NS_ENSURE_SUCCESS(rv, rv);
         142                 :
         143             280 :   nsCAutoString path;
         144             140 :   rv = innerURI->GetPath(path);
         145             140 :   NS_ENSURE_SUCCESS(rv, rv);
         146                 :
         147                 :   // strip out anchors
         148             140 :   PRInt32 ref = path.FindChar('#');
         149             140 :   if (ref != kNotFound)
         150               0 :     path.SetLength(ref);
         151                 :
         152             280 :   nsCAutoString temp;
         153             140 :   rv = CanonicalizePath(path, temp);
         154             140 :   NS_ENSURE_SUCCESS(rv, rv);
         155                 :
         156             140 :   _retval.Append(temp);
         157                 :
         158             140 :   return NS_OK;
         159                 : }
         160                 :
         161                 : /////////////////////////////////////////////////////////////////////////////
         162                 : // non-interface methods
         163                 :
         164                 : nsresult
         165             140 : nsUrlClassifierUtils::CanonicalizeHostname(const nsACString & hostname,
         166                 :                                            nsACString & _retval)
         167                 : {
         168             280 :   nsCAutoString unescaped;
         169             280 :   if (!NS_UnescapeURL(PromiseFlatCString(hostname).get(),
         170             280 :                       PromiseFlatCString(hostname).Length(),
         171             140 :                       0, unescaped)) {
         172             140 :     unescaped.Assign(hostname);
         173                 :   }
         174                 :
         175             280 :   nsCAutoString cleaned;
         176             140 :   CleanupHostname(unescaped, cleaned);
         177                 :
         178             280 :   nsCAutoString temp;
         179             140 :   ParseIPAddress(cleaned, temp);
         180             140 :   if (!temp.IsEmpty()) {
         181               2 :     cleaned.Assign(temp);
         182                 :   }
         183                 :
         184             140 :   ToLowerCase(cleaned);
         185             140 :   SpecialEncode(cleaned, false, _retval);
         186                 :
         187             140 :   return NS_OK;
         188                 : }
         189                 :
         190                 :
         191                 : nsresult
         192             140 : nsUrlClassifierUtils::CanonicalizePath(const nsACString & path,
         193                 :                                        nsACString & _retval)
         194                 : {
         195             140 :   _retval.Truncate();
         196                 :
         197             280 :   nsCAutoString decodedPath(path);
         198             280 :   nsCAutoString temp;
         199             280 :   while (NS_UnescapeURL(decodedPath.get(), decodedPath.Length(), 0, temp)) {
         200               0 :     decodedPath.Assign(temp);
         201               0 :     temp.Truncate();
         202                 :   }
         203                 :
         204             140 :   SpecialEncode(decodedPath, true, _retval);
         205                 :   // XXX: lowercase the path?
         206                 :
         207             140 :   return NS_OK;
         208                 : }
         209                 :
         210                 : void
         211             140 : nsUrlClassifierUtils::CleanupHostname(const nsACString & hostname,
         212                 :                                       nsACString & _retval)
         213                 : {
         214             140 :   _retval.Truncate();
         215                 :
         216             140 :   const char* curChar = hostname.BeginReading();
         217             140 :   const char* end = hostname.EndReading();
         218             140 :   char lastChar = '\0';
         219            1298 :   while (curChar != end) {
         220            1018 :     unsigned char c = static_cast<unsigned char>(*curChar);
         221            1018 :     if (c == '.' && (lastChar == '\0' || lastChar == '.')) {
         222                 :       // skip
         223                 :     } else {
         224            1018 :       _retval.Append(*curChar);
         225                 :     }
         226            1018 :     lastChar = c;
         227            1018 :     ++curChar;
         228                 :   }
         229                 :
         230                 :   // cut off trailing dots
         231             280 :   while (_retval.Length() > 0 && _retval[_retval.Length() - 1] == '.') {
         232               0 :     _retval.SetLength(_retval.Length() - 1);
         233                 :   }
         234             140 : }
         235                 :
         236                 : void
         237             140 : nsUrlClassifierUtils::ParseIPAddress(const nsACString & host,
         238                 :                                      nsACString & _retval)
         239                 : {
         240             140 :   _retval.Truncate();
         241             140 :   nsACString::const_iterator iter, end;
         242             140 :   host.BeginReading(iter);
         243             140 :   host.EndReading(end);
         244                 :
         245             140 :   if (host.Length() <= 15) {
         246                 :     // The Windows resolver allows a 4-part dotted decimal IP address to
         247                 :     // have a space followed by any old rubbish, so long as the total length
         248                 :     // of the string doesn't get above 15 characters. So, "10.192.95.89 xy"
         249                 :     // is resolved to 10.192.95.89.
         250                 :     // If the string length is greater than 15 characters, e.g.
         251                 :     // "10.192.95.89 xy.wildcard.example.com", it will be resolved through
         252                 :     // DNS.
         253                 :
         254             140 :     if (FindCharInReadable(' ', iter, end)) {
         255               0 :       end = iter;
         256                 :     }
         257                 :   }
         258                 :
         259             353 :   for (host.BeginReading(iter); iter != end; iter++) {
         260             350 :     if (!(isxdigit(*iter) || *iter == 'x' || *iter == 'X' || *iter == '.')) {
         261                 :       // not an IP
         262             137 :       return;
         263                 :     }
         264                 :   }
         265                 :
         266               3 :   host.BeginReading(iter);
         267               6 :   nsTArray<nsCString> parts;
         268               3 :   ParseString(PromiseFlatCString(Substring(iter, end)), '.', parts);
         269               3 :   if (parts.Length() > 4) {
         270                 :     return;
         271                 :   }
         272                 :
         273                 :   // If any potentially-octal numbers (start with 0 but not hex) have
         274                 :   // non-octal digits, no part of the ip can be in octal
         275                 :   // XXX: this came from the old javascript implementation, is it really
         276                 :   // supposed to be like this?
         277               3 :   bool allowOctal = true;
         278                 :   PRUint32 i;
         279                 :
         280              14 :   for (i = 0; i < parts.Length(); i++) {
         281              11 :     const nsCString& part = parts[i];
         282              11 :     if (part[0] == '0') {
         283               2 :       for (PRUint32 j = 1; j < part.Length(); j++) {
         284               0 :         if (part[j] == 'x') {
         285               0 :           break;
         286                 :         }
         287               0 :         if (part[j] == '8' || part[j] == '9') {
         288               0 :           allowOctal = false;
         289               0 :           break;
         290                 :         }
         291                 :       }
         292                 :     }
         293                 :   }
         294                 :
         295              11 :   for (i = 0; i < parts.Length(); i++) {
         296              18 :     nsCAutoString canonical;
         297                 :
         298               9 :     if (i == parts.Length() - 1) {
         299               2 :       CanonicalNum(parts[i], 5 - parts.Length(), allowOctal, canonical);
         300                 :     } else {
         301               7 :       CanonicalNum(parts[i], 1, allowOctal, canonical);
         302                 :     }
         303                 :
         304               9 :     if (canonical.IsEmpty()) {
         305               1 :       _retval.Truncate();
         306                 :       return;
         307                 :     }
         308                 :
         309               8 :     if (_retval.IsEmpty()) {
         310               2 :       _retval.Assign(canonical);
         311                 :     } else {
         312               6 :       _retval.Append('.');
         313               6 :       _retval.Append(canonical);
         314                 :     }
         315                 :   }
         316                 :   return;
         317                 : }
         318                 :
         319                 : void
         320               9 : nsUrlClassifierUtils::CanonicalNum(const nsACString& num,
         321                 :                                    PRUint32 bytes,
         322                 :                                    bool allowOctal,
         323                 :                                    nsACString& _retval)
         324                 : {
         325               9 :   _retval.Truncate();
         326                 :
         327               9 :   if (num.Length() < 1) {
         328               0 :     return;
         329                 :   }
         330                 :
         331                 :   PRUint32 val;
         332               9 :   if (allowOctal && IsOctal(num)) {
         333               0 :     if (PR_sscanf(PromiseFlatCString(num).get(), "%o", &val) != 1) {
         334               0 :       return;
         335                 :     }
         336               9 :   } else if (IsDecimal(num)) {
         337               8 :     if (PR_sscanf(PromiseFlatCString(num).get(), "%u", &val) != 1) {
         338               0 :       return;
         339                 :     }
         340               1 :   } else if (IsHex(num)) {
         341               0 :   if (PR_sscanf(PromiseFlatCString(num).get(), num[1] == 'X' ? "0X%x" : "0x%x",
         342               0 :                 &val) != 1) {
         343               0 :       return;
         344                 :     }
         345                 :   } else {
         346               1 :     return;
         347                 :   }
         348                 :
         349              24 :   while (bytes--) {
         350                 :     char buf[20];
         351               8 :     PR_snprintf(buf, sizeof(buf), "%u", val & 0xff);
         352               8 :     if (_retval.IsEmpty()) {
         353               8 :       _retval.Assign(buf);
         354                 :     } else {
         355               0 :       _retval = nsDependentCString(buf) + NS_LITERAL_CSTRING(".") + _retval;
         356                 :     }
         357               8 :     val >>= 8;
         358                 :   }
         359                 : }
         360                 :
         361                 : // This function will encode all "special" characters in typical url
         362                 : // encoding, that is %hh where h is a valid hex digit.  It will also fold
         363                 : // any duplicated slashes.
         364                 : bool
         365             280 : nsUrlClassifierUtils::SpecialEncode(const nsACString & url,
         366                 :                                     bool foldSlashes,
         367                 :                                     nsACString & _retval)
         368                 : {
         369             280 :   bool changed = false;
         370             280 :   const char* curChar = url.BeginReading();
         371             280 :   const char* end = url.EndReading();
         372                 :
         373             280 :   unsigned char lastChar = '\0';
         374            1921 :   while (curChar != end) {
         375            1361 :     unsigned char c = static_cast<unsigned char>(*curChar);
         376            1361 :     if (ShouldURLEscape(c)) {
         377               0 :       _retval.Append('%');
         378               0 :       _retval.Append(int_to_hex_digit(c / 16));
         379               0 :       _retval.Append(int_to_hex_digit(c % 16));
         380                 :
         381               0 :       changed = true;
         382            1361 :     } else if (foldSlashes && (c == '/' && lastChar == '/')) {
         383                 :       // skip
         384                 :     } else {
         385            1361 :       _retval.Append(*curChar);
         386                 :     }
         387            1361 :     lastChar = c;
         388            1361 :     curChar++;
         389                 :   }
         390             280 :   return changed;
         391                 : }
         392                 :
         393                 : bool
         394            1361 : nsUrlClassifierUtils::ShouldURLEscape(const unsigned char c) const
         395                 : {
         396            1361 :   return c <= 32 || c == '%' || c >=127;
         397                 : }
         398                 :
         399                 : /* static */
         400                 : void
         401              18 : nsUrlClassifierUtils::UnUrlsafeBase64(nsACString &str)
         402                 : {
         403              18 :   nsACString::iterator iter, end;
         404              18 :   str.BeginWriting(iter);
         405              18 :   str.EndWriting(end);
         406             400 :   while (iter != end) {
         407             364 :     if (*iter == '-') {
         408               0 :       *iter = '+';
         409             364 :     } else if (*iter == '_') {
         410               0 :       *iter = '/';
         411                 :     }
         412             364 :     iter++;
         413                 :   }
         414              18 : }
         415                 :
         416                 : /* static */
         417                 : nsresult
         418               7 : nsUrlClassifierUtils::DecodeClientKey(const nsACString &key,
         419                 :                                       nsACString &_retval)
         420                 : {
         421                 :   // Client key is sent in urlsafe base64, we need to decode it first.
         422              14 :   nsCAutoString base64(key);
         423               7 :   UnUrlsafeBase64(base64);
         424                 :
         425                 :   // PL_Base64Decode doesn't null-terminate unless we let it allocate,
         426                 :   // so we need to calculate the length ourselves.
         427                 :   PRUint32 destLength;
         428               7 :   destLength = base64.Length();
         429               7 :   if (destLength > 0 && base64[destLength - 1] == '=') {
         430               7 :     if (destLength > 1 && base64[destLength - 2] == '=') {
         431               7 :       destLength -= 2;
         432                 :     } else {
         433               0 :       destLength -= 1;
         434                 :     }
         435                 :   }
         436                 :
         437               7 :   destLength = ((destLength * 3) / 4);
         438               7 :   _retval.SetLength(destLength);
         439               7 :   if (destLength != _retval.Length())
         440               0 :     return NS_ERROR_OUT_OF_MEMORY;
         441                 :
         442               7 :   if (!PL_Base64Decode(base64.BeginReading(), base64.Length(),
         443               7 :                        _retval.BeginWriting())) {
         444               0 :     return NS_ERROR_FAILURE;
         445                 :   }
         446                 :
         447               7 :   return NS_OK;
         448                 : }

Generated by: LCOV version 1.7