netwerk/base/src/nsURLParsers.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial