1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/base/src/nsURLParsers.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,676 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include <string.h> 1.10 + 1.11 +#include "mozilla/RangedPtr.h" 1.12 + 1.13 +#include "nsURLParsers.h" 1.14 +#include "nsURLHelper.h" 1.15 +#include "nsString.h" 1.16 +#include "nsCRT.h" 1.17 + 1.18 +using namespace mozilla; 1.19 + 1.20 +//---------------------------------------------------------------------------- 1.21 + 1.22 +static uint32_t 1.23 +CountConsecutiveSlashes(const char *str, int32_t len) 1.24 +{ 1.25 + RangedPtr<const char> p(str, len); 1.26 + uint32_t count = 0; 1.27 + while (len-- && *p++ == '/') ++count; 1.28 + return count; 1.29 +} 1.30 + 1.31 +//---------------------------------------------------------------------------- 1.32 +// nsBaseURLParser implementation 1.33 +//---------------------------------------------------------------------------- 1.34 + 1.35 +NS_IMPL_ISUPPORTS(nsAuthURLParser, nsIURLParser) 1.36 +NS_IMPL_ISUPPORTS(nsNoAuthURLParser, nsIURLParser) 1.37 + 1.38 +#define SET_RESULT(component, pos, len) \ 1.39 + PR_BEGIN_MACRO \ 1.40 + if (component ## Pos) \ 1.41 + *component ## Pos = uint32_t(pos); \ 1.42 + if (component ## Len) \ 1.43 + *component ## Len = int32_t(len); \ 1.44 + PR_END_MACRO 1.45 + 1.46 +#define OFFSET_RESULT(component, offset) \ 1.47 + PR_BEGIN_MACRO \ 1.48 + if (component ## Pos) \ 1.49 + *component ## Pos += offset; \ 1.50 + PR_END_MACRO 1.51 + 1.52 +NS_IMETHODIMP 1.53 +nsBaseURLParser::ParseURL(const char *spec, int32_t specLen, 1.54 + uint32_t *schemePos, int32_t *schemeLen, 1.55 + uint32_t *authorityPos, int32_t *authorityLen, 1.56 + uint32_t *pathPos, int32_t *pathLen) 1.57 +{ 1.58 + NS_PRECONDITION(spec, "null pointer"); 1.59 + 1.60 + if (specLen < 0) 1.61 + specLen = strlen(spec); 1.62 + 1.63 + const char *stop = nullptr; 1.64 + const char *colon = nullptr; 1.65 + const char *slash = nullptr; 1.66 + const char *p; 1.67 + uint32_t offset = 0; 1.68 + int32_t len = specLen; 1.69 + for (p = spec; len && *p && !colon && !slash; ++p, --len) { 1.70 + // skip leading whitespace 1.71 + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') { 1.72 + spec++; 1.73 + specLen--; 1.74 + offset++; 1.75 + continue; 1.76 + } 1.77 + switch (*p) { 1.78 + case ':': 1.79 + if (!colon) 1.80 + colon = p; 1.81 + break; 1.82 + case '/': // start of filepath 1.83 + case '?': // start of query 1.84 + case '#': // start of ref 1.85 + if (!slash) 1.86 + slash = p; 1.87 + break; 1.88 + case '@': // username@hostname 1.89 + case '[': // start of IPv6 address literal 1.90 + if (!stop) 1.91 + stop = p; 1.92 + break; 1.93 + } 1.94 + } 1.95 + // disregard the first colon if it follows an '@' or a '[' 1.96 + if (colon && stop && colon > stop) 1.97 + colon = nullptr; 1.98 + 1.99 + // if the spec only contained whitespace ... 1.100 + if (specLen == 0) { 1.101 + SET_RESULT(scheme, 0, -1); 1.102 + SET_RESULT(authority, 0, 0); 1.103 + SET_RESULT(path, 0, 0); 1.104 + return NS_OK; 1.105 + } 1.106 + 1.107 + // ignore trailing whitespace and control characters 1.108 + for (p = spec + specLen - 1; ((unsigned char) *p <= ' ') && (p != spec); --p) 1.109 + ; 1.110 + 1.111 + specLen = p - spec + 1; 1.112 + 1.113 + if (colon && (colon < slash || !slash)) { 1.114 + // 1.115 + // spec = <scheme>:/<the-rest> 1.116 + // 1.117 + // or 1.118 + // 1.119 + // spec = <scheme>:<authority> 1.120 + // spec = <scheme>:<path-no-slashes> 1.121 + // 1.122 + if (!net_IsValidScheme(spec, colon - spec) || (*(colon+1) == ':')) { 1.123 + NS_WARNING("malformed uri"); 1.124 + return NS_ERROR_MALFORMED_URI; 1.125 + } 1.126 + SET_RESULT(scheme, offset, colon - spec); 1.127 + if (authorityLen || pathLen) { 1.128 + uint32_t schemeLen = colon + 1 - spec; 1.129 + offset += schemeLen; 1.130 + ParseAfterScheme(colon + 1, specLen - schemeLen, 1.131 + authorityPos, authorityLen, 1.132 + pathPos, pathLen); 1.133 + OFFSET_RESULT(authority, offset); 1.134 + OFFSET_RESULT(path, offset); 1.135 + } 1.136 + } 1.137 + else { 1.138 + // 1.139 + // spec = <authority-no-port-or-password>/<path> 1.140 + // spec = <path> 1.141 + // 1.142 + // or 1.143 + // 1.144 + // spec = <authority-no-port-or-password>/<path-with-colon> 1.145 + // spec = <path-with-colon> 1.146 + // 1.147 + // or 1.148 + // 1.149 + // spec = <authority-no-port-or-password> 1.150 + // spec = <path-no-slashes-or-colon> 1.151 + // 1.152 + SET_RESULT(scheme, 0, -1); 1.153 + if (authorityLen || pathLen) { 1.154 + ParseAfterScheme(spec, specLen, 1.155 + authorityPos, authorityLen, 1.156 + pathPos, pathLen); 1.157 + OFFSET_RESULT(authority, offset); 1.158 + OFFSET_RESULT(path, offset); 1.159 + } 1.160 + } 1.161 + return NS_OK; 1.162 +} 1.163 + 1.164 +NS_IMETHODIMP 1.165 +nsBaseURLParser::ParseAuthority(const char *auth, int32_t authLen, 1.166 + uint32_t *usernamePos, int32_t *usernameLen, 1.167 + uint32_t *passwordPos, int32_t *passwordLen, 1.168 + uint32_t *hostnamePos, int32_t *hostnameLen, 1.169 + int32_t *port) 1.170 +{ 1.171 + NS_PRECONDITION(auth, "null pointer"); 1.172 + 1.173 + if (authLen < 0) 1.174 + authLen = strlen(auth); 1.175 + 1.176 + SET_RESULT(username, 0, -1); 1.177 + SET_RESULT(password, 0, -1); 1.178 + SET_RESULT(hostname, 0, authLen); 1.179 + if (port) 1.180 + *port = -1; 1.181 + return NS_OK; 1.182 +} 1.183 + 1.184 +NS_IMETHODIMP 1.185 +nsBaseURLParser::ParseUserInfo(const char *userinfo, int32_t userinfoLen, 1.186 + uint32_t *usernamePos, int32_t *usernameLen, 1.187 + uint32_t *passwordPos, int32_t *passwordLen) 1.188 +{ 1.189 + SET_RESULT(username, 0, -1); 1.190 + SET_RESULT(password, 0, -1); 1.191 + return NS_OK; 1.192 +} 1.193 + 1.194 +NS_IMETHODIMP 1.195 +nsBaseURLParser::ParseServerInfo(const char *serverinfo, int32_t serverinfoLen, 1.196 + uint32_t *hostnamePos, int32_t *hostnameLen, 1.197 + int32_t *port) 1.198 +{ 1.199 + SET_RESULT(hostname, 0, -1); 1.200 + if (port) 1.201 + *port = -1; 1.202 + return NS_OK; 1.203 +} 1.204 + 1.205 +NS_IMETHODIMP 1.206 +nsBaseURLParser::ParsePath(const char *path, int32_t pathLen, 1.207 + uint32_t *filepathPos, int32_t *filepathLen, 1.208 + uint32_t *queryPos, int32_t *queryLen, 1.209 + uint32_t *refPos, int32_t *refLen) 1.210 +{ 1.211 + NS_PRECONDITION(path, "null pointer"); 1.212 + 1.213 + if (pathLen < 0) 1.214 + pathLen = strlen(path); 1.215 + 1.216 + // path = [/]<segment1>/<segment2>/<...>/<segmentN>?<query>#<ref> 1.217 + 1.218 + // XXX PL_strnpbrk would be nice, but it's buggy 1.219 + 1.220 + // search for first occurrence of either ? or # 1.221 + const char *query_beg = 0, *query_end = 0; 1.222 + const char *ref_beg = 0; 1.223 + const char *p = 0; 1.224 + for (p = path; p < path + pathLen; ++p) { 1.225 + // only match the query string if it precedes the reference fragment 1.226 + if (!ref_beg && !query_beg && *p == '?') 1.227 + query_beg = p + 1; 1.228 + else if (*p == '#') { 1.229 + ref_beg = p + 1; 1.230 + if (query_beg) 1.231 + query_end = p; 1.232 + break; 1.233 + } 1.234 + } 1.235 + 1.236 + if (query_beg) { 1.237 + if (query_end) 1.238 + SET_RESULT(query, query_beg - path, query_end - query_beg); 1.239 + else 1.240 + SET_RESULT(query, query_beg - path, pathLen - (query_beg - path)); 1.241 + } 1.242 + else 1.243 + SET_RESULT(query, 0, -1); 1.244 + 1.245 + if (ref_beg) 1.246 + SET_RESULT(ref, ref_beg - path, pathLen - (ref_beg - path)); 1.247 + else 1.248 + SET_RESULT(ref, 0, -1); 1.249 + 1.250 + const char *end; 1.251 + if (query_beg) 1.252 + end = query_beg - 1; 1.253 + else if (ref_beg) 1.254 + end = ref_beg - 1; 1.255 + else 1.256 + end = path + pathLen; 1.257 + 1.258 + // an empty file path is no file path 1.259 + if (end != path) 1.260 + SET_RESULT(filepath, 0, end - path); 1.261 + else 1.262 + SET_RESULT(filepath, 0, -1); 1.263 + return NS_OK; 1.264 +} 1.265 + 1.266 +NS_IMETHODIMP 1.267 +nsBaseURLParser::ParseFilePath(const char *filepath, int32_t filepathLen, 1.268 + uint32_t *directoryPos, int32_t *directoryLen, 1.269 + uint32_t *basenamePos, int32_t *basenameLen, 1.270 + uint32_t *extensionPos, int32_t *extensionLen) 1.271 +{ 1.272 + NS_PRECONDITION(filepath, "null pointer"); 1.273 + 1.274 + if (filepathLen < 0) 1.275 + filepathLen = strlen(filepath); 1.276 + 1.277 + if (filepathLen == 0) { 1.278 + SET_RESULT(directory, 0, -1); 1.279 + SET_RESULT(basename, 0, 0); // assume a zero length file basename 1.280 + SET_RESULT(extension, 0, -1); 1.281 + return NS_OK; 1.282 + } 1.283 + 1.284 + const char *p; 1.285 + const char *end = filepath + filepathLen; 1.286 + 1.287 + // search backwards for filename 1.288 + for (p = end - 1; *p != '/' && p > filepath; --p) 1.289 + ; 1.290 + if (*p == '/') { 1.291 + // catch /.. and /. 1.292 + if ((p+1 < end && *(p+1) == '.') && 1.293 + (p+2 == end || (*(p+2) == '.' && p+3 == end))) 1.294 + p = end - 1; 1.295 + // filepath = <directory><filename>.<extension> 1.296 + SET_RESULT(directory, 0, p - filepath + 1); 1.297 + ParseFileName(p + 1, end - (p + 1), 1.298 + basenamePos, basenameLen, 1.299 + extensionPos, extensionLen); 1.300 + OFFSET_RESULT(basename, p + 1 - filepath); 1.301 + OFFSET_RESULT(extension, p + 1 - filepath); 1.302 + } 1.303 + else { 1.304 + // filepath = <filename>.<extension> 1.305 + SET_RESULT(directory, 0, -1); 1.306 + ParseFileName(filepath, filepathLen, 1.307 + basenamePos, basenameLen, 1.308 + extensionPos, extensionLen); 1.309 + } 1.310 + return NS_OK; 1.311 +} 1.312 + 1.313 +nsresult 1.314 +nsBaseURLParser::ParseFileName(const char *filename, int32_t filenameLen, 1.315 + uint32_t *basenamePos, int32_t *basenameLen, 1.316 + uint32_t *extensionPos, int32_t *extensionLen) 1.317 +{ 1.318 + NS_PRECONDITION(filename, "null pointer"); 1.319 + 1.320 + if (filenameLen < 0) 1.321 + filenameLen = strlen(filename); 1.322 + 1.323 + // no extension if filename ends with a '.' 1.324 + if (filename[filenameLen-1] != '.') { 1.325 + // ignore '.' at the beginning 1.326 + for (const char *p = filename + filenameLen - 1; p > filename; --p) { 1.327 + if (*p == '.') { 1.328 + // filename = <basename.extension> 1.329 + SET_RESULT(basename, 0, p - filename); 1.330 + SET_RESULT(extension, p + 1 - filename, filenameLen - (p - filename + 1)); 1.331 + return NS_OK; 1.332 + } 1.333 + } 1.334 + } 1.335 + // filename = <basename> 1.336 + SET_RESULT(basename, 0, filenameLen); 1.337 + SET_RESULT(extension, 0, -1); 1.338 + return NS_OK; 1.339 +} 1.340 + 1.341 +//---------------------------------------------------------------------------- 1.342 +// nsNoAuthURLParser implementation 1.343 +//---------------------------------------------------------------------------- 1.344 + 1.345 +NS_IMETHODIMP 1.346 +nsNoAuthURLParser::ParseAuthority(const char *auth, int32_t authLen, 1.347 + uint32_t *usernamePos, int32_t *usernameLen, 1.348 + uint32_t *passwordPos, int32_t *passwordLen, 1.349 + uint32_t *hostnamePos, int32_t *hostnameLen, 1.350 + int32_t *port) 1.351 +{ 1.352 + NS_NOTREACHED("Shouldn't parse auth in a NoAuthURL!"); 1.353 + return NS_ERROR_UNEXPECTED; 1.354 +} 1.355 + 1.356 +void 1.357 +nsNoAuthURLParser::ParseAfterScheme(const char *spec, int32_t specLen, 1.358 + uint32_t *authPos, int32_t *authLen, 1.359 + uint32_t *pathPos, int32_t *pathLen) 1.360 +{ 1.361 + NS_PRECONDITION(specLen >= 0, "unexpected"); 1.362 + 1.363 + // everything is the path 1.364 + uint32_t pos = 0; 1.365 + switch (CountConsecutiveSlashes(spec, specLen)) { 1.366 + case 0: 1.367 + case 1: 1.368 + break; 1.369 + case 2: 1.370 + { 1.371 + const char *p = nullptr; 1.372 + if (specLen > 2) { 1.373 + // looks like there is an authority section 1.374 +#if defined(XP_WIN) 1.375 + // if the authority looks like a drive number then we 1.376 + // really want to treat it as part of the path 1.377 + // [a-zA-Z][:|]{/\} 1.378 + // i.e one of: c: c:\foo c:/foo c| c|\foo c|/foo 1.379 + if ((specLen > 3) && (spec[3] == ':' || spec[3] == '|') && 1.380 + nsCRT::IsAsciiAlpha(spec[2]) && 1.381 + ((specLen == 4) || (spec[4] == '/') || (spec[4] == '\\'))) { 1.382 + pos = 1; 1.383 + break; 1.384 + } 1.385 +#endif 1.386 + // Ignore apparent authority; path is everything after it 1.387 + for (p = spec + 2; p < spec + specLen; ++p) { 1.388 + if (*p == '/' || *p == '?' || *p == '#') 1.389 + break; 1.390 + } 1.391 + } 1.392 + SET_RESULT(auth, 0, -1); 1.393 + if (p && p != spec+specLen) 1.394 + SET_RESULT(path, p - spec, specLen - (p - spec)); 1.395 + else 1.396 + SET_RESULT(path, 0, -1); 1.397 + return; 1.398 + } 1.399 + default: 1.400 + pos = 2; 1.401 + break; 1.402 + } 1.403 + SET_RESULT(auth, pos, 0); 1.404 + SET_RESULT(path, pos, specLen - pos); 1.405 +} 1.406 + 1.407 +#if defined(XP_WIN) 1.408 +NS_IMETHODIMP 1.409 +nsNoAuthURLParser::ParseFilePath(const char *filepath, int32_t filepathLen, 1.410 + uint32_t *directoryPos, int32_t *directoryLen, 1.411 + uint32_t *basenamePos, int32_t *basenameLen, 1.412 + uint32_t *extensionPos, int32_t *extensionLen) 1.413 +{ 1.414 + NS_PRECONDITION(filepath, "null pointer"); 1.415 + 1.416 + if (filepathLen < 0) 1.417 + filepathLen = strlen(filepath); 1.418 + 1.419 + // look for a filepath consisting of only a drive number, which may or 1.420 + // may not have a leading slash. 1.421 + if (filepathLen > 1 && filepathLen < 4) { 1.422 + const char *end = filepath + filepathLen; 1.423 + const char *p = filepath; 1.424 + if (*p == '/') 1.425 + p++; 1.426 + if ((end-p == 2) && (p[1]==':' || p[1]=='|') && nsCRT::IsAsciiAlpha(*p)) { 1.427 + // filepath = <drive-number>: 1.428 + SET_RESULT(directory, 0, filepathLen); 1.429 + SET_RESULT(basename, 0, -1); 1.430 + SET_RESULT(extension, 0, -1); 1.431 + return NS_OK; 1.432 + } 1.433 + } 1.434 + 1.435 + // otherwise fallback on common implementation 1.436 + return nsBaseURLParser::ParseFilePath(filepath, filepathLen, 1.437 + directoryPos, directoryLen, 1.438 + basenamePos, basenameLen, 1.439 + extensionPos, extensionLen); 1.440 +} 1.441 +#endif 1.442 + 1.443 +//---------------------------------------------------------------------------- 1.444 +// nsAuthURLParser implementation 1.445 +//---------------------------------------------------------------------------- 1.446 + 1.447 +NS_IMETHODIMP 1.448 +nsAuthURLParser::ParseAuthority(const char *auth, int32_t authLen, 1.449 + uint32_t *usernamePos, int32_t *usernameLen, 1.450 + uint32_t *passwordPos, int32_t *passwordLen, 1.451 + uint32_t *hostnamePos, int32_t *hostnameLen, 1.452 + int32_t *port) 1.453 +{ 1.454 + nsresult rv; 1.455 + 1.456 + NS_PRECONDITION(auth, "null pointer"); 1.457 + 1.458 + if (authLen < 0) 1.459 + authLen = strlen(auth); 1.460 + 1.461 + if (authLen == 0) { 1.462 + SET_RESULT(username, 0, -1); 1.463 + SET_RESULT(password, 0, -1); 1.464 + SET_RESULT(hostname, 0, 0); 1.465 + if (port) 1.466 + *port = -1; 1.467 + return NS_OK; 1.468 + } 1.469 + 1.470 + // search backwards for @ 1.471 + const char *p = auth + authLen - 1; 1.472 + for (; (*p != '@') && (p > auth); --p) { 1.473 + continue; 1.474 + } 1.475 + if ( *p == '@' ) { 1.476 + // auth = <user-info@server-info> 1.477 + rv = ParseUserInfo(auth, p - auth, 1.478 + usernamePos, usernameLen, 1.479 + passwordPos, passwordLen); 1.480 + if (NS_FAILED(rv)) return rv; 1.481 + rv = ParseServerInfo(p + 1, authLen - (p - auth + 1), 1.482 + hostnamePos, hostnameLen, 1.483 + port); 1.484 + if (NS_FAILED(rv)) return rv; 1.485 + OFFSET_RESULT(hostname, p + 1 - auth); 1.486 + } 1.487 + else { 1.488 + // auth = <server-info> 1.489 + SET_RESULT(username, 0, -1); 1.490 + SET_RESULT(password, 0, -1); 1.491 + rv = ParseServerInfo(auth, authLen, 1.492 + hostnamePos, hostnameLen, 1.493 + port); 1.494 + if (NS_FAILED(rv)) return rv; 1.495 + } 1.496 + return NS_OK; 1.497 +} 1.498 + 1.499 +NS_IMETHODIMP 1.500 +nsAuthURLParser::ParseUserInfo(const char *userinfo, int32_t userinfoLen, 1.501 + uint32_t *usernamePos, int32_t *usernameLen, 1.502 + uint32_t *passwordPos, int32_t *passwordLen) 1.503 +{ 1.504 + NS_PRECONDITION(userinfo, "null pointer"); 1.505 + 1.506 + if (userinfoLen < 0) 1.507 + userinfoLen = strlen(userinfo); 1.508 + 1.509 + if (userinfoLen == 0) { 1.510 + SET_RESULT(username, 0, -1); 1.511 + SET_RESULT(password, 0, -1); 1.512 + return NS_OK; 1.513 + } 1.514 + 1.515 + const char *p = (const char *) memchr(userinfo, ':', userinfoLen); 1.516 + if (p) { 1.517 + // userinfo = <username:password> 1.518 + if (p == userinfo) { 1.519 + // must have a username! 1.520 + return NS_ERROR_MALFORMED_URI; 1.521 + } 1.522 + SET_RESULT(username, 0, p - userinfo); 1.523 + SET_RESULT(password, p - userinfo + 1, userinfoLen - (p - userinfo + 1)); 1.524 + } 1.525 + else { 1.526 + // userinfo = <username> 1.527 + SET_RESULT(username, 0, userinfoLen); 1.528 + SET_RESULT(password, 0, -1); 1.529 + } 1.530 + return NS_OK; 1.531 +} 1.532 + 1.533 +NS_IMETHODIMP 1.534 +nsAuthURLParser::ParseServerInfo(const char *serverinfo, int32_t serverinfoLen, 1.535 + uint32_t *hostnamePos, int32_t *hostnameLen, 1.536 + int32_t *port) 1.537 +{ 1.538 + NS_PRECONDITION(serverinfo, "null pointer"); 1.539 + 1.540 + if (serverinfoLen < 0) 1.541 + serverinfoLen = strlen(serverinfo); 1.542 + 1.543 + if (serverinfoLen == 0) { 1.544 + SET_RESULT(hostname, 0, 0); 1.545 + if (port) 1.546 + *port = -1; 1.547 + return NS_OK; 1.548 + } 1.549 + 1.550 + // search backwards for a ':' but stop on ']' (IPv6 address literal 1.551 + // delimiter). check for illegal characters in the hostname. 1.552 + const char *p = serverinfo + serverinfoLen - 1; 1.553 + const char *colon = nullptr, *bracket = nullptr; 1.554 + for (; p > serverinfo; --p) { 1.555 + switch (*p) { 1.556 + case ']': 1.557 + bracket = p; 1.558 + break; 1.559 + case ':': 1.560 + if (bracket == nullptr) 1.561 + colon = p; 1.562 + break; 1.563 + case ' ': 1.564 + // hostname must not contain a space 1.565 + NS_WARNING("malformed hostname"); 1.566 + return NS_ERROR_MALFORMED_URI; 1.567 + } 1.568 + } 1.569 + 1.570 + if (colon) { 1.571 + // serverinfo = <hostname:port> 1.572 + SET_RESULT(hostname, 0, colon - serverinfo); 1.573 + if (port) { 1.574 + // XXX unfortunately ToInteger is not defined for substrings 1.575 + nsAutoCString buf(colon+1, serverinfoLen - (colon + 1 - serverinfo)); 1.576 + if (buf.Length() == 0) { 1.577 + *port = -1; 1.578 + } 1.579 + else { 1.580 + const char* nondigit = NS_strspnp("0123456789", buf.get()); 1.581 + if (nondigit && *nondigit) 1.582 + return NS_ERROR_MALFORMED_URI; 1.583 + 1.584 + nsresult err; 1.585 + *port = buf.ToInteger(&err); 1.586 + if (NS_FAILED(err) || *port < 0) 1.587 + return NS_ERROR_MALFORMED_URI; 1.588 + } 1.589 + } 1.590 + } 1.591 + else { 1.592 + // serverinfo = <hostname> 1.593 + SET_RESULT(hostname, 0, serverinfoLen); 1.594 + if (port) 1.595 + *port = -1; 1.596 + } 1.597 + 1.598 + // In case of IPv6 address check its validity 1.599 + if (*hostnameLen > 1 && *(serverinfo + *hostnamePos) == '[' && 1.600 + *(serverinfo + *hostnamePos + *hostnameLen - 1) == ']' && 1.601 + !net_IsValidIPv6Addr(serverinfo + *hostnamePos + 1, *hostnameLen - 2)) 1.602 + return NS_ERROR_MALFORMED_URI; 1.603 + 1.604 + return NS_OK; 1.605 +} 1.606 + 1.607 +void 1.608 +nsAuthURLParser::ParseAfterScheme(const char *spec, int32_t specLen, 1.609 + uint32_t *authPos, int32_t *authLen, 1.610 + uint32_t *pathPos, int32_t *pathLen) 1.611 +{ 1.612 + NS_PRECONDITION(specLen >= 0, "unexpected"); 1.613 + 1.614 + uint32_t nslash = CountConsecutiveSlashes(spec, specLen); 1.615 + 1.616 + // search for the end of the authority section 1.617 + const char *end = spec + specLen; 1.618 + const char *p; 1.619 + for (p = spec + nslash; p < end; ++p) { 1.620 + if (*p == '/' || *p == '?' || *p == '#') 1.621 + break; 1.622 + } 1.623 + if (p < end) { 1.624 + // spec = [/]<auth><path> 1.625 + SET_RESULT(auth, nslash, p - (spec + nslash)); 1.626 + SET_RESULT(path, p - spec, specLen - (p - spec)); 1.627 + } 1.628 + else { 1.629 + // spec = [/]<auth> 1.630 + SET_RESULT(auth, nslash, specLen - nslash); 1.631 + SET_RESULT(path, 0, -1); 1.632 + } 1.633 +} 1.634 + 1.635 +//---------------------------------------------------------------------------- 1.636 +// nsStdURLParser implementation 1.637 +//---------------------------------------------------------------------------- 1.638 + 1.639 +void 1.640 +nsStdURLParser::ParseAfterScheme(const char *spec, int32_t specLen, 1.641 + uint32_t *authPos, int32_t *authLen, 1.642 + uint32_t *pathPos, int32_t *pathLen) 1.643 +{ 1.644 + NS_PRECONDITION(specLen >= 0, "unexpected"); 1.645 + 1.646 + uint32_t nslash = CountConsecutiveSlashes(spec, specLen); 1.647 + 1.648 + // search for the end of the authority section 1.649 + const char *end = spec + specLen; 1.650 + const char *p; 1.651 + for (p = spec + nslash; p < end; ++p) { 1.652 + if (strchr("/?#;", *p)) 1.653 + break; 1.654 + } 1.655 + switch (nslash) { 1.656 + case 0: 1.657 + case 2: 1.658 + if (p < end) { 1.659 + // spec = (//)<auth><path> 1.660 + SET_RESULT(auth, nslash, p - (spec + nslash)); 1.661 + SET_RESULT(path, p - spec, specLen - (p - spec)); 1.662 + } 1.663 + else { 1.664 + // spec = (//)<auth> 1.665 + SET_RESULT(auth, nslash, specLen - nslash); 1.666 + SET_RESULT(path, 0, -1); 1.667 + } 1.668 + break; 1.669 + case 1: 1.670 + // spec = /<path> 1.671 + SET_RESULT(auth, 0, -1); 1.672 + SET_RESULT(path, 0, specLen); 1.673 + break; 1.674 + default: 1.675 + // spec = ///[/]<path> 1.676 + SET_RESULT(auth, 2, 0); 1.677 + SET_RESULT(path, 2, specLen - 2); 1.678 + } 1.679 +}