Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/base/nsURLParsers.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "mozilla/TextUtils.h"
10
11
#include "nsURLParsers.h"
12
#include "nsURLHelper.h"
13
#include "nsString.h"
14
15
using namespace mozilla;
16
17
//----------------------------------------------------------------------------
18
19
static uint32_t
20
CountConsecutiveSlashes(const char *str, int32_t len)
21
1.12M
{
22
1.12M
    RangedPtr<const char> p(str, len);
23
1.12M
    uint32_t count = 0;
24
3.29M
    while (len-- && *p++ == '/') ++count;
25
1.12M
    return count;
26
1.12M
}
27
28
//----------------------------------------------------------------------------
29
// nsBaseURLParser implementation
30
//----------------------------------------------------------------------------
31
32
NS_IMPL_ISUPPORTS(nsAuthURLParser, nsIURLParser)
33
NS_IMPL_ISUPPORTS(nsNoAuthURLParser, nsIURLParser)
34
35
#define SET_RESULT(component, pos, len) \
36
21.0M
    PR_BEGIN_MACRO \
37
20.1M
        if (component ## Pos) \
38
20.1M
           *component ## Pos = uint32_t(pos); \
39
20.1M
        if (component ## Len) \
40
20.1M
           *component ## Len = int32_t(len); \
41
20.1M
    PR_END_MACRO
42
43
#define OFFSET_RESULT(component, offset) \
44
4.39M
    PR_BEGIN_MACRO \
45
4.39M
        if (component ## Pos) \
46
4.39M
           *component ## Pos += offset; \
47
4.39M
    PR_END_MACRO
48
49
NS_IMETHODIMP
50
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
3.86M
{
55
3.86M
    if (NS_WARN_IF(!spec)) {
56
0
        return NS_ERROR_INVALID_POINTER;
57
0
    }
58
3.86M
59
3.86M
    if (specLen < 0)
60
0
        specLen = strlen(spec);
61
3.86M
62
3.86M
    const char *stop = nullptr;
63
3.86M
    const char *colon = nullptr;
64
3.86M
    const char *slash = nullptr;
65
3.86M
    const char *p = spec;
66
3.86M
    uint32_t offset = 0;
67
3.86M
    int32_t len = specLen;
68
3.86M
69
3.86M
    // skip leading whitespace
70
3.86M
    while (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') {
71
0
        spec++;
72
0
        specLen--;
73
0
        offset++;
74
0
75
0
        p++;
76
0
        len--;
77
0
    }
78
3.86M
79
21.5M
    for (; len && *p && !colon && !slash; ++p, --len) {
80
17.6M
        switch (*p) {
81
17.6M
            case ':':
82
2.81M
                if (!colon)
83
2.81M
                    colon = p;
84
2.81M
                break;
85
17.6M
            case '/': // start of filepath
86
408k
            case '?': // start of query
87
408k
            case '#': // start of ref
88
408k
                if (!slash)
89
408k
                    slash = p;
90
408k
                break;
91
408k
            case '@': // username@hostname
92
25.3k
            case '[': // start of IPv6 address literal
93
25.3k
                if (!stop)
94
24.9k
                    stop = p;
95
25.3k
                break;
96
17.6M
        }
97
17.6M
    }
98
3.86M
    // disregard the first colon if it follows an '@' or a '['
99
3.86M
    if (colon && stop && colon > stop)
100
336
        colon = nullptr;
101
3.86M
102
3.86M
    // if the spec only contained whitespace ...
103
3.86M
    if (specLen == 0) {
104
3.51k
        SET_RESULT(scheme, 0, -1);
105
3.51k
        SET_RESULT(authority, 0, 0);
106
3.51k
        SET_RESULT(path, 0, 0);
107
3.51k
        return NS_OK;
108
3.51k
    }
109
3.86M
110
3.86M
    // ignore trailing whitespace and control characters
111
3.86M
    for (p = spec + specLen - 1; ((unsigned char) *p <= ' ') && (p != spec); --p)
112
0
        ;
113
3.86M
114
3.86M
    specLen = p - spec + 1;
115
3.86M
116
3.86M
    if (colon && (colon < slash || !slash)) {
117
2.80M
        //
118
2.80M
        // spec = <scheme>:/<the-rest>
119
2.80M
        //
120
2.80M
        // or
121
2.80M
        //
122
2.80M
        // spec = <scheme>:<authority>
123
2.80M
        // spec = <scheme>:<path-no-slashes>
124
2.80M
        //
125
2.80M
        if (!net_IsValidScheme(spec, colon - spec) || (*(colon+1) == ':')) {
126
5.77k
            return NS_ERROR_MALFORMED_URI;
127
5.77k
        }
128
2.80M
        SET_RESULT(scheme, offset, colon - spec);
129
2.80M
        if (authorityLen || pathLen) {
130
1.12M
            uint32_t schemeLen = colon + 1 - spec;
131
1.12M
            offset += schemeLen;
132
1.12M
            ParseAfterScheme(colon + 1, specLen - schemeLen,
133
1.12M
                             authorityPos, authorityLen,
134
1.12M
                             pathPos, pathLen);
135
1.12M
            OFFSET_RESULT(authority, offset);
136
1.12M
            OFFSET_RESULT(path, offset);
137
1.12M
        }
138
2.80M
    }
139
1.05M
    else {
140
1.05M
        //
141
1.05M
        // spec = <authority-no-port-or-password>/<path>
142
1.05M
        // spec = <path>
143
1.05M
        //
144
1.05M
        // or
145
1.05M
        //
146
1.05M
        // spec = <authority-no-port-or-password>/<path-with-colon>
147
1.05M
        // spec = <path-with-colon>
148
1.05M
        //
149
1.05M
        // or
150
1.05M
        //
151
1.05M
        // spec = <authority-no-port-or-password>
152
1.05M
        // spec = <path-no-slashes-or-colon>
153
1.05M
        //
154
1.05M
        SET_RESULT(scheme, 0, -1);
155
1.05M
        if (authorityLen || pathLen) {
156
0
            ParseAfterScheme(spec, specLen,
157
0
                             authorityPos, authorityLen,
158
0
                             pathPos, pathLen);
159
0
            OFFSET_RESULT(authority, offset);
160
0
            OFFSET_RESULT(path, offset);
161
0
        }
162
1.05M
    }
163
3.86M
    return NS_OK;
164
3.86M
}
165
166
NS_IMETHODIMP
167
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
0
{
173
0
    if (NS_WARN_IF(!auth)) {
174
0
        return NS_ERROR_INVALID_POINTER;
175
0
    }
176
0
177
0
    if (authLen < 0)
178
0
        authLen = strlen(auth);
179
0
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
0
}
187
188
NS_IMETHODIMP
189
nsBaseURLParser::ParseUserInfo(const char *userinfo, int32_t userinfoLen,
190
                               uint32_t *usernamePos, int32_t *usernameLen,
191
                               uint32_t *passwordPos, int32_t *passwordLen)
192
0
{
193
0
    SET_RESULT(username, 0, -1);
194
0
    SET_RESULT(password, 0, -1);
195
0
    return NS_OK;
196
0
}
197
198
NS_IMETHODIMP
199
nsBaseURLParser::ParseServerInfo(const char *serverinfo, int32_t serverinfoLen,
200
                                 uint32_t *hostnamePos, int32_t *hostnameLen,
201
                                 int32_t *port)
202
0
{
203
0
    SET_RESULT(hostname, 0, -1);
204
0
    if (port)
205
0
       *port = -1;
206
0
    return NS_OK;
207
0
}
208
209
NS_IMETHODIMP
210
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
1.07M
{
215
1.07M
    if (NS_WARN_IF(!path)) {
216
0
        return NS_ERROR_INVALID_POINTER;
217
0
    }
218
1.07M
219
1.07M
    if (pathLen < 0)
220
0
        pathLen = strlen(path);
221
1.07M
222
1.07M
    // path = [/]<segment1>/<segment2>/<...>/<segmentN>?<query>#<ref>
223
1.07M
224
1.07M
    // XXX PL_strnpbrk would be nice, but it's buggy
225
1.07M
226
1.07M
    // search for first occurrence of either ? or #
227
1.07M
    const char *query_beg = nullptr, *query_end = nullptr;
228
1.07M
    const char *ref_beg = nullptr;
229
1.07M
    const char *p = nullptr;
230
9.32M
    for (p = path; p < path + pathLen; ++p) {
231
8.26M
        // only match the query string if it precedes the reference fragment
232
8.26M
        if (!ref_beg && !query_beg && *p == '?')
233
120k
            query_beg = p + 1;
234
8.14M
        else if (*p == '#') {
235
4.95k
            ref_beg = p + 1;
236
4.95k
            if (query_beg)
237
276
                query_end = p;
238
4.95k
            break;
239
4.95k
        }
240
8.26M
    }
241
1.07M
242
1.07M
    if (query_beg) {
243
120k
        if (query_end)
244
120k
            SET_RESULT(query, query_beg - path, query_end - query_beg);
245
120k
        else
246
120k
            SET_RESULT(query, query_beg - path, pathLen - (query_beg - path));
247
120k
    }
248
1.07M
    else
249
1.07M
        SET_RESULT(query, 0, -1);
250
1.07M
251
1.07M
    if (ref_beg)
252
1.07M
        SET_RESULT(ref, ref_beg - path, pathLen - (ref_beg - path));
253
1.07M
    else
254
1.07M
        SET_RESULT(ref, 0, -1);
255
1.07M
256
1.07M
    const char *end;
257
1.07M
    if (query_beg)
258
120k
        end = query_beg - 1;
259
954k
    else if (ref_beg)
260
4.67k
        end = ref_beg - 1;
261
949k
    else
262
949k
        end = path + pathLen;
263
1.07M
264
1.07M
    // an empty file path is no file path
265
1.07M
    if (end != path)
266
1.07M
        SET_RESULT(filepath, 0, end - path);
267
1.07M
    else
268
1.07M
        SET_RESULT(filepath, 0, -1);
269
1.07M
    return NS_OK;
270
1.07M
}
271
272
NS_IMETHODIMP
273
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
1.07M
{
278
1.07M
    if (NS_WARN_IF(!filepath)) {
279
0
        return NS_ERROR_INVALID_POINTER;
280
0
    }
281
1.07M
282
1.07M
    if (filepathLen < 0)
283
0
        filepathLen = strlen(filepath);
284
1.07M
285
1.07M
    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
0
    }
291
1.07M
292
1.07M
    const char *p;
293
1.07M
    const char *end = filepath + filepathLen;
294
1.07M
295
1.07M
    // search backwards for filename
296
6.85M
    for (p = end - 1; *p != '/' && p > filepath; --p)
297
5.78M
        ;
298
1.07M
    if (*p == '/') {
299
1.06M
        // catch /.. and /.
300
1.06M
        if ((p+1 < end && *(p+1) == '.') &&
301
1.06M
           (p+2 == end || (*(p+2) == '.' && p+3 == end)))
302
653
            p = end - 1;
303
1.06M
        // filepath = <directory><filename>.<extension>
304
1.06M
        SET_RESULT(directory, 0, p - filepath + 1);
305
1.06M
        ParseFileName(p + 1, end - (p + 1),
306
1.06M
                      basenamePos, basenameLen,
307
1.06M
                      extensionPos, extensionLen);
308
1.06M
        OFFSET_RESULT(basename, p + 1 - filepath);
309
1.06M
        OFFSET_RESULT(extension, p + 1 - filepath);
310
1.06M
    }
311
1.20k
    else {
312
1.20k
        // filepath = <filename>.<extension>
313
1.20k
        SET_RESULT(directory, 0, -1);
314
1.20k
        ParseFileName(filepath, filepathLen,
315
1.20k
                      basenamePos, basenameLen,
316
1.20k
                      extensionPos, extensionLen);
317
1.20k
    }
318
1.07M
    return NS_OK;
319
1.07M
}
320
321
nsresult
322
nsBaseURLParser::ParseFileName(const char *filename, int32_t filenameLen,
323
                               uint32_t *basenamePos, int32_t *basenameLen,
324
                               uint32_t *extensionPos, int32_t *extensionLen)
325
1.07M
{
326
1.07M
    if (NS_WARN_IF(!filename)) {
327
0
        return NS_ERROR_INVALID_POINTER;
328
0
    }
329
1.07M
330
1.07M
    if (filenameLen < 0)
331
0
        filenameLen = strlen(filename);
332
1.07M
333
1.07M
    // no extension if filename ends with a '.'
334
1.07M
    if (filename[filenameLen-1] != '.') {
335
1.06M
        // ignore '.' at the beginning
336
5.83M
        for (const char *p = filename + filenameLen - 1; p > filename; --p) {
337
4.76M
            if (*p == '.') {
338
3.05k
                // filename = <basename.extension>
339
3.05k
                SET_RESULT(basename, 0, p - filename);
340
3.05k
                SET_RESULT(extension, p + 1 - filename, filenameLen - (p - filename + 1));
341
3.05k
                return NS_OK;
342
3.05k
            }
343
4.76M
        }
344
1.06M
    }
345
1.07M
    // filename = <basename>
346
1.07M
    SET_RESULT(basename, 0, filenameLen);
347
1.06M
    SET_RESULT(extension, 0, -1);
348
1.06M
    return NS_OK;
349
1.07M
}
350
351
//----------------------------------------------------------------------------
352
// nsNoAuthURLParser implementation
353
//----------------------------------------------------------------------------
354
355
NS_IMETHODIMP
356
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
0
{
362
0
    MOZ_ASSERT_UNREACHABLE("Shouldn't parse auth in a NoAuthURL!");
363
0
    return NS_ERROR_UNEXPECTED;
364
0
}
365
366
void
367
nsNoAuthURLParser::ParseAfterScheme(const char *spec, int32_t specLen,
368
                                    uint32_t *authPos, int32_t *authLen,
369
                                    uint32_t *pathPos, int32_t *pathLen)
370
7.01k
{
371
7.01k
    MOZ_ASSERT(specLen >= 0, "unexpected");
372
7.01k
373
7.01k
    // everything is the path
374
7.01k
    uint32_t pos = 0;
375
7.01k
    switch (CountConsecutiveSlashes(spec, specLen)) {
376
7.01k
    case 0:
377
2.38k
    case 1:
378
2.38k
        break;
379
2.38k
    case 2:
380
2.25k
        {
381
2.25k
            const char *p = nullptr;
382
2.25k
            if (specLen > 2) {
383
2.09k
                // looks like there is an authority section
384
2.09k
385
2.09k
                // if the authority looks like a drive number then we
386
2.09k
                // really want to treat it as part of the path
387
2.09k
                // [a-zA-Z][:|]{/\}
388
2.09k
                // i.e one of:   c:   c:\foo  c:/foo  c|  c|\foo  c|/foo
389
2.09k
                if ((specLen > 3) && (spec[3] == ':' || spec[3] == '|') &&
390
2.09k
                    IsAsciiAlpha(spec[2]) &&
391
2.09k
                    ((specLen == 4) || (spec[4] == '/') || (spec[4] == '\\'))) {
392
445
                    pos = 1;
393
445
                    break;
394
445
                }
395
1.64k
                // Ignore apparent authority; path is everything after it
396
402k
                for (p = spec + 2; p < spec + specLen; ++p) {
397
401k
                    if (*p == '/' || *p == '?' || *p == '#')
398
379
                        break;
399
401k
                }
400
1.64k
            }
401
2.25k
            SET_RESULT(auth, 0, -1);
402
1.80k
            if (p && p != spec+specLen)
403
1.80k
                SET_RESULT(path, p - spec, specLen - (p - spec));
404
1.80k
            else
405
1.80k
                SET_RESULT(path, 0, -1);
406
1.80k
            return;
407
2.25k
        }
408
2.37k
    default:
409
2.37k
        pos = 2;
410
2.37k
        break;
411
5.20k
    }
412
5.20k
    SET_RESULT(auth, pos, 0);
413
5.20k
    SET_RESULT(path, pos, specLen - pos);
414
5.20k
}
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]=='|') && 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
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
1.09M
{
465
1.09M
    nsresult rv;
466
1.09M
467
1.09M
    if (NS_WARN_IF(!auth)) {
468
0
        return NS_ERROR_INVALID_POINTER;
469
0
    }
470
1.09M
471
1.09M
    if (authLen < 0)
472
0
        authLen = strlen(auth);
473
1.09M
474
1.09M
    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
0
    }
