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