LCOV - code coverage report
Current view: top level - netwerk/base - nsURLParsers.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 182 299 60.9 %
Date: 2017-07-14 16:53:18 Functions: 17 21 81.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13