482
1.09M
483
1.09M
    // search backwards for @
484
1.09M
    const char *p = auth + authLen - 1;
485
13.8M
    for (; (*p != '@') && (p > auth); --p) {
486
12.7M
    }
487
1.09M
    if ( *p == '@' ) {
488
4.35k
        // auth = <user-info@server-info>
489
4.35k
        rv = ParseUserInfo(auth, p - auth,
490
4.35k
                           usernamePos, usernameLen,
491
4.35k
                           passwordPos, passwordLen);
492
4.35k
        if (NS_FAILED(rv)) return rv;
493
4.06k
        rv = ParseServerInfo(p + 1, authLen - (p - auth + 1),
494
4.06k
                             hostnamePos, hostnameLen,
495
4.06k
                             port);
496
4.06k
        if (NS_FAILED(rv)) return rv;
497
3.35k
        OFFSET_RESULT(hostname, p + 1 - auth);
498
3.35k
499
3.35k
        // malformed if has a username or password
500
3.35k
        // but no host info, such as: http://u:p@/
501
3.35k
        if ((usernamePos || passwordPos) && (!hostnamePos || !*hostnameLen)) {
502
341
            return NS_ERROR_MALFORMED_URI;
503
341
        }
504
1.08M
    }
505
1.08M
    else {
506
1.08M
        // auth = <server-info>
507
1.08M
        SET_RESULT(username, 0, -1);
508
1.08M
        SET_RESULT(password, 0, -1);
509
1.08M
        rv = ParseServerInfo(auth, authLen,
510
1.08M
                             hostnamePos, hostnameLen,
511
1.08M
                             port);
512
1.08M
        if (NS_FAILED(rv)) return rv;
513
1.08M
    }
