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 : }
|