LCOV - code coverage report
Current view: directory - netwerk/base/src - nsURLParsers.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 281 221 78.6 %
Date: 2012-06-02 Functions: 18 14 77.8 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       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 mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Darin Fisher (original author)
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include <string.h>
      40                 : 
      41                 : #include "mozilla/RangedPtr.h"
      42                 : 
      43                 : #include "nsURLParsers.h"
      44                 : #include "nsURLHelper.h"
      45                 : #include "nsIURI.h"
      46                 : #include "prtypes.h"
      47                 : #include "nsString.h"
      48                 : #include "nsCRT.h"
      49                 : #include "netCore.h"
      50                 : 
      51                 : using namespace mozilla;
      52                 : 
      53                 : //----------------------------------------------------------------------------
      54                 : 
      55                 : static PRUint32
      56          353151 : CountConsecutiveSlashes(const char *str, PRInt32 len)
      57                 : {
      58          353151 :     RangedPtr<const char> p(str, len);
      59          353151 :     PRUint32 count = 0;
      60          353151 :     while (len-- && *p++ == '/') ++count;
      61          353151 :     return count;
      62                 : }
      63                 : 
      64                 : //----------------------------------------------------------------------------
      65                 : // nsBaseURLParser implementation
      66                 : //----------------------------------------------------------------------------
      67                 : 
      68                 : // The URL parser service does not have any internal state; however, it can
      69                 : // be called from multiple threads, so we must use a threadsafe AddRef and
      70                 : // Release implementation.
      71         2916594 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsBaseURLParser, nsIURLParser)
      72                 : 
      73                 : #define SET_RESULT(component, pos, len) \
      74                 :     PR_BEGIN_MACRO \
      75                 :         if (component ## Pos) \
      76                 :            *component ## Pos = PRUint32(pos); \
      77                 :         if (component ## Len) \
      78                 :            *component ## Len = PRInt32(len); \
      79                 :     PR_END_MACRO
      80                 : 
      81                 : #define OFFSET_RESULT(component, offset) \
      82                 :     PR_BEGIN_MACRO \
      83                 :         if (component ## Pos) \
      84                 :            *component ## Pos += offset; \
      85                 :     PR_END_MACRO
      86                 : 
      87                 : NS_IMETHODIMP
      88          485815 : nsBaseURLParser::ParseURL(const char *spec, PRInt32 specLen,
      89                 :                           PRUint32 *schemePos, PRInt32 *schemeLen,
      90                 :                           PRUint32 *authorityPos, PRInt32 *authorityLen,
      91                 :                           PRUint32 *pathPos, PRInt32 *pathLen)
      92                 : {
      93          485815 :     NS_PRECONDITION(spec, "null pointer");
      94                 : 
      95          485815 :     if (specLen < 0)
      96               0 :         specLen = strlen(spec);
      97                 : 
      98          485815 :     const char *stop = nsnull;
      99          485815 :     const char *colon = nsnull;
     100          485815 :     const char *slash = nsnull;
     101                 :     const char *p;
     102          485815 :     PRUint32 offset = 0;
     103          485815 :     PRInt32 len = specLen;
     104         3595516 :     for (p = spec; len && *p && !colon && !slash; ++p, --len) {
     105                 :         // skip leading whitespace
     106         3109701 :         if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') {
     107               0 :             spec++;
     108               0 :             specLen--;
     109               0 :             offset++;
     110               0 :             continue;
     111                 :         }
     112         3109701 :         switch (*p) {
     113                 :             case ':':
     114          353219 :                 if (!colon)
     115          353219 :                     colon = p;
     116          353219 :                 break;
     117                 :             case '/': // start of filepath
     118                 :             case '?': // start of query
     119                 :             case '#': // start of ref
     120          119473 :                 if (!slash)
     121          119473 :                     slash = p;
     122          119473 :                 break;
     123                 :             case '@': // username@hostname
     124                 :             case '[': // start of IPv6 address literal
     125               0 :                 if (!stop)
     126               0 :                     stop = p;
     127               0 :                 break;
     128                 :         }
     129                 :     }
     130                 :     // disregard the first colon if it follows an '@' or a '['
     131          485815 :     if (colon && stop && colon > stop)
     132               0 :         colon = nsnull;
     133                 : 
     134                 :     // if the spec only contained whitespace ...
     135          485815 :     if (specLen == 0) {
     136              34 :         SET_RESULT(scheme, 0, -1);
     137              34 :         SET_RESULT(authority, 0, 0);
     138              34 :         SET_RESULT(path, 0, 0);
     139              34 :         return NS_OK;
     140                 :     }
     141                 : 
     142                 :     // ignore trailing whitespace and control characters
     143          485781 :     for (p = spec + specLen - 1; ((unsigned char) *p <= ' ') && (p != spec); --p)
     144                 :         ;
     145                 : 
     146          485781 :     specLen = p - spec + 1;
     147                 : 
     148          485781 :     if (colon && (colon < slash || !slash)) {
     149                 :         //
     150                 :         // spec = <scheme>:/<the-rest>
     151                 :         //
     152                 :         // or
     153                 :         //
     154                 :         // spec = <scheme>:<authority>
     155                 :         // spec = <scheme>:<path-no-slashes>
     156                 :         //
     157          353219 :         if (!net_IsValidScheme(spec, colon - spec) || (*(colon+1) == ':')) {
     158               0 :             NS_WARNING("malformed uri");
     159               0 :             return NS_ERROR_MALFORMED_URI;
     160                 :         }
     161          353219 :         SET_RESULT(scheme, offset, colon - spec);
     162          353219 :         if (authorityLen || pathLen) {
     163          353148 :             PRUint32 schemeLen = colon + 1 - spec;
     164          353148 :             offset += schemeLen;
     165                 :             ParseAfterScheme(colon + 1, specLen - schemeLen,
     166                 :                              authorityPos, authorityLen,
     167          353148 :                              pathPos, pathLen);
     168          353148 :             OFFSET_RESULT(authority, offset);
     169          353148 :             OFFSET_RESULT(path, offset);
     170          353219 :         }
     171                 :     }
     172                 :     else {
     173                 :         // 
     174                 :         // spec = <authority-no-port-or-password>/<path>
     175                 :         // spec = <path>
     176                 :         //
     177                 :         // or
     178                 :         //
     179                 :         // spec = <authority-no-port-or-password>/<path-with-colon>
     180                 :         // spec = <path-with-colon>
     181                 :         //
     182                 :         // or
     183                 :         //
     184                 :         // spec = <authority-no-port-or-password>
     185                 :         // spec = <path-no-slashes-or-colon>
     186                 :         //
     187          132562 :         SET_RESULT(scheme, 0, -1);
     188          132562 :         if (authorityLen || pathLen)
     189                 :             ParseAfterScheme(spec, specLen,
     190                 :                              authorityPos, authorityLen,
     191               3 :                              pathPos, pathLen);
     192          132562 :             OFFSET_RESULT(authority, offset);
     193          132562 :             OFFSET_RESULT(path, offset);
     194                 :     }
     195          485781 :     return NS_OK;
     196                 : }
     197                 : 
     198                 : NS_IMETHODIMP
     199               0 : nsBaseURLParser::ParseAuthority(const char *auth, PRInt32 authLen,
     200                 :                                 PRUint32 *usernamePos, PRInt32 *usernameLen,
     201                 :                                 PRUint32 *passwordPos, PRInt32 *passwordLen,
     202                 :                                 PRUint32 *hostnamePos, PRInt32 *hostnameLen,
     203                 :                                 PRInt32 *port)
     204                 : {
     205               0 :     NS_PRECONDITION(auth, "null pointer");
     206                 : 
     207               0 :     if (authLen < 0)
     208               0 :         authLen = strlen(auth);
     209                 : 
     210               0 :     SET_RESULT(username, 0, -1);
     211               0 :     SET_RESULT(password, 0, -1);
     212               0 :     SET_RESULT(hostname, 0, authLen);
     213               0 :     if (port)
     214               0 :        *port = -1;
     215               0 :     return NS_OK;
     216                 : }
     217                 : 
     218                 : NS_IMETHODIMP
     219               0 : nsBaseURLParser::ParseUserInfo(const char *userinfo, PRInt32 userinfoLen,
     220                 :                                PRUint32 *usernamePos, PRInt32 *usernameLen,
     221                 :                                PRUint32 *passwordPos, PRInt32 *passwordLen)
     222                 : {
     223               0 :     SET_RESULT(username, 0, -1);
     224               0 :     SET_RESULT(password, 0, -1);
     225               0 :     return NS_OK;
     226                 : }
     227                 : 
     228                 : NS_IMETHODIMP
     229               0 : nsBaseURLParser::ParseServerInfo(const char *serverinfo, PRInt32 serverinfoLen,
     230                 :                                  PRUint32 *hostnamePos, PRInt32 *hostnameLen,
     231                 :                                  PRInt32 *port)
     232                 : {
     233               0 :     SET_RESULT(hostname, 0, -1);
     234               0 :     if (port)
     235               0 :        *port = -1;
     236               0 :     return NS_OK;
     237                 : }
     238                 : 
     239                 : NS_IMETHODIMP
     240          349747 : nsBaseURLParser::ParsePath(const char *path, PRInt32 pathLen,
     241                 :                            PRUint32 *filepathPos, PRInt32 *filepathLen,
     242                 :                            PRUint32 *queryPos, PRInt32 *queryLen,
     243                 :                            PRUint32 *refPos, PRInt32 *refLen)
     244                 : {
     245          349747 :     NS_PRECONDITION(path, "null pointer");
     246                 : 
     247          349747 :     if (pathLen < 0)
     248               0 :         pathLen = strlen(path);
     249                 : 
     250                 :     // path = [/]<segment1>/<segment2>/<...>/<segmentN>?<query>#<ref>
     251                 : 
     252                 :     // XXX PL_strnpbrk would be nice, but it's buggy
     253                 : 
     254                 :     // search for first occurrence of either ? or #
     255          349747 :     const char *query_beg = 0, *query_end = 0;
     256          349747 :     const char *ref_beg = 0;
     257          349747 :     const char *p = 0;
     258        21904410 :     for (p = path; p < path + pathLen; ++p) {
     259                 :         // only match the query string if it precedes the reference fragment
     260        21555652 :         if (!ref_beg && !query_beg && *p == '?')
     261            2907 :             query_beg = p + 1;
     262        21552745 :         else if (*p == '#') {
     263             989 :             ref_beg = p + 1;
     264             989 :             if (query_beg)
     265             230 :                 query_end = p;
     266             989 :             break;
     267                 :         }
     268                 :     }
     269                 : 
     270          349747 :     if (query_beg) {
     271            2907 :         if (query_end)
     272             230 :             SET_RESULT(query, query_beg - path, query_end - query_beg);
     273                 :         else
     274            2677 :             SET_RESULT(query, query_beg - path, pathLen - (query_beg - path));
     275                 :     }
     276                 :     else
     277          346840 :         SET_RESULT(query, 0, -1);
     278                 : 
     279          349747 :     if (ref_beg)
     280             989 :         SET_RESULT(ref, ref_beg - path, pathLen - (ref_beg - path));
     281                 :     else
     282          348758 :         SET_RESULT(ref, 0, -1);
     283                 : 
     284                 :     const char *end;
     285          349747 :     if (query_beg)
     286            2907 :         end = query_beg - 1;
     287          346840 :     else if (ref_beg)
     288             759 :         end = ref_beg - 1;
     289                 :     else
     290          346081 :         end = path + pathLen;
     291                 : 
     292                 :     // an empty file path is no file path
     293          349747 :     if (end != path)
     294          349612 :         SET_RESULT(filepath, 0, end - path);
     295                 :     else
     296             135 :         SET_RESULT(filepath, 0, -1);
     297          349747 :     return NS_OK;
     298                 : }
     299                 : 
     300                 : NS_IMETHODIMP
     301          349629 : nsBaseURLParser::ParseFilePath(const char *filepath, PRInt32 filepathLen,
     302                 :                                PRUint32 *directoryPos, PRInt32 *directoryLen,
     303                 :                                PRUint32 *basenamePos, PRInt32 *basenameLen,
     304                 :                                PRUint32 *extensionPos, PRInt32 *extensionLen)
     305                 : {
     306          349629 :     NS_PRECONDITION(filepath, "null pointer");
     307                 : 
     308          349629 :     if (filepathLen < 0)
     309              17 :         filepathLen = strlen(filepath);
     310                 : 
     311          349629 :     if (filepathLen == 0) {
     312               0 :         SET_RESULT(directory, 0, -1);
     313               0 :         SET_RESULT(basename, 0, 0); // assume a zero length file basename
     314               0 :         SET_RESULT(extension, 0, -1);
     315               0 :         return NS_OK;
     316                 :     }
     317                 : 
     318                 :     const char *p;
     319          349629 :     const char *end = filepath + filepathLen;
     320                 : 
     321                 :     // search backwards for filename
     322          349629 :     for (p = end - 1; *p != '/' && p > filepath; --p)
     323                 :         ;
     324          349629 :     if (*p == '/') {
     325                 :         // catch /.. and /.
     326          349705 :         if ((p+1 < end && *(p+1) == '.') && 
     327              76 :            (p+2 == end || (*(p+2) == '.' && p+3 == end)))
     328               3 :             p = end - 1;
     329                 :         // filepath = <directory><filename>.<extension>
     330          349629 :         SET_RESULT(directory, 0, p - filepath + 1);
     331          349629 :         ParseFileName(p + 1, end - (p + 1),
     332                 :                       basenamePos, basenameLen,
     333          699258 :                       extensionPos, extensionLen);
     334          349629 :         OFFSET_RESULT(basename, p + 1 - filepath);
     335          349629 :         OFFSET_RESULT(extension, p + 1 - filepath);
     336                 :     }
     337                 :     else {
     338                 :         // filepath = <filename>.<extension>
     339               0 :         SET_RESULT(directory, 0, -1);
     340                 :         ParseFileName(filepath, filepathLen,
     341                 :                       basenamePos, basenameLen,
     342               0 :                       extensionPos, extensionLen);
     343                 :     }
     344          349629 :     return NS_OK;
     345                 : }
     346                 : 
     347                 : nsresult
     348          349629 : nsBaseURLParser::ParseFileName(const char *filename, PRInt32 filenameLen,
     349                 :                                PRUint32 *basenamePos, PRInt32 *basenameLen,
     350                 :                                PRUint32 *extensionPos, PRInt32 *extensionLen)
     351                 : {
     352          349629 :     NS_PRECONDITION(filename, "null pointer");
     353                 : 
     354          349629 :     if (filenameLen < 0)
     355               0 :         filenameLen = strlen(filename);
     356                 : 
     357                 :     // no extension if filename ends with a '.'
     358          349629 :     if (filename[filenameLen-1] != '.') {
     359                 :         // ignore '.' at the beginning
     360         1257422 :         for (const char *p = filename + filenameLen - 1; p > filename; --p) {
     361         1154895 :             if (*p == '.') {
     362                 :                 // filename = <basename.extension>
     363          247077 :                 SET_RESULT(basename, 0, p - filename);
     364          247077 :                 SET_RESULT(extension, p + 1 - filename, filenameLen - (p - filename + 1));
     365          247077 :                 return NS_OK;
     366                 :             }
     367                 :         }
     368                 :     }
     369                 :     // filename = <basename>
     370          102552 :     SET_RESULT(basename, 0, filenameLen);
     371          102552 :     SET_RESULT(extension, 0, -1);
     372          102552 :     return NS_OK;
     373                 : }
     374                 : 
     375                 : //----------------------------------------------------------------------------
     376                 : // nsNoAuthURLParser implementation
     377                 : //----------------------------------------------------------------------------
     378                 : 
     379                 : NS_IMETHODIMP
     380               0 : nsNoAuthURLParser::ParseAuthority(const char *auth, PRInt32 authLen,
     381                 :                                  PRUint32 *usernamePos, PRInt32 *usernameLen,
     382                 :                                  PRUint32 *passwordPos, PRInt32 *passwordLen,
     383                 :                                  PRUint32 *hostnamePos, PRInt32 *hostnameLen,
     384                 :                                  PRInt32 *port)
     385                 : {
     386               0 :     NS_NOTREACHED("Shouldn't parse auth in a NoAuthURL!");
     387               0 :     return NS_ERROR_UNEXPECTED;
     388                 : }
     389                 : 
     390                 : void
     391          205469 : nsNoAuthURLParser::ParseAfterScheme(const char *spec, PRInt32 specLen,
     392                 :                                     PRUint32 *authPos, PRInt32 *authLen,
     393                 :                                     PRUint32 *pathPos, PRInt32 *pathLen)
     394                 : {
     395          205469 :     NS_PRECONDITION(specLen >= 0, "unexpected");
     396                 : 
     397                 :     // everything is the path
     398          205469 :     PRUint32 pos = 0;
     399          205469 :     switch (CountConsecutiveSlashes(spec, specLen)) {
     400                 :     case 0:
     401                 :     case 1:
     402               0 :         break;
     403                 :     case 2:
     404                 :         {
     405              42 :             const char *p = nsnull;
     406              42 :             if (specLen > 2) {
     407                 :                 // looks like there is an authority section
     408                 : #if defined(XP_WIN) || defined(XP_OS2)
     409                 :                 // if the authority looks like a drive number then we
     410                 :                 // really want to treat it as part of the path
     411                 :                 // [a-zA-Z][:|]{/\}
     412                 :                 // i.e one of:   c:   c:\foo  c:/foo  c|  c|\foo  c|/foo
     413                 :                 if ((specLen > 3) && (spec[3] == ':' || spec[3] == '|') &&
     414                 :                     nsCRT::IsAsciiAlpha(spec[2]) &&
     415                 :                     ((specLen == 4) || (spec[4] == '/') || (spec[4] == '\\'))) {
     416                 :                     pos = 1;
     417                 :                     break;  
     418                 :                 } 
     419                 : #endif
     420                 :                 // Ignore apparent authority; path is everything after it
     421              57 :                 for (p = spec + 2; p < spec + specLen; ++p) {
     422              53 :                     if (*p == '/' || *p == '?' || *p == '#')
     423              17 :                         break;
     424                 :                 }
     425                 :             }
     426              42 :             SET_RESULT(auth, 0, -1);
     427              42 :             if (p && p != spec+specLen)
     428              17 :                 SET_RESULT(path, p - spec, specLen - (p - spec));
     429                 :             else
     430              25 :                 SET_RESULT(path, 0, -1);
     431              42 :             return;
     432                 :         }
     433                 :     default:
     434          205427 :         pos = 2;
     435          205427 :         break;
     436                 :     }
     437          205427 :     SET_RESULT(auth, pos, 0);
     438          205427 :     SET_RESULT(path, pos, specLen - pos);
     439                 : }
     440                 : 
     441                 : #if defined(XP_WIN) || defined(XP_OS2)
     442                 : NS_IMETHODIMP
     443                 : nsNoAuthURLParser::ParseFilePath(const char *filepath, PRInt32 filepathLen,
     444                 :                                  PRUint32 *directoryPos, PRInt32 *directoryLen,
     445                 :                                  PRUint32 *basenamePos, PRInt32 *basenameLen,
     446                 :                                  PRUint32 *extensionPos, PRInt32 *extensionLen)
     447                 : {
     448                 :     NS_PRECONDITION(filepath, "null pointer");
     449                 : 
     450                 :     if (filepathLen < 0)
     451                 :         filepathLen = strlen(filepath);
     452                 : 
     453                 :     // look for a filepath consisting of only a drive number, which may or
     454                 :     // may not have a leading slash.
     455                 :     if (filepathLen > 1 && filepathLen < 4) {
     456                 :         const char *end = filepath + filepathLen;
     457                 :         const char *p = filepath;
     458                 :         if (*p == '/')
     459                 :             p++;
     460                 :         if ((end-p == 2) && (p[1]==':' || p[1]=='|') && nsCRT::IsAsciiAlpha(*p)) {
     461                 :             // filepath = <drive-number>:
     462                 :             SET_RESULT(directory, 0, filepathLen);
     463                 :             SET_RESULT(basename, 0, -1);
     464                 :             SET_RESULT(extension, 0, -1);
     465                 :             return NS_OK;
     466                 :         }
     467                 :     }
     468                 : 
     469                 :     // otherwise fallback on common implementation
     470                 :     return nsBaseURLParser::ParseFilePath(filepath, filepathLen,
     471                 :                                           directoryPos, directoryLen,
     472                 :                                           basenamePos, basenameLen,
     473                 :                                           extensionPos, extensionLen);
     474                 : }
     475                 : #endif
     476                 : 
     477                 : //----------------------------------------------------------------------------
     478                 : // nsAuthURLParser implementation
     479                 : //----------------------------------------------------------------------------
     480                 : 
     481                 : NS_IMETHODIMP
     482          131525 : nsAuthURLParser::ParseAuthority(const char *auth, PRInt32 authLen,
     483                 :                                 PRUint32 *usernamePos, PRInt32 *usernameLen,
     484                 :                                 PRUint32 *passwordPos, PRInt32 *passwordLen,
     485                 :                                 PRUint32 *hostnamePos, PRInt32 *hostnameLen,
     486                 :                                 PRInt32 *port)
     487                 : {
     488                 :     nsresult rv;
     489                 : 
     490          131525 :     NS_PRECONDITION(auth, "null pointer");
     491                 : 
     492          131525 :     if (authLen < 0)
     493               0 :         authLen = strlen(auth);
     494                 : 
     495          131525 :     if (authLen == 0) {
     496               0 :         SET_RESULT(username, 0, -1);
     497               0 :         SET_RESULT(password, 0, -1);
     498               0 :         SET_RESULT(hostname, 0, 0);
     499               0 :         if (port)
     500               0 :             *port = -1;
     501               0 :         return NS_OK;
     502                 :     }
     503                 : 
     504                 :     // search backwards for @
     505          131525 :     const char *p = auth + authLen - 1;
     506          131525 :     for (; (*p != '@') && (p > auth); --p);
     507          131525 :     if ( *p == '@' ) {
     508                 :         // auth = <user-info@server-info>
     509                 :         rv = ParseUserInfo(auth, p - auth,
     510                 :                            usernamePos, usernameLen,
     511             194 :                            passwordPos, passwordLen);
     512             194 :         if (NS_FAILED(rv)) return rv;
     513                 :         rv = ParseServerInfo(p + 1, authLen - (p - auth + 1),
     514                 :                              hostnamePos, hostnameLen,
     515             194 :                              port);
     516             194 :         if (NS_FAILED(rv)) return rv;
     517             194 :         OFFSET_RESULT(hostname, p + 1 - auth);
     518                 :     }
     519                 :     else {
     520                 :         // auth = <server-info>
     521          131331 :         SET_RESULT(username, 0, -1);
     522          131331 :         SET_RESULT(password, 0, -1);
     523                 :         rv = ParseServerInfo(auth, authLen,
     524                 :                              hostnamePos, hostnameLen,
     525          131331 :                              port);
     526          131331 :         if (NS_FAILED(rv)) return rv;
     527                 :     }
     528          131481 :     return NS_OK;
     529                 : }
     530                 : 
     531                 : NS_IMETHODIMP
     532             194 : nsAuthURLParser::ParseUserInfo(const char *userinfo, PRInt32 userinfoLen,
     533                 :                                PRUint32 *usernamePos, PRInt32 *usernameLen,
     534                 :                                PRUint32 *passwordPos, PRInt32 *passwordLen)
     535                 : {
     536             194 :     NS_PRECONDITION(userinfo, "null pointer");
     537                 : 
     538             194 :     if (userinfoLen < 0)
     539               0 :         userinfoLen = strlen(userinfo);
     540                 : 
     541             194 :     if (userinfoLen == 0) {
     542               0 :         SET_RESULT(username, 0, -1);
     543               0 :         SET_RESULT(password, 0, -1);
     544               0 :         return NS_OK;
     545                 :     }
     546                 : 
     547             194 :     const char *p = (const char *) memchr(userinfo, ':', userinfoLen);
     548             194 :     if (p) {
     549                 :         // userinfo = <username:password>
     550             186 :         if (p == userinfo) {
     551                 :             // must have a username!
     552               0 :             return NS_ERROR_MALFORMED_URI;
     553                 :         }
     554             186 :         SET_RESULT(username, 0, p - userinfo);
     555             186 :         SET_RESULT(password, p - userinfo + 1, userinfoLen - (p - userinfo + 1));
     556                 :     }
     557                 :     else {
     558                 :         // userinfo = <username>
     559               8 :         SET_RESULT(username, 0, userinfoLen);
     560               8 :         SET_RESULT(password, 0, -1);
     561                 :     }
     562             194 :     return NS_OK;
     563                 : }
     564                 : 
     565                 : NS_IMETHODIMP
     566          131525 : nsAuthURLParser::ParseServerInfo(const char *serverinfo, PRInt32 serverinfoLen,
     567                 :                                  PRUint32 *hostnamePos, PRInt32 *hostnameLen,
     568                 :                                  PRInt32 *port)
     569                 : {
     570          131525 :     NS_PRECONDITION(serverinfo, "null pointer");
     571                 : 
     572          131525 :     if (serverinfoLen < 0)
     573               0 :         serverinfoLen = strlen(serverinfo);
     574                 : 
     575          131525 :     if (serverinfoLen == 0) {
     576              46 :         SET_RESULT(hostname, 0, 0);
     577              46 :         if (port)
     578              46 :             *port = -1;
     579              46 :         return NS_OK;
     580                 :     }
     581                 : 
     582                 :     // search backwards for a ':' but stop on ']' (IPv6 address literal
     583                 :     // delimiter).  check for illegal characters in the hostname.
     584          131479 :     const char *p = serverinfo + serverinfoLen - 1;
     585          131479 :     const char *colon = nsnull, *bracket = nsnull;
     586          969877 :     for (; p > serverinfo; --p) {
     587          838398 :         switch (*p) {
     588                 :             case ']':
     589             138 :                 bracket = p;
     590             138 :                 break;
     591                 :             case ':':
     592            6459 :                 if (bracket == nsnull)
     593            5844 :                     colon = p;
     594            6459 :                 break;
     595                 :             case ' ':
     596                 :                 // hostname must not contain a space
     597               0 :                 NS_WARNING("malformed hostname");
     598               0 :                 return NS_ERROR_MALFORMED_URI;
     599                 :         }
     600                 :     }
     601                 : 
     602          131479 :     if (colon) {
     603                 :         // serverinfo = <hostname:port>
     604            5842 :         SET_RESULT(hostname, 0, colon - serverinfo);
     605            5842 :         if (port) {
     606                 :             // XXX unfortunately ToInteger is not defined for substrings
     607           11684 :             nsCAutoString buf(colon+1, serverinfoLen - (colon + 1 - serverinfo));
     608            5842 :             if (buf.Length() == 0) {
     609               3 :                 *port = -1;
     610                 :             }
     611                 :             else {
     612            5839 :                 const char* nondigit = NS_strspnp("0123456789", buf.get());
     613            5839 :                 if (nondigit && *nondigit)
     614              12 :                     return NS_ERROR_MALFORMED_URI;
     615                 : 
     616                 :                 PRInt32 err;
     617            5827 :                 *port = buf.ToInteger(&err);
     618            5827 :                 if (NS_FAILED(err) || *port <= 0)
     619               5 :                     return NS_ERROR_MALFORMED_URI;
     620                 :             }
     621                 :         }
     622                 :     }
     623                 :     else {
     624                 :         // serverinfo = <hostname>
     625          125637 :         SET_RESULT(hostname, 0, serverinfoLen);
     626          125637 :         if (port)
     627          125637 :            *port = -1;
     628                 :     }
     629                 : 
     630                 :     // In case of IPv6 address check its validity
     631          131738 :     if (*hostnameLen > 1 && *(serverinfo + *hostnamePos) == '[' &&
     632             138 :         *(serverinfo + *hostnamePos + *hostnameLen - 1) == ']' &&
     633             138 :         !net_IsValidIPv6Addr(serverinfo + *hostnamePos + 1, *hostnameLen - 2))
     634              27 :             return NS_ERROR_MALFORMED_URI;
     635                 : 
     636          131435 :     return NS_OK;
     637                 : }
     638                 : 
     639                 : void
     640           35728 : nsAuthURLParser::ParseAfterScheme(const char *spec, PRInt32 specLen,
     641                 :                                   PRUint32 *authPos, PRInt32 *authLen,
     642                 :                                   PRUint32 *pathPos, PRInt32 *pathLen)
     643                 : {
     644           35728 :     NS_PRECONDITION(specLen >= 0, "unexpected");
     645                 : 
     646           35728 :     PRUint32 nslash = CountConsecutiveSlashes(spec, specLen);
     647                 : 
     648                 :     // search for the end of the authority section
     649           35728 :     const char *end = spec + specLen;
     650                 :     const char *p;
     651          414464 :     for (p = spec + nslash; p < end; ++p) {
     652          411157 :         if (*p == '/' || *p == '?' || *p == '#')
     653           32421 :             break;
     654                 :     }
     655           35728 :     if (p < end) {
     656                 :         // spec = [/]<auth><path>
     657           32421 :         SET_RESULT(auth, nslash, p - (spec + nslash));
     658           32421 :         SET_RESULT(path, p - spec, specLen - (p - spec));
     659                 :     }
     660                 :     else {
     661                 :         // spec = [/]<auth>
     662            3307 :         SET_RESULT(auth, nslash, specLen - nslash);
     663            3307 :         SET_RESULT(path, 0, -1);
     664                 :     }
     665           35728 : }
     666                 : 
     667                 : //----------------------------------------------------------------------------
     668                 : // nsStdURLParser implementation
     669                 : //----------------------------------------------------------------------------
     670                 : 
     671                 : void
     672          111954 : nsStdURLParser::ParseAfterScheme(const char *spec, PRInt32 specLen,
     673                 :                                  PRUint32 *authPos, PRInt32 *authLen,
     674                 :                                  PRUint32 *pathPos, PRInt32 *pathLen)
     675                 : {
     676          111954 :     NS_PRECONDITION(specLen >= 0, "unexpected");
     677                 : 
     678          111954 :     PRUint32 nslash = CountConsecutiveSlashes(spec, specLen);
     679                 : 
     680                 :     // search for the end of the authority section
     681          111954 :     const char *end = spec + specLen;
     682                 :     const char *p;
     683          781867 :     for (p = spec + nslash; p < end; ++p) {
     684          781817 :         if (strchr("/?#;", *p))
     685          111904 :             break;
     686                 :     }
     687          111954 :     switch (nslash) {
     688                 :     case 0:
     689                 :     case 2:
     690           96045 :         if (p < end) {
     691                 :             // spec = (//)<auth><path>
     692           96001 :             SET_RESULT(auth, nslash, p - (spec + nslash));
     693           96001 :             SET_RESULT(path, p - spec, specLen - (p - spec));
     694                 :         }
     695                 :         else {
     696                 :             // spec = (//)<auth>
     697              44 :             SET_RESULT(auth, nslash, specLen - nslash);
     698              44 :             SET_RESULT(path, 0, -1);
     699                 :         }
     700           96045 :         break;
     701                 :     case 1:
     702                 :         // spec = /<path>
     703               0 :         SET_RESULT(auth, 0, -1);
     704               0 :         SET_RESULT(path, 0, specLen);
     705               0 :         break;
     706                 :     default:
     707                 :         // spec = ///[/]<path>
     708           15909 :         SET_RESULT(auth, 2, 0);
     709           15909 :         SET_RESULT(path, 2, specLen - 2);
     710                 :     }
     711          111954 : }

Generated by: LCOV version 1.7