514
1.08M
    return NS_OK;
515
1.08M
}
516
517
NS_IMETHODIMP
518
nsAuthURLParser::ParseUserInfo(const char *userinfo, int32_t userinfoLen,
519
                               uint32_t *usernamePos, int32_t *usernameLen,
520
                               uint32_t *passwordPos, int32_t *passwordLen)
521
4.35k
{
522
4.35k
    if (NS_WARN_IF(!userinfo)) {
523
0
        return NS_ERROR_INVALID_POINTER;
524
0
    }
525
4.35k
526
4.35k
    if (userinfoLen < 0)
527
0
        userinfoLen = strlen(userinfo);
528
4.35k
529
4.35k
    if (userinfoLen == 0) {
530
886
        SET_RESULT(username, 0, -1);
531
886
        SET_RESULT(password, 0, -1);
532
886
        return NS_OK;
533
886
    }
534
3.47k
535
3.47k
    const char *p = (const char *) memchr(userinfo, ':', userinfoLen);
536
3.47k
    if (p) {
537
1.87k
        // userinfo = <username:password>
538
1.87k
        if (p == userinfo) {
539
295
            // must have a username!
540
295
            return NS_ERROR_MALFORMED_URI;
541
295
        }
542
1.58k
        SET_RESULT(username, 0, p - userinfo);
543
1.58k
        SET_RESULT(password, p - userinfo + 1, userinfoLen - (p - userinfo + 1));
544
1.58k
    }
545
1.59k
    else {
546
1.59k
        // userinfo = <username>
547
1.59k
        SET_RESULT(username, 0, userinfoLen);
548
1.59k
        SET_RESULT(password, 0, -1);
549
1.59k
    }
550
3.47k
    return NS_OK;
551
3.47k
}
552
553
NS_IMETHODIMP
554
nsAuthURLParser::ParseServerInfo(const char *serverinfo, int32_t serverinfoLen,
555
                                 uint32_t *hostnamePos, int32_t *hostnameLen,
556
                                 int32_t *port)
557
1.09M
{
558
1.09M
    if (NS_WARN_IF(!serverinfo)) {
559
0
        return NS_ERROR_INVALID_POINTER;
560
0
    }
561
1.09M
562
1.09M
    if (serverinfoLen < 0)
563
0
        serverinfoLen = strlen(serverinfo);
564
1.09M
565
1.09M
    if (serverinfoLen == 0) {
566
341
        SET_RESULT(hostname, 0, 0);
567
341
        if (port)
568
341
            *port = -1;
569
341
        return NS_OK;
570
341
    }
571
1.09M
572
1.09M
    // search backwards for a ':' but stop on ']' (IPv6 address literal
573
1.09M
    // delimiter).  check for illegal characters in the hostname.
574
1.09M
    const char *p = serverinfo + serverinfoLen - 1;
575
1.09M
    const char *colon = nullptr, *bracket = nullptr;
576
13.7M
    for (; p > serverinfo; --p) {
577
12.7M
        switch (*p) {
578
12.7M
            case ']':
579
5.23k
                bracket = p;
580
5.23k
                break;
581
12.7M
            case ':':
582
7.46k
                if (bracket == nullptr)
583
4.38k
                    colon = p;
584
7.46k
                break;
585
12.7M
            case ' ':
586
0
                // hostname must not contain a space
587
0
                return NS_ERROR_MALFORMED_URI;
588
12.7M
        }
589
12.7M
    }
590
1.09M
591
1.09M
    if (colon) {
592
3.97k
        // serverinfo = <hostname:port>
593
3.97k
        SET_RESULT(hostname, 0, colon - serverinfo);
594
3.97k
        if (port) {
595
3.97k
            // XXX unfortunately ToInteger is not defined for substrings
596
3.97k
            nsAutoCString buf(colon+1, serverinfoLen - (colon + 1 - serverinfo));
597
3.97k
            if (buf.Length() == 0) {
598
797
                *port = -1;
599
797
            }
600
3.17k
            else {
601
3.17k
                const char* nondigit = NS_strspnp("0123456789", buf.get());
602
3.17k
                if (nondigit && *nondigit)
603
1.91k
                    return NS_ERROR_MALFORMED_URI;
604
1.25k
605
1.25k
                nsresult err;
606
1.25k
                *port = buf.ToInteger(&err);
607
1.25k
                if (NS_FAILED(err) || *port < 0 || *port > std::numeric_limits<uint16_t>::max())
608
851
                    return NS_ERROR_MALFORMED_URI;
609
1.08M
            }
610
3.97k
        }
611
1.08M
    }
612
1.08M
    else {
613
1.08M
        // serverinfo = <hostname>
614
1.08M
        SET_RESULT(hostname, 0, serverinfoLen);
615
1.08M
        if (port)
616
1.08M
           *port = -1;
617
1.08M
    }
618
1.09M
619
1.09M
    // In case of IPv6 address check its validity
620
1.09M
    if (*hostnameLen > 1 && *(serverinfo + *hostnamePos) == '[' &&
621
1.09M
        *(serverinfo + *hostnamePos + *hostnameLen - 1) == ']' &&
622
1.09M
        !net_IsValidIPv6Addr(serverinfo + *hostnamePos + 1, *hostnameLen - 2))
623
2.85k
            return NS_ERROR_MALFORMED_URI;
624
1.08M
625
1.08M
    return NS_OK;
626
1.08M
}
627
628
void
629
nsAuthURLParser::ParseAfterScheme(const char *spec, int32_t specLen,
630
                                  uint32_t *authPos, int32_t *authLen,
631
                                  uint32_t *pathPos, int32_t *pathLen)
632
1.08M
{
633
1.08M
    MOZ_ASSERT(specLen >= 0, "unexpected");
634
1.08M
635
1.08M
    uint32_t nslash = CountConsecutiveSlashes(spec, specLen);
636
1.08M
637
1.08M
    // search for the end of the authority section
638
1.08M
    const char *end = spec + specLen;
639
1.08M
    const char *p;
640
15.2M
    for (p = spec + nslash; p < end; ++p) {
641
15.1M
        if (*p == '/' || *p == '?' || *p == '#')
642
1.04M
            break;
643
15.1M
    }
644
1.08M
    if (p < end) {
645
1.04M
        // spec = [/]<auth><path>
646
1.04M
        SET_RESULT(auth, nslash, p - (spec + nslash));
647
1.04M
        SET_RESULT(path, p - spec, specLen - (p - spec));
648
1.04M
    }
649
45.9k
    else {
650
45.9k
        // spec = [/]<auth>
651
45.9k
        SET_RESULT(auth, nslash, specLen - nslash);
652
45.9k
        SET_RESULT(path, 0, -1);
653
45.9k
    }
654
1.08M
}
655
656
//----------------------------------------------------------------------------
657
// nsStdURLParser implementation
658
//----------------------------------------------------------------------------
659
660
void
661
nsStdURLParser::ParseAfterScheme(const char *spec, int32_t specLen,
662
                                 uint32_t *authPos, int32_t *authLen,
663
                                 uint32_t *pathPos, int32_t *pathLen)
664
30.8k
{
665
30.8k
    MOZ_ASSERT(specLen >= 0, "unexpected");
666
30.8k
667
30.8k
    uint32_t nslash = CountConsecutiveSlashes(spec, specLen);
668
30.8k
669
30.8k
    // search for the end of the authority section
670
30.8k
    const char *end = spec + specLen;
671
30.8k
    const char *p;
672
414k
    for (p = spec + nslash; p < end; ++p) {
673
403k
        if (strchr("/?#;", *p))
674
19.8k
            break;
675
403k
    }
676
30.8k
    switch (nslash) {
677
30.8k
    case 0:
678
12.6k
    case 2:
679
12.6k
        if (p < end) {
680
8.17k
            // spec = (//)<auth><path>
681
8.17k
            SET_RESULT(auth, nslash, p - (spec + nslash));
682
8.17k
            SET_RESULT(path, p - spec, specLen - (p - spec));
683
8.17k
        }
684
4.51k
        else {
685
4.51k
            // spec = (//)<auth>
686
4.51k
            SET_RESULT(auth, nslash, specLen - nslash);
687
4.51k
            SET_RESULT(path, 0, -1);
688
4.51k
        }
689
12.6k
        break;
690
17.9k
    case 1:
691
17.9k
        // spec = /<path>
692
17.9k
        SET_RESULT(auth, 0, -1);
693
17.9k
        SET_RESULT(path, 0, specLen);
694
17.9k
        break;
695
12.6k
    default:
696
173
        // spec = ///[/]<path>
697
173
        SET_RESULT(auth, 2, 0);
698
173
        SET_RESULT(path, 2, specLen - 2);
699
30.8k
    }
700
30.8k
}