GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_url.cc Lines: 1196 1248 95.8 %
Date: 2021-06-04 04:12:13 Branches: 1085 1229 88.3 %

Line Branch Exec Source
1
#include "node_url.h"
2
#include "base_object-inl.h"
3
#include "node_errors.h"
4
#include "node_external_reference.h"
5
#include "node_i18n.h"
6
#include "util-inl.h"
7
8
#include <cmath>
9
#include <cstdio>
10
#include <string>
11
#include <vector>
12
13
namespace node {
14
15
using errors::TryCatchScope;
16
17
using v8::Array;
18
using v8::Context;
19
using v8::Function;
20
using v8::FunctionCallbackInfo;
21
using v8::HandleScope;
22
using v8::Int32;
23
using v8::Integer;
24
using v8::Isolate;
25
using v8::Local;
26
using v8::MaybeLocal;
27
using v8::NewStringType;
28
using v8::Null;
29
using v8::Object;
30
using v8::String;
31
using v8::Undefined;
32
using v8::Value;
33
34
121681
Local<String> Utf8String(Isolate* isolate, const std::string& str) {
35
243371
  return String::NewFromUtf8(isolate,
36
                             str.data(),
37
                             NewStringType::kNormal,
38
243370
                             str.length()).ToLocalChecked();
39
}
40
41
namespace url {
42
43
namespace {
44
45
// https://url.spec.whatwg.org/#eof-code-point
46
constexpr char kEOL = -1;
47
48
// Used in ToUSVString().
49
constexpr char16_t kUnicodeReplacementCharacter = 0xFFFD;
50
51
// https://url.spec.whatwg.org/#concept-host
52
5042
class URLHost {
53
 public:
54
  ~URLHost();
55
56
  void ParseIPv4Host(const char* input, size_t length, bool* is_ipv4);
57
  void ParseIPv6Host(const char* input, size_t length);
58
  void ParseOpaqueHost(const char* input, size_t length);
59
  void ParseHost(const char* input,
60
                 size_t length,
61
                 bool is_special,
62
                 bool unicode = false);
63
64
5043
  bool ParsingFailed() const { return type_ == HostType::H_FAILED; }
65
  std::string ToString() const;
66
  // Like ToString(), but avoids a copy in exchange for invalidating `*this`.
67
  std::string ToStringMove();
68
69
 private:
70
  enum class HostType {
71
    H_FAILED,
72
    H_DOMAIN,
73
    H_IPV4,
74
    H_IPV6,
75
    H_OPAQUE,
76
  };
77
78
  union Value {
79
    std::string domain_or_opaque;
80
    uint32_t ipv4;
81
    uint16_t ipv6[8];
82
83
5042
    ~Value() {}
84
5042
    Value() : ipv4(0) {}
85
  };
86
87
  Value value_;
88
  HostType type_ = HostType::H_FAILED;
89
90
14191
  void Reset() {
91
    using string = std::string;
92
14191
    switch (type_) {
93
      case HostType::H_DOMAIN:
94
      case HostType::H_OPAQUE:
95
4512
        value_.domain_or_opaque.~string();
96
4512
        break;
97
      default:
98
9679
        break;
99
    }
100
14191
    type_ = HostType::H_FAILED;
101
14191
  }
102
103
  // Setting the string members of the union with = is brittle because
104
  // it relies on them being initialized to a state that requires no
105
  // destruction of old data.
106
  // For a long time, that worked well enough because ParseIPv6Host() happens
107
  // to zero-fill `value_`, but that really is relying on standard library
108
  // internals too much.
109
  // These helpers are the easiest solution but we might want to consider
110
  // just not forcing strings into an union.
111
442
  void SetOpaque(std::string&& string) {
112
442
    Reset();
113
442
    type_ = HostType::H_OPAQUE;
114
442
    new(&value_.domain_or_opaque) std::string(std::move(string));
115
442
  }
116
117
4074
  void SetDomain(std::string&& string) {
118
4074
    Reset();
119
4073
    type_ = HostType::H_DOMAIN;
120
4073
    new(&value_.domain_or_opaque) std::string(std::move(string));
121
4073
  }
122
};
123
124
10084
URLHost::~URLHost() {
125
5042
  Reset();
126
5042
}
127
128
#define ARGS(XX)                                                              \
129
  XX(ARG_FLAGS)                                                               \
130
  XX(ARG_PROTOCOL)                                                            \
131
  XX(ARG_USERNAME)                                                            \
132
  XX(ARG_PASSWORD)                                                            \
133
  XX(ARG_HOST)                                                                \
134
  XX(ARG_PORT)                                                                \
135
  XX(ARG_PATH)                                                                \
136
  XX(ARG_QUERY)                                                               \
137
  XX(ARG_FRAGMENT)                                                            \
138
  XX(ARG_COUNT)  // This one has to be last.
139
140
#define ERR_ARGS(XX)                                                          \
141
  XX(ERR_ARG_FLAGS)                                                           \
142
  XX(ERR_ARG_INPUT)                                                           \
143
144
enum url_cb_args {
145
#define XX(name) name,
146
  ARGS(XX)
147
#undef XX
148
};
149
150
enum url_error_cb_args {
151
#define XX(name) name,
152
  ERR_ARGS(XX)
153
#undef XX
154
};
155
156
#define CHAR_TEST(bits, name, expr)                                           \
157
  template <typename T>                                                       \
158
  bool name(const T ch) {                                              \
159
    static_assert(sizeof(ch) >= (bits) / 8,                                   \
160
                  "Character must be wider than " #bits " bits");             \
161
    return (expr);                                                            \
162
  }
163
164
#define TWO_CHAR_STRING_TEST(bits, name, expr)                                \
165
  template <typename T>                                                       \
166
  bool name(const T ch1, const T ch2) {                                \
167
    static_assert(sizeof(ch1) >= (bits) / 8,                                  \
168
                  "Character must be wider than " #bits " bits");             \
169
    return (expr);                                                            \
170
  }                                                                           \
171
  template <typename T>                                                       \
172
  bool name(const std::basic_string<T>& str) {                         \
173
    static_assert(sizeof(str[0]) >= (bits) / 8,                               \
174
                  "Character must be wider than " #bits " bits");             \
175
    return str.length() >= 2 && name(str[0], str[1]);                         \
176
  }
177
178
// https://infra.spec.whatwg.org/#ascii-tab-or-newline
179

13729938
CHAR_TEST(8, IsASCIITabOrNewline, (ch == '\t' || ch == '\n' || ch == '\r'))
180
181
// https://infra.spec.whatwg.org/#c0-control-or-space
182

242394
CHAR_TEST(8, IsC0ControlOrSpace, (ch >= '\0' && ch <= ' '))
183
184
// https://infra.spec.whatwg.org/#ascii-digit
185

488083
CHAR_TEST(8, IsASCIIDigit, (ch >= '0' && ch <= '9'))
186
187
// https://infra.spec.whatwg.org/#ascii-hex-digit
188


1596
CHAR_TEST(8, IsASCIIHexDigit, (IsASCIIDigit(ch) ||
189
                               (ch >= 'A' && ch <= 'F') ||
190
                               (ch >= 'a' && ch <= 'f')))
191
192
// https://infra.spec.whatwg.org/#ascii-alpha
193


1076162
CHAR_TEST(8, IsASCIIAlpha, ((ch >= 'A' && ch <= 'Z') ||
194
                            (ch >= 'a' && ch <= 'z')))
195
196
// https://infra.spec.whatwg.org/#ascii-alphanumeric
197

475779
CHAR_TEST(8, IsASCIIAlphanumeric, (IsASCIIDigit(ch) || IsASCIIAlpha(ch)))
198
199
// https://infra.spec.whatwg.org/#ascii-lowercase
200
template <typename T>
201
475858
T ASCIILowercase(T ch) {
202
475858
  return IsASCIIAlpha(ch) ? (ch | 0x20) : ch;
203
}
204
205
// https://url.spec.whatwg.org/#forbidden-host-code-point
206









96116
CHAR_TEST(8, IsForbiddenHostCodePoint,
207
          ch == '\0' || ch == '\t' || ch == '\n' || ch == '\r' ||
208
          ch == ' ' || ch == '#' || ch == '%' || ch == '/' ||
209
          ch == ':' || ch == '?' || ch == '@' || ch == '[' ||
210
          ch == '<' || ch == '>' || ch == '\\' || ch == ']' ||
211
          ch == '^' || ch == '|')
212
213
// https://url.spec.whatwg.org/#windows-drive-letter
214


3083
TWO_CHAR_STRING_TEST(8, IsWindowsDriveLetter,
215
                     (IsASCIIAlpha(ch1) && (ch2 == ':' || ch2 == '|')))
216
217
// https://url.spec.whatwg.org/#normalized-windows-drive-letter
218


907
TWO_CHAR_STRING_TEST(8, IsNormalizedWindowsDriveLetter,
219
                     (IsASCIIAlpha(ch1) && ch2 == ':'))
220
221
// If a UTF-16 character is a low/trailing surrogate.
222
3
CHAR_TEST(16, IsUnicodeTrail, (ch & 0xFC00) == 0xDC00)
223
224
// If a UTF-16 character is a surrogate.
225
31
CHAR_TEST(16, IsUnicodeSurrogate, (ch & 0xF800) == 0xD800)
226
227
// If a UTF-16 surrogate is a low/trailing one.
228
18
CHAR_TEST(16, IsUnicodeSurrogateTrail, (ch & 0x400) != 0)
229
230
#undef CHAR_TEST
231
#undef TWO_CHAR_STRING_TEST
232
233
const char* hex[256] = {
234
  "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
235
  "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F",
236
  "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
237
  "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F",
238
  "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27",
239
  "%28", "%29", "%2A", "%2B", "%2C", "%2D", "%2E", "%2F",
240
  "%30", "%31", "%32", "%33", "%34", "%35", "%36", "%37",
241
  "%38", "%39", "%3A", "%3B", "%3C", "%3D", "%3E", "%3F",
242
  "%40", "%41", "%42", "%43", "%44", "%45", "%46", "%47",
243
  "%48", "%49", "%4A", "%4B", "%4C", "%4D", "%4E", "%4F",
244
  "%50", "%51", "%52", "%53", "%54", "%55", "%56", "%57",
245
  "%58", "%59", "%5A", "%5B", "%5C", "%5D", "%5E", "%5F",
246
  "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67",
247
  "%68", "%69", "%6A", "%6B", "%6C", "%6D", "%6E", "%6F",
248
  "%70", "%71", "%72", "%73", "%74", "%75", "%76", "%77",
249
  "%78", "%79", "%7A", "%7B", "%7C", "%7D", "%7E", "%7F",
250
  "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
251
  "%88", "%89", "%8A", "%8B", "%8C", "%8D", "%8E", "%8F",
252
  "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
253
  "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
254
  "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7",
255
  "%A8", "%A9", "%AA", "%AB", "%AC", "%AD", "%AE", "%AF",
256
  "%B0", "%B1", "%B2", "%B3", "%B4", "%B5", "%B6", "%B7",
257
  "%B8", "%B9", "%BA", "%BB", "%BC", "%BD", "%BE", "%BF",
258
  "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
259
  "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF",
260
  "%D0", "%D1", "%D2", "%D3", "%D4", "%D5", "%D6", "%D7",
261
  "%D8", "%D9", "%DA", "%DB", "%DC", "%DD", "%DE", "%DF",
262
  "%E0", "%E1", "%E2", "%E3", "%E4", "%E5", "%E6", "%E7",
263
  "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
264
  "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7",
265
  "%F8", "%F9", "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
266
};
267
268
const uint8_t C0_CONTROL_ENCODE_SET[32] = {
269
  // 00     01     02     03     04     05     06     07
270
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
271
  // 08     09     0A     0B     0C     0D     0E     0F
272
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
273
  // 10     11     12     13     14     15     16     17
274
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
275
  // 18     19     1A     1B     1C     1D     1E     1F
276
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
277
  // 20     21     22     23     24     25     26     27
278
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
279
  // 28     29     2A     2B     2C     2D     2E     2F
280
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
281
  // 30     31     32     33     34     35     36     37
282
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
283
  // 38     39     3A     3B     3C     3D     3E     3F
284
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
285
  // 40     41     42     43     44     45     46     47
286
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
287
  // 48     49     4A     4B     4C     4D     4E     4F
288
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
289
  // 50     51     52     53     54     55     56     57
290
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
291
  // 58     59     5A     5B     5C     5D     5E     5F
292
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
293
  // 60     61     62     63     64     65     66     67
294
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
295
  // 68     69     6A     6B     6C     6D     6E     6F
296
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
297
  // 70     71     72     73     74     75     76     77
298
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
299
  // 78     79     7A     7B     7C     7D     7E     7F
300
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
301
  // 80     81     82     83     84     85     86     87
302
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
303
  // 88     89     8A     8B     8C     8D     8E     8F
304
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
305
  // 90     91     92     93     94     95     96     97
306
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
307
  // 98     99     9A     9B     9C     9D     9E     9F
308
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
309
  // A0     A1     A2     A3     A4     A5     A6     A7
310
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
311
  // A8     A9     AA     AB     AC     AD     AE     AF
312
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
313
  // B0     B1     B2     B3     B4     B5     B6     B7
314
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
315
  // B8     B9     BA     BB     BC     BD     BE     BF
316
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
317
  // C0     C1     C2     C3     C4     C5     C6     C7
318
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
319
  // C8     C9     CA     CB     CC     CD     CE     CF
320
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
321
  // D0     D1     D2     D3     D4     D5     D6     D7
322
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
323
  // D8     D9     DA     DB     DC     DD     DE     DF
324
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
325
  // E0     E1     E2     E3     E4     E5     E6     E7
326
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
327
  // E8     E9     EA     EB     EC     ED     EE     EF
328
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
329
  // F0     F1     F2     F3     F4     F5     F6     F7
330
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
331
  // F8     F9     FA     FB     FC     FD     FE     FF
332
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80
333
};
334
335
const uint8_t FRAGMENT_ENCODE_SET[32] = {
336
  // 00     01     02     03     04     05     06     07
337
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
338
  // 08     09     0A     0B     0C     0D     0E     0F
339
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
340
  // 10     11     12     13     14     15     16     17
341
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
342
  // 18     19     1A     1B     1C     1D     1E     1F
343
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
344
  // 20     21     22     23     24     25     26     27
345
    0x01 | 0x00 | 0x04 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
346
  // 28     29     2A     2B     2C     2D     2E     2F
347
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
348
  // 30     31     32     33     34     35     36     37
349
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
350
  // 38     39     3A     3B     3C     3D     3E     3F
351
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
352
  // 40     41     42     43     44     45     46     47
353
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
354
  // 48     49     4A     4B     4C     4D     4E     4F
355
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
356
  // 50     51     52     53     54     55     56     57
357
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
358
  // 58     59     5A     5B     5C     5D     5E     5F
359
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
360
  // 60     61     62     63     64     65     66     67
361
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
362
  // 68     69     6A     6B     6C     6D     6E     6F
363
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
364
  // 70     71     72     73     74     75     76     77
365
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
366
  // 78     79     7A     7B     7C     7D     7E     7F
367
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
368
  // 80     81     82     83     84     85     86     87
369
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
370
  // 88     89     8A     8B     8C     8D     8E     8F
371
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
372
  // 90     91     92     93     94     95     96     97
373
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
374
  // 98     99     9A     9B     9C     9D     9E     9F
375
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
376
  // A0     A1     A2     A3     A4     A5     A6     A7
377
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
378
  // A8     A9     AA     AB     AC     AD     AE     AF
379
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
380
  // B0     B1     B2     B3     B4     B5     B6     B7
381
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
382
  // B8     B9     BA     BB     BC     BD     BE     BF
383
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
384
  // C0     C1     C2     C3     C4     C5     C6     C7
385
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
386
  // C8     C9     CA     CB     CC     CD     CE     CF
387
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
388
  // D0     D1     D2     D3     D4     D5     D6     D7
389
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
390
  // D8     D9     DA     DB     DC     DD     DE     DF
391
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
392
  // E0     E1     E2     E3     E4     E5     E6     E7
393
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
394
  // E8     E9     EA     EB     EC     ED     EE     EF
395
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
396
  // F0     F1     F2     F3     F4     F5     F6     F7
397
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
398
  // F8     F9     FA     FB     FC     FD     FE     FF
399
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80
400
};
401
402
403
const uint8_t PATH_ENCODE_SET[32] = {
404
  // 00     01     02     03     04     05     06     07
405
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
406
  // 08     09     0A     0B     0C     0D     0E     0F
407
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
408
  // 10     11     12     13     14     15     16     17
409
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
410
  // 18     19     1A     1B     1C     1D     1E     1F
411
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
412
  // 20     21     22     23     24     25     26     27
413
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
414
  // 28     29     2A     2B     2C     2D     2E     2F
415
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
416
  // 30     31     32     33     34     35     36     37
417
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
418
  // 38     39     3A     3B     3C     3D     3E     3F
419
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x80,
420
  // 40     41     42     43     44     45     46     47
421
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
422
  // 48     49     4A     4B     4C     4D     4E     4F
423
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
424
  // 50     51     52     53     54     55     56     57
425
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
426
  // 58     59     5A     5B     5C     5D     5E     5F
427
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
428
  // 60     61     62     63     64     65     66     67
429
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
430
  // 68     69     6A     6B     6C     6D     6E     6F
431
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
432
  // 70     71     72     73     74     75     76     77
433
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
434
  // 78     79     7A     7B     7C     7D     7E     7F
435
    0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x00 | 0x80,
436
  // 80     81     82     83     84     85     86     87
437
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
438
  // 88     89     8A     8B     8C     8D     8E     8F
439
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
440
  // 90     91     92     93     94     95     96     97
441
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
442
  // 98     99     9A     9B     9C     9D     9E     9F
443
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
444
  // A0     A1     A2     A3     A4     A5     A6     A7
445
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
446
  // A8     A9     AA     AB     AC     AD     AE     AF
447
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
448
  // B0     B1     B2     B3     B4     B5     B6     B7
449
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
450
  // B8     B9     BA     BB     BC     BD     BE     BF
451
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
452
  // C0     C1     C2     C3     C4     C5     C6     C7
453
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
454
  // C8     C9     CA     CB     CC     CD     CE     CF
455
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
456
  // D0     D1     D2     D3     D4     D5     D6     D7
457
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
458
  // D8     D9     DA     DB     DC     DD     DE     DF
459
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
460
  // E0     E1     E2     E3     E4     E5     E6     E7
461
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
462
  // E8     E9     EA     EB     EC     ED     EE     EF
463
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
464
  // F0     F1     F2     F3     F4     F5     F6     F7
465
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
466
  // F8     F9     FA     FB     FC     FD     FE     FF
467
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80
468
};
469
470
const uint8_t USERINFO_ENCODE_SET[32] = {
471
  // 00     01     02     03     04     05     06     07
472
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
473
  // 08     09     0A     0B     0C     0D     0E     0F
474
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
475
  // 10     11     12     13     14     15     16     17
476
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
477
  // 18     19     1A     1B     1C     1D     1E     1F
478
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
479
  // 20     21     22     23     24     25     26     27
480
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
481
  // 28     29     2A     2B     2C     2D     2E     2F
482
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
483
  // 30     31     32     33     34     35     36     37
484
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
485
  // 38     39     3A     3B     3C     3D     3E     3F
486
    0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
487
  // 40     41     42     43     44     45     46     47
488
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
489
  // 48     49     4A     4B     4C     4D     4E     4F
490
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
491
  // 50     51     52     53     54     55     56     57
492
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
493
  // 58     59     5A     5B     5C     5D     5E     5F
494
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00,
495
  // 60     61     62     63     64     65     66     67
496
    0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
497
  // 68     69     6A     6B     6C     6D     6E     6F
498
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
499
  // 70     71     72     73     74     75     76     77
500
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
501
  // 78     79     7A     7B     7C     7D     7E     7F
502
    0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x00 | 0x80,
503
  // 80     81     82     83     84     85     86     87
504
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
505
  // 88     89     8A     8B     8C     8D     8E     8F
506
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
507
  // 90     91     92     93     94     95     96     97
508
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
509
  // 98     99     9A     9B     9C     9D     9E     9F
510
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
511
  // A0     A1     A2     A3     A4     A5     A6     A7
512
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
513
  // A8     A9     AA     AB     AC     AD     AE     AF
514
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
515
  // B0     B1     B2     B3     B4     B5     B6     B7
516
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
517
  // B8     B9     BA     BB     BC     BD     BE     BF
518
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
519
  // C0     C1     C2     C3     C4     C5     C6     C7
520
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
521
  // C8     C9     CA     CB     CC     CD     CE     CF
522
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
523
  // D0     D1     D2     D3     D4     D5     D6     D7
524
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
525
  // D8     D9     DA     DB     DC     DD     DE     DF
526
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
527
  // E0     E1     E2     E3     E4     E5     E6     E7
528
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
529
  // E8     E9     EA     EB     EC     ED     EE     EF
530
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
531
  // F0     F1     F2     F3     F4     F5     F6     F7
532
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
533
  // F8     F9     FA     FB     FC     FD     FE     FF
534
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80
535
};
536
537
const uint8_t QUERY_ENCODE_SET_NONSPECIAL[32] = {
538
  // 00     01     02     03     04     05     06     07
539
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
540
  // 08     09     0A     0B     0C     0D     0E     0F
541
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
542
  // 10     11     12     13     14     15     16     17
543
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
544
  // 18     19     1A     1B     1C     1D     1E     1F
545
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
546
  // 20     21     22     23     24     25     26     27
547
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
548
  // 28     29     2A     2B     2C     2D     2E     2F
549
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
550
  // 30     31     32     33     34     35     36     37
551
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
552
  // 38     39     3A     3B     3C     3D     3E     3F
553
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
554
  // 40     41     42     43     44     45     46     47
555
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
556
  // 48     49     4A     4B     4C     4D     4E     4F
557
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
558
  // 50     51     52     53     54     55     56     57
559
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
560
  // 58     59     5A     5B     5C     5D     5E     5F
561
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
562
  // 60     61     62     63     64     65     66     67
563
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
564
  // 68     69     6A     6B     6C     6D     6E     6F
565
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
566
  // 70     71     72     73     74     75     76     77
567
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
568
  // 78     79     7A     7B     7C     7D     7E     7F
569
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
570
  // 80     81     82     83     84     85     86     87
571
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
572
  // 88     89     8A     8B     8C     8D     8E     8F
573
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
574
  // 90     91     92     93     94     95     96     97
575
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
576
  // 98     99     9A     9B     9C     9D     9E     9F
577
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
578
  // A0     A1     A2     A3     A4     A5     A6     A7
579
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
580
  // A8     A9     AA     AB     AC     AD     AE     AF
581
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
582
  // B0     B1     B2     B3     B4     B5     B6     B7
583
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
584
  // B8     B9     BA     BB     BC     BD     BE     BF
585
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
586
  // C0     C1     C2     C3     C4     C5     C6     C7
587
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
588
  // C8     C9     CA     CB     CC     CD     CE     CF
589
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
590
  // D0     D1     D2     D3     D4     D5     D6     D7
591
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
592
  // D8     D9     DA     DB     DC     DD     DE     DF
593
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
594
  // E0     E1     E2     E3     E4     E5     E6     E7
595
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
596
  // E8     E9     EA     EB     EC     ED     EE     EF
597
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
598
  // F0     F1     F2     F3     F4     F5     F6     F7
599
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
600
  // F8     F9     FA     FB     FC     FD     FE     FF
601
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80
602
};
603
604
// Same as QUERY_ENCODE_SET_NONSPECIAL, but with 0x27 (') encoded.
605
const uint8_t QUERY_ENCODE_SET_SPECIAL[32] = {
606
  // 00     01     02     03     04     05     06     07
607
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
608
  // 08     09     0A     0B     0C     0D     0E     0F
609
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
610
  // 10     11     12     13     14     15     16     17
611
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
612
  // 18     19     1A     1B     1C     1D     1E     1F
613
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
614
  // 20     21     22     23     24     25     26     27
615
    0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x80,
616
  // 28     29     2A     2B     2C     2D     2E     2F
617
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
618
  // 30     31     32     33     34     35     36     37
619
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
620
  // 38     39     3A     3B     3C     3D     3E     3F
621
    0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
622
  // 40     41     42     43     44     45     46     47
623
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
624
  // 48     49     4A     4B     4C     4D     4E     4F
625
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
626
  // 50     51     52     53     54     55     56     57
627
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
628
  // 58     59     5A     5B     5C     5D     5E     5F
629
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
630
  // 60     61     62     63     64     65     66     67
631
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
632
  // 68     69     6A     6B     6C     6D     6E     6F
633
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
634
  // 70     71     72     73     74     75     76     77
635
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
636
  // 78     79     7A     7B     7C     7D     7E     7F
637
    0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
638
  // 80     81     82     83     84     85     86     87
639
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
640
  // 88     89     8A     8B     8C     8D     8E     8F
641
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
642
  // 90     91     92     93     94     95     96     97
643
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
644
  // 98     99     9A     9B     9C     9D     9E     9F
645
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
646
  // A0     A1     A2     A3     A4     A5     A6     A7
647
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
648
  // A8     A9     AA     AB     AC     AD     AE     AF
649
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
650
  // B0     B1     B2     B3     B4     B5     B6     B7
651
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
652
  // B8     B9     BA     BB     BC     BD     BE     BF
653
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
654
  // C0     C1     C2     C3     C4     C5     C6     C7
655
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
656
  // C8     C9     CA     CB     CC     CD     CE     CF
657
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
658
  // D0     D1     D2     D3     D4     D5     D6     D7
659
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
660
  // D8     D9     DA     DB     DC     DD     DE     DF
661
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
662
  // E0     E1     E2     E3     E4     E5     E6     E7
663
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
664
  // E8     E9     EA     EB     EC     ED     EE     EF
665
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
666
  // F0     F1     F2     F3     F4     F5     F6     F7
667
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
668
  // F8     F9     FA     FB     FC     FD     FE     FF
669
    0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80
670
};
671
672
11592835
bool BitAt(const uint8_t a[], const uint8_t i) {
673
11592835
  return !!(a[i >> 3] & (1 << (i & 7)));
674
}
675
676
// Appends ch to str. If ch position in encode_set is set, the ch will
677
// be percent-encoded then appended.
678
11592802
void AppendOrEscape(std::string* str,
679
                           const unsigned char ch,
680
                           const uint8_t encode_set[]) {
681
11592802
  if (BitAt(encode_set, ch))
682
1902
    *str += hex[ch];
683
  else
684
11590961
    *str += ch;
685
11592933
}
686
687
template <typename T>
688
1059
unsigned hex2bin(const T ch) {
689

1059
  if (ch >= '0' && ch <= '9')
690
809
    return ch - '0';
691

250
  if (ch >= 'A' && ch <= 'F')
692
110
    return 10 + (ch - 'A');
693

140
  if (ch >= 'a' && ch <= 'f')
694
140
    return 10 + (ch - 'a');
695
  return static_cast<unsigned>(-1);
696
}
697
698
4416
std::string PercentDecode(const char* input, size_t len) {
699
4416
  std::string dest;
700
4416
  if (len == 0)
701
2
    return dest;
702
4414
  dest.reserve(len);
703
4413
  const char* pointer = input;
704
4413
  const char* end = input + len;
705
706
193675
  while (pointer < end) {
707
94630
    const char ch = pointer[0];
708
94630
    size_t remaining = end - pointer - 1;
709


188911
    if (ch != '%' || remaining < 2 ||
710
361
        (ch == '%' &&
711
718
         (!IsASCIIHexDigit(pointer[1]) ||
712
357
          !IsASCIIHexDigit(pointer[2])))) {
713
94281
      dest += ch;
714
94282
      pointer++;
715
94282
      continue;
716
    } else {
717
349
      unsigned a = hex2bin(pointer[1]);
718
349
      unsigned b = hex2bin(pointer[2]);
719
349
      char c = static_cast<char>(a * 16 + b);
720
349
      dest += c;
721
349
      pointer += 3;
722
    }
723
  }
724
4414
  return dest;
725
}
726
727
#define SPECIALS(XX)                                                          \
728
  XX(ftp, 21, "ftp:")                                                         \
729
  XX(file, -1, "file:")                                                       \
730
  XX(http, 80, "http:")                                                       \
731
  XX(https, 443, "https:")                                                    \
732
  XX(ws, 80, "ws:")                                                           \
733
  XX(wss, 443, "wss:")
734
735
297277
bool IsSpecial(const std::string& scheme) {
736
#define V(_, __, name) if (scheme == name) return true;
737



297277
  SPECIALS(V);
738
#undef V
739
6420
  return false;
740
}
741
742
118459
Local<String> GetSpecial(Environment* env, const std::string& scheme) {
743
#define V(key, _, name) if (scheme == name)                                  \
744
    return env->url_special_##key##_string();
745



118459
  SPECIALS(V)
746
#undef V
747
  UNREACHABLE();
748
}
749
750
117091
int NormalizePort(const std::string& scheme, int p) {
751
#define V(_, port, name) if (scheme == name && p == port) return -1;
752









117091
  SPECIALS(V);
753
#undef V
754
10473
  return p;
755
}
756
757
// https://url.spec.whatwg.org/#start-with-a-windows-drive-letter
758
3092
bool StartsWithWindowsDriveLetter(const char* p, const char* end) {
759
3092
  size_t length = end - p;
760
2837
  return length >= 2 &&
761

3170
    IsWindowsDriveLetter(p[0], p[1]) &&
762
36
    (length == 2 ||
763
50
      p[2] == '/' ||
764
20
      p[2] == '\\' ||
765
10
      p[2] == '?' ||
766
3096
      p[2] == '#');
767
}
768
769
#if defined(NODE_HAVE_I18N_SUPPORT)
770
195
bool ToUnicode(const std::string& input, std::string* output) {
771
390
  MaybeStackBuffer<char> buf;
772
195
  if (i18n::ToUnicode(&buf, input.c_str(), input.length()) < 0)
773
    return false;
774
195
  output->assign(*buf, buf.length());
775
195
  return true;
776
}
777
778
4403
bool ToASCII(const std::string& input, std::string* output) {
779
8808
  MaybeStackBuffer<char> buf;
780
4403
  if (i18n::ToASCII(&buf, input.c_str(), input.length()) < 0)
781
94
    return false;
782
4311
  if (buf.length() == 0)
783
18
    return false;
784
4293
  output->assign(*buf, buf.length());
785
4293
  return true;
786
}
787
#else
788
// Intentional non-ops if ICU is not present.
789
bool ToUnicode(const std::string& input, std::string* output) {
790
  *output = input;
791
  return true;
792
}
793
794
bool ToASCII(const std::string& input, std::string* output) {
795
  *output = input;
796
  return true;
797
}
798
#endif
799
800
137
void URLHost::ParseIPv6Host(const char* input, size_t length) {
801
137
  CHECK_EQ(type_, HostType::H_FAILED);
802
137
  unsigned size = arraysize(value_.ipv6);
803
1233
  for (unsigned n = 0; n < size; n++)
804
1096
    value_.ipv6[n] = 0;
805
137
  uint16_t* piece_pointer = &value_.ipv6[0];
806
137
  uint16_t* const buffer_end = piece_pointer + size;
807
137
  uint16_t* compress_pointer = nullptr;
808
137
  const char* pointer = input;
809
137
  const char* end = pointer + length;
810
  unsigned value, len, numbers_seen;
811
137
  char ch = pointer < end ? pointer[0] : kEOL;
812
137
  if (ch == ':') {
813

51
    if (length < 2 || pointer[1] != ':')
814
4
      return;
815
47
    pointer += 2;
816
47
    ch = pointer < end ? pointer[0] : kEOL;
817
47
    piece_pointer++;
818
47
    compress_pointer = piece_pointer;
819
  }
820
671
  while (ch != kEOL) {
821
353
    if (piece_pointer >= buffer_end)
822
4
      return;
823
349
    if (ch == ':') {
824
30
      if (compress_pointer != nullptr)
825
4
        return;
826
26
      pointer++;
827
26
      ch = pointer < end ? pointer[0] : kEOL;
828
26
      piece_pointer++;
829
26
      compress_pointer = piece_pointer;
830
26
      continue;
831
    }
832
319
    value = 0;
833
319
    len = 0;
834

1041
    while (len < 4 && IsASCIIHexDigit(ch)) {
835
361
      value = value * 0x10 + hex2bin(ch);
836
361
      pointer++;
837
361
      ch = pointer < end ? pointer[0] : kEOL;
838
361
      len++;
839
    }
840

319
    switch (ch) {
841
      case '.':
842
64
        if (len == 0)
843
4
          return;
844
60
        pointer -= len;
845
60
        ch = pointer < end ? pointer[0] : kEOL;
846
60
        if (piece_pointer > buffer_end - 2)
847
4
          return;
848
56
        numbers_seen = 0;
849
352
        while (ch != kEOL) {
850
192
          value = 0xffffffff;
851
192
          if (numbers_seen > 0) {
852

136
            if (ch == '.' && numbers_seen < 4) {
853
124
              pointer++;
854
124
              ch = pointer < end ? pointer[0] : kEOL;
855
            } else {
856
12
              return;
857
            }
858
          }
859
180
          if (!IsASCIIDigit(ch))
860
24
            return;
861
540
          while (IsASCIIDigit(ch)) {
862
200
            unsigned number = ch - '0';
863
200
            if (value == 0xffffffff) {
864
156
              value = number;
865
44
            } else if (value == 0) {
866
4
              return;
867
            } else {
868
40
              value = value * 10 + number;
869
            }
870
196
            if (value > 255)
871
4
              return;
872
192
            pointer++;
873
192
            ch = pointer < end ? pointer[0] : kEOL;
874
          }
875
148
          *piece_pointer = *piece_pointer * 0x100 + value;
876
148
          numbers_seen++;
877

148
          if (numbers_seen == 2 || numbers_seen == 4)
878
60
            piece_pointer++;
879
        }
880
12
        if (numbers_seen != 4)
881
4
          return;
882
8
        continue;
883
      case ':':
884
206
        pointer++;
885
206
        ch = pointer < end ? pointer[0] : kEOL;
886
206
        if (ch == kEOL)
887
4
          return;
888
202
        break;
889
      case kEOL:
890
33
        break;
891
      default:
892
16
        return;
893
    }
894
235
    *piece_pointer = value;
895
235
    piece_pointer++;
896
  }
897
898
49
  if (compress_pointer != nullptr) {
899
33
    int64_t swaps = piece_pointer - compress_pointer;
900
33
    piece_pointer = buffer_end - 1;
901

107
    while (piece_pointer != &value_.ipv6[0] && swaps > 0) {
902
37
      uint16_t temp = *piece_pointer;
903
37
      uint16_t* swap_piece = compress_pointer + swaps - 1;
904
37
      *piece_pointer = *swap_piece;
905
37
      *swap_piece = temp;
906
37
       piece_pointer--;
907
37
       swaps--;
908
    }
909

16
  } else if (compress_pointer == nullptr &&
910
             piece_pointer != buffer_end) {
911
4
    return;
912
  }
913
45
  type_ = HostType::H_IPV6;
914
}
915
916
4380
int64_t ParseNumber(const char* start, const char* end) {
917
4380
  unsigned R = 10;
918

4380
  if (end - start >= 2 && start[0] == '0' && (start[1] | 0x20) == 'x') {
919
48
    start += 2;
920
48
    R = 16;
921
  }
922
4380
  if (end - start == 0) {
923
8
    return 0;
924

4372
  } else if (R == 10 && end - start > 1 && start[0] == '0') {
925
46
    start++;
926
46
    R = 8;
927
  }
928
4372
  const char* p = start;
929
930
6572
  while (p < end) {
931
5158
    const char ch = p[0];
932

5158
    switch (R) {
933
      case 8:
934

202
        if (ch < '0' || ch > '7')
935
20
          return -1;
936
182
        break;
937
      case 10:
938
4748
        if (!IsASCIIDigit(ch))
939
4034
          return -1;
940
714
        break;
941
      case 16:
942
208
        if (!IsASCIIHexDigit(ch))
943
4
          return -1;
944
204
        break;
945
    }
946
1100
    p++;
947
  }
948
314
  return strtoll(start, nullptr, R);
949
}
950
951
4178
void URLHost::ParseIPv4Host(const char* input, size_t length, bool* is_ipv4) {
952
4178
  CHECK_EQ(type_, HostType::H_FAILED);
953
4178
  *is_ipv4 = false;
954
4178
  const char* pointer = input;
955
4178
  const char* mark = input;
956
4178
  const char* end = pointer + length;
957
4178
  int parts = 0;
958
4178
  uint32_t val = 0;
959
  uint64_t numbers[4];
960
4178
  int tooBigNumbers = 0;
961
4178
  if (length == 0)
962
4102
    return;
963
964
71236
  while (pointer <= end) {
965
37603
    const char ch = pointer < end ? pointer[0] : kEOL;
966
37603
    int64_t remaining = end - pointer - 1;
967

37603
    if (ch == '.' || ch == kEOL) {
968
4392
      if (++parts > static_cast<int>(arraysize(numbers)))
969
4
        return;
970
4392
      if (pointer == mark)
971
12
        return;
972
4380
      int64_t n = ParseNumber(mark, pointer);
973
4380
      if (n < 0)
974
4058
        return;
975
976
322
      if (n > 255) {
977
112
        tooBigNumbers++;
978
      }
979
322
      numbers[parts - 1] = n;
980
322
      mark = pointer + 1;
981

322
      if (ch == '.' && remaining == 0)
982
4
        break;
983
    }
984
33529
    pointer++;
985
  }
986
108
  CHECK_GT(parts, 0);
987
108
  *is_ipv4 = true;
988
989
  // If any but the last item in numbers is greater than 255, return failure.
990
  // If the last item in numbers is greater than or equal to
991
  // 256^(5 - the number of items in numbers), return failure.
992

212
  if (tooBigNumbers > 1 ||
993

272
      (tooBigNumbers == 1 && numbers[parts - 1] <= 255) ||
994
100
      numbers[parts - 1] >= pow(256, static_cast<double>(5 - parts))) {
995
28
    return;
996
  }
997
998
80
  type_ = HostType::H_IPV4;
999
80
  val = static_cast<uint32_t>(numbers[parts - 1]);
1000
196
  for (int n = 0; n < parts - 1; n++) {
1001
116
    double b = 3 - n;
1002
116
    val +=
1003
116
        static_cast<uint32_t>(numbers[n]) * static_cast<uint32_t>(pow(256, b));
1004
  }
1005
1006
80
  value_.ipv4 = val;
1007
}
1008
1009
496
void URLHost::ParseOpaqueHost(const char* input, size_t length) {
1010
496
  CHECK_EQ(type_, HostType::H_FAILED);
1011
938
  std::string output;
1012
496
  output.reserve(length);
1013
2913
  for (size_t i = 0; i < length; i++) {
1014
2471
    const char ch = input[i];
1015

2471
    if (ch != '%' && IsForbiddenHostCodePoint(ch)) {
1016
54
      return;
1017
    } else {
1018
2417
      AppendOrEscape(&output, ch, C0_CONTROL_ENCODE_SET);
1019
    }
1020
  }
1021
1022
442
  SetOpaque(std::move(output));
1023
}
1024
1025
5044
void URLHost::ParseHost(const char* input,
1026
                        size_t length,
1027
                        bool is_special,
1028
                        bool unicode) {
1029
5044
  CHECK_EQ(type_, HostType::H_FAILED);
1030
5044
  const char* pointer = input;
1031
1032
5044
  if (length == 0)
1033
972
    return;
1034
1035
5044
  if (pointer[0] == '[') {
1036
145
    if (pointer[length - 1] != ']')
1037
8
      return;
1038
137
    return ParseIPv6Host(++pointer, length - 2);
1039
  }
1040
1041
4899
  if (!is_special)
1042
496
    return ParseOpaqueHost(input, length);
1043
1044
  // First, we have to percent decode
1045
8476
  std::string decoded = PercentDecode(input, length);
1046
1047
  // Then we have to punycode toASCII
1048
4403
  if (!ToASCII(decoded, &decoded))
1049
112
    return;
1050
1051
  // If any of the following characters are still present, we have to fail
1052
97875
  for (size_t n = 0; n < decoded.size(); n++) {
1053
93699
    const char ch = decoded[n];
1054
93694
    if (IsForbiddenHostCodePoint(ch)) {
1055
111
      return;
1056
    }
1057
  }
1058
1059
  // Check to see if it's an IPv4 IP address
1060
  bool is_ipv4;
1061
4177
  ParseIPv4Host(decoded.c_str(), decoded.length(), &is_ipv4);
1062
4182
  if (is_ipv4)
1063
108
    return;
1064
1065
  // If the unicode flag is set, run the result through punycode ToUnicode
1066

4074
  if (unicode && !ToUnicode(decoded, &decoded))
1067
    return;
1068
1069
  // It's not an IPv4 or IPv6 address, it must be a domain
1070
4074
  SetDomain(std::move(decoded));
1071
}
1072
1073
// Locates the longest sequence of 0 segments in an IPv6 address
1074
// in order to use the :: compression when serializing
1075
template <typename T>
1076
45
T* FindLongestZeroSequence(T* values, size_t len) {
1077
45
  T* start = values;
1078
45
  T* end = start + len;
1079
45
  T* result = nullptr;
1080
1081
45
  T* current = nullptr;
1082
45
  unsigned counter = 0, longest = 1;
1083
1084
765
  while (start < end) {
1085
360
    if (*start == 0) {
1086
265
      if (current == nullptr)
1087
59
        current = start;
1088
265
      counter++;
1089
    } else {
1090
95
      if (counter > longest) {
1091
37
        longest = counter;
1092
37
        result = current;
1093
      }
1094
95
      counter = 0;
1095
95
      current = nullptr;
1096
    }
1097
360
    start++;
1098
  }
1099
45
  if (counter > longest)
1100
6
    result = current;
1101
45
  return result;
1102
}
1103
1104
4638
std::string URLHost::ToStringMove() {
1105
4638
  std::string return_value;
1106
4638
  switch (type_) {
1107
    case HostType::H_DOMAIN:
1108
    case HostType::H_OPAQUE:
1109
4513
      return_value = std::move(value_.domain_or_opaque);
1110
4512
      break;
1111
    default:
1112
125
      return_value = ToString();
1113
125
      break;
1114
  }
1115
4637
  Reset();
1116
4637
  return return_value;
1117
}
1118
1119
125
std::string URLHost::ToString() const {
1120
250
  std::string dest;
1121

125
  switch (type_) {
1122
    case HostType::H_DOMAIN:
1123
    case HostType::H_OPAQUE:
1124
      return value_.domain_or_opaque;
1125
      break;
1126
    case HostType::H_IPV4: {
1127
80
      dest.reserve(15);
1128
80
      uint32_t value = value_.ipv4;
1129
400
      for (int n = 0; n < 4; n++) {
1130
        char buf[4];
1131
320
        snprintf(buf, sizeof(buf), "%d", value % 256);
1132
320
        dest.insert(0, buf);
1133
320
        if (n < 3)
1134
240
          dest.insert(0, 1, '.');
1135
320
        value /= 256;
1136
      }
1137
80
      break;
1138
    }
1139
    case HostType::H_IPV6: {
1140
45
      dest.reserve(41);
1141
45
      dest += '[';
1142
45
      const uint16_t* start = &value_.ipv6[0];
1143
      const uint16_t* compress_pointer =
1144
45
          FindLongestZeroSequence(start, 8);
1145
45
      bool ignore0 = false;
1146
405
      for (int n = 0; n <= 7; n++) {
1147
360
        const uint16_t* piece = &value_.ipv6[n];
1148

360
        if (ignore0 && *piece == 0)
1149
449
          continue;
1150
156
        else if (ignore0)
1151
35
          ignore0 = false;
1152
156
        if (compress_pointer == piece) {
1153
41
          dest += n == 0 ? "::" : ":";
1154
41
          ignore0 = true;
1155
41
          continue;
1156
        }
1157
        char buf[5];
1158
115
        snprintf(buf, sizeof(buf), "%x", *piece);
1159
115
        dest += buf;
1160
115
        if (n < 7)
1161
76
          dest += ':';
1162
      }
1163
45
      dest += ']';
1164
45
      break;
1165
    }
1166
    case HostType::H_FAILED:
1167
      break;
1168
  }
1169
125
  return dest;
1170
}
1171
1172
4693
bool ParseHost(const std::string& input,
1173
               std::string* output,
1174
               bool is_special,
1175
               bool unicode = false) {
1176
4693
  if (input.empty()) {
1177
88
    output->clear();
1178
88
    return true;
1179
  }
1180
9213
  URLHost host;
1181
4606
  host.ParseHost(input.c_str(), input.length(), is_special, unicode);
1182
4608
  if (host.ParsingFailed())
1183
381
    return false;
1184
4226
  *output = host.ToStringMove();
1185
4226
  return true;
1186
}
1187
1188
5055
std::vector<std::string> FromJSStringArray(Environment* env,
1189
                                           Local<Array> array) {
1190
5055
  std::vector<std::string> vec;
1191
5055
  if (array->Length() > 0)
1192
5039
    vec.reserve(array->Length());
1193
66000
  for (size_t n = 0; n < array->Length(); n++) {
1194
83850
    Local<Value> val = array->Get(env->context(), n).ToLocalChecked();
1195
55902
    if (val->IsString()) {
1196
55898
      Utf8Value value(env->isolate(), val.As<String>());
1197
27950
      vec.emplace_back(*value, value.length());
1198
    }
1199
  }
1200
5052
  return vec;
1201
}
1202
1203
5055
url_data HarvestBase(Environment* env, Local<Object> base_obj) {
1204
5055
  url_data base;
1205
5055
  Local<Context> context = env->context();
1206
1207
  Local<Value> flags =
1208
20219
      base_obj->Get(env->context(), env->flags_string()).ToLocalChecked();
1209
5054
  if (flags->IsInt32())
1210
10107
    base.flags = flags->Int32Value(context).FromJust();
1211
1212
  Local<Value> port =
1213
20219
      base_obj->Get(env->context(), env->port_string()).ToLocalChecked();
1214
5055
  if (port->IsInt32())
1215
16
    base.port = port->Int32Value(context).FromJust();
1216
1217
  Local<Value> scheme =
1218
20218
      base_obj->Get(env->context(), env->scheme_string()).ToLocalChecked();
1219
5055
  base.scheme = Utf8Value(env->isolate(), scheme).out();
1220
1221
  auto GetStr = [&](std::string url_data::*member,
1222
                    int flag,
1223
                    Local<String> name,
1224
25252
                    bool empty_as_present) {
1225
89842
    Local<Value> value = base_obj->Get(env->context(), name).ToLocalChecked();
1226
50542
    if (value->IsString()) {
1227
28143
      Utf8Value utf8value(env->isolate(), value.As<String>());
1228
18060
      (base.*member).assign(*utf8value, utf8value.length());
1229

34283
      if (empty_as_present || value.As<String>()->Length() != 0) {
1230
3987
        base.flags |= flag;
1231
      }
1232
    }
1233
30320
  };
1234
5054
  GetStr(&url_data::username,
1235
         URL_FLAGS_HAS_USERNAME,
1236
         env->username_string(),
1237
5053
         false);
1238
5052
  GetStr(&url_data::password,
1239
         URL_FLAGS_HAS_PASSWORD,
1240
         env->password_string(),
1241
5051
         false);
1242
5054
  GetStr(&url_data::host, URL_FLAGS_HAS_HOST, env->host_string(), true);
1243
5054
  GetStr(&url_data::query, URL_FLAGS_HAS_QUERY, env->query_string(), true);
1244
5055
  GetStr(&url_data::fragment,
1245
         URL_FLAGS_HAS_FRAGMENT,
1246
         env->fragment_string(),
1247
5052
         true);
1248
1249
  Local<Value>
1250
20217
      path = base_obj->Get(env->context(), env->path_string()).ToLocalChecked();
1251
5055
  if (path->IsArray()) {
1252
5055
    base.flags |= URL_FLAGS_HAS_PATH;
1253
5055
    base.path = FromJSStringArray(env, path.As<Array>());
1254
  }
1255
5052
  return base;
1256
}
1257
1258
38201
url_data HarvestContext(Environment* env, Local<Object> context_obj) {
1259
38201
  url_data context;
1260
  Local<Value> flags =
1261
152801
      context_obj->Get(env->context(), env->flags_string()).ToLocalChecked();
1262
38201
  if (flags->IsInt32()) {
1263
    static constexpr int32_t kCopyFlagsMask =
1264
        URL_FLAGS_SPECIAL |
1265
        URL_FLAGS_CANNOT_BE_BASE |
1266
        URL_FLAGS_HAS_USERNAME |
1267
        URL_FLAGS_HAS_PASSWORD |
1268
        URL_FLAGS_HAS_HOST;
1269
76400
    context.flags |= flags.As<Int32>()->Value() & kCopyFlagsMask;
1270
  }
1271
  Local<Value> scheme =
1272
152802
      context_obj->Get(env->context(), env->scheme_string()).ToLocalChecked();
1273
76402
  if (scheme->IsString()) {
1274
76402
    Utf8Value value(env->isolate(), scheme);
1275
38201
    context.scheme.assign(*value, value.length());
1276
  }
1277
  Local<Value> port =
1278
152804
      context_obj->Get(env->context(), env->port_string()).ToLocalChecked();
1279
38201
  if (port->IsInt32())
1280
474
    context.port = port.As<Int32>()->Value();
1281
38201
  if (context.flags & URL_FLAGS_HAS_USERNAME) {
1282
    Local<Value> username =
1283
442
        context_obj->Get(env->context(),
1284
1105
                         env->username_string()).ToLocalChecked();
1285
442
    CHECK(username->IsString());
1286
442
    Utf8Value value(env->isolate(), username);
1287
221
    context.username.assign(*value, value.length());
1288
  }
1289
38201
  if (context.flags & URL_FLAGS_HAS_PASSWORD) {
1290
    Local<Value> password =
1291
418
        context_obj->Get(env->context(),
1292
1045
                         env->password_string()).ToLocalChecked();
1293
418
    CHECK(password->IsString());
1294
418
    Utf8Value value(env->isolate(), password);
1295
209
    context.password.assign(*value, value.length());
1296
  }
1297
  Local<Value> host =
1298
76402
      context_obj->Get(env->context(),
1299
191005
                       env->host_string()).ToLocalChecked();
1300
76402
  if (host->IsString()) {
1301
76334
    Utf8Value value(env->isolate(), host);
1302
38167
    context.host.assign(*value, value.length());
1303
  }
1304
38201
  return context;
1305
}
1306
1307
// Single dot segment can be ".", "%2e", or "%2E"
1308
2571494
bool IsSingleDotSegment(const std::string& str) {
1309
2571494
  switch (str.size()) {
1310
    case 1:
1311
3196
      return str == ".";
1312
    case 3:
1313
120461
      return str[0] == '%' &&
1314

120445
             str[1] == '2' &&
1315
120445
             ASCIILowercase(str[2]) == 'e';
1316
    default:
1317
2447928
      return false;
1318
  }
1319
}
1320
1321
// Double dot segment can be:
1322
//   "..", ".%2e", ".%2E", "%2e.", "%2E.",
1323
//   "%2e%2e", "%2E%2E", "%2e%2E", or "%2E%2e"
1324
1287967
bool IsDoubleDotSegment(const std::string& str) {
1325

1287967
  switch (str.size()) {
1326
    case 2:
1327
2507
      return str == "..";
1328
    case 4:
1329

307023
      if (str[0] != '.' && str[0] != '%')
1330
307004
        return false;
1331
32
      return ((str[0] == '.' &&
1332
17
               str[1] == '%' &&
1333
8
               str[2] == '2' &&
1334

48
               ASCIILowercase(str[3]) == 'e') ||
1335
21
              (str[0] == '%' &&
1336
12
               str[1] == '2' &&
1337
12
               ASCIILowercase(str[2]) == 'e' &&
1338
25
               str[3] == '.'));
1339
    case 6:
1340
63414
      return (str[0] == '%' &&
1341
24
              str[1] == '2' &&
1342
16
              ASCIILowercase(str[2]) == 'e' &&
1343
8
              str[3] == '%' &&
1344

63410
              str[4] == '2' &&
1345
63406
              ASCIILowercase(str[5]) == 'e');
1346
    default:
1347
915048
      return false;
1348
  }
1349
}
1350
1351
5193
void ShortenUrlPath(struct url_data* url) {
1352
5193
  if (url->path.empty()) return;
1353


5293
  if (url->path.size() == 1 && url->scheme == "file:" &&
1354
376
      IsNormalizedWindowsDriveLetter(url->path[0])) return;
1355
4917
  url->path.pop_back();
1356
}
1357
1358
}  // anonymous namespace
1359
1360
192097
void URL::Parse(const char* input,
1361
                size_t len,
1362
                enum url_parse_state state_override,
1363
                struct url_data* url,
1364
                bool has_url,
1365
                const struct url_data* base,
1366
                bool has_base) {
1367
192097
  const char* p = input;
1368
192097
  const char* end = input + len;
1369
1370
192097
  if (!has_url) {
1371
121222
    for (const char* ptr = p; ptr < end; ptr++) {
1372
121204
      if (IsC0ControlOrSpace(*ptr))
1373
56
        p++;
1374
      else
1375
121148
        break;
1376
    }
1377
121214
    for (const char* ptr = end - 1; ptr >= p; ptr--) {
1378
121195
      if (IsC0ControlOrSpace(*ptr))
1379
48
        end--;
1380
      else
1381
121149
        break;
1382
    }
1383
121168
    input = p;
1384
121168
    len = end - p;
1385
  }
1386
1387
  // The spec says we should strip out any ASCII tabs or newlines.
1388
  // In those cases, we create another std::string instance with the filtered
1389
  // contents, but in the general case we avoid the overhead.
1390
381792
  std::string whitespace_stripped;
1391
13921060
  for (const char* ptr = p; ptr < end; ptr++) {
1392
13729118
    if (!IsASCIITabOrNewline(*ptr))
1393
13728962
      continue;
1394
    // Hit tab or newline. Allocate storage, copy what we have until now,
1395
    // and then iterate and filter all similar characters out.
1396
164
    whitespace_stripped.reserve(len - 1);
1397
164
    whitespace_stripped.assign(p, ptr - p);
1398
    // 'ptr + 1' skips the current char, which we know to be tab or newline.
1399
999
    for (ptr = ptr + 1; ptr < end; ptr++) {
1400
835
      if (!IsASCIITabOrNewline(*ptr))
1401
751
        whitespace_stripped += *ptr;
1402
    }
1403
1404
    // Update variables like they should have looked like if the string
1405
    // had been stripped of whitespace to begin with.
1406
164
    input = whitespace_stripped.c_str();
1407
164
    len = whitespace_stripped.size();
1408
164
    p = input;
1409
164
    end = input + len;
1410
164
    break;
1411
  }
1412
1413
192106
  bool atflag = false;  // Set when @ has been seen.
1414
192106
  bool square_bracket_flag = false;  // Set inside of [...]
1415
192106
  bool password_token_seen_flag = false;  // Set after a : after an username.
1416
1417
381799
  std::string buffer;
1418
1419
  // Set the initial parse state.
1420
194338
  const bool has_state_override = state_override != kUnknownState;
1421
194338
  enum url_parse_state state = has_state_override ? state_override :
1422
194338
                                                    kSchemeStart;
1423
1424

194338
  if (state < kSchemeStart || state > kFragment) {
1425
    url->flags |= URL_FLAGS_INVALID_PARSE_STATE;
1426
    return;
1427
  }
1428
1429

28555900
  while (p <= end) {
1430
14185428
    const char ch = p < end ? p[0] : kEOL;
1431
14185428
    bool special = (url->flags & URL_FLAGS_SPECIAL);
1432
    bool cannot_be_base;
1433

14185428
    bool special_back_slash = (special && ch == '\\');
1434
1435





14185428
    switch (state) {
1436
      case kSchemeStart:
1437
121252
        if (IsASCIIAlpha(ch)) {
1438
117017
          buffer += ASCIILowercase(ch);
1439
114933
          state = kScheme;
1440
4076
        } else if (!has_state_override) {
1441
4066
          state = kNoScheme;
1442
4066
          continue;
1443
        } else {
1444
10
          url->flags |= URL_FLAGS_FAILED;
1445
10
          return;
1446
        }
1447
114933
        break;
1448
      case kScheme:
1449


475781
        if (IsASCIIAlphanumeric(ch) || ch == '+' || ch == '-' || ch == '.') {
1450
358784
          buffer += ASCIILowercase(ch);
1451

117014
        } else if (ch == ':' || (has_state_override && ch == kEOL)) {
1452

116159
          if (has_state_override && buffer.size() == 0) {
1453
            url->flags |= URL_FLAGS_TERMINATED;
1454
            return;
1455
          }
1456
116159
          buffer += ':';
1457
1458
116160
          bool new_is_special = IsSpecial(buffer);
1459
1460
116160
          if (has_state_override) {
1461

98
            if ((special != new_is_special) ||
1462
45
                ((buffer == "file:") &&
1463
8
                 ((url->flags & URL_FLAGS_HAS_USERNAME) ||
1464
4
                  (url->flags & URL_FLAGS_HAS_PASSWORD) ||
1465

126
                  (url->port != -1))) ||
1466
39
                  (url->scheme == "file:" && url->host.empty())) {
1467
32
              url->flags |= URL_FLAGS_TERMINATED;
1468
32
              return;
1469
            }
1470
          }
1471
1472
116128
          url->scheme = std::move(buffer);
1473
116127
          url->port = NormalizePort(url->scheme, url->port);
1474
116130
          if (new_is_special) {
1475
110389
            url->flags |= URL_FLAGS_SPECIAL;
1476
110389
            special = true;
1477
          } else {
1478
5741
            url->flags &= ~URL_FLAGS_SPECIAL;
1479
5741
            special = false;
1480
          }
1481

116130
          special_back_slash = (special && ch == '\\');
1482
116130
          buffer.clear();
1483
116131
          if (has_state_override)
1484
27
            return;
1485
116104
          if (url->scheme == "file:") {
1486
106570
            state = kFile;
1487

13340
          } else if (special &&
1488

10511
                     has_base &&
1489
979
                     url->scheme == base->scheme) {
1490
317
            state = kSpecialRelativeOrAuthority;
1491
9215
          } else if (special) {
1492
3490
            state = kSpecialAuthoritySlashes;
1493

5725
          } else if (p + 1 < end && p[1] == '/') {
1494
681
            state = kPathOrAuthority;
1495
681
            p++;
1496
          } else {
1497
5044
            url->flags |= URL_FLAGS_CANNOT_BE_BASE;
1498
5044
            url->flags |= URL_FLAGS_HAS_PATH;
1499
5044
            url->path.emplace_back("");
1500
5043
            state = kCannotBeBase;
1501
116101
          }
1502
855
        } else if (!has_state_override) {
1503
847
          buffer.clear();
1504
847
          state = kNoScheme;
1505
847
          p = input;
1506
847
          continue;
1507
        } else {
1508
8
          url->flags |= URL_FLAGS_FAILED;
1509
8
          return;
1510
        }
1511
474863
        break;
1512
      case kNoScheme:
1513

5071
        cannot_be_base = has_base && (base->flags & URL_FLAGS_CANNOT_BE_BASE);
1514

5071
        if (!has_base || (cannot_be_base && ch != '#')) {
1515
1602
          url->flags |= URL_FLAGS_FAILED;
1516
1602
          return;
1517

3469
        } else if (cannot_be_base && ch == '#') {
1518
28
          url->scheme = base->scheme;
1519
28
          if (IsSpecial(url->scheme)) {
1520
            url->flags |= URL_FLAGS_SPECIAL;
1521
            special = true;
1522
          } else {
1523
28
            url->flags &= ~URL_FLAGS_SPECIAL;
1524
28
            special = false;
1525
          }
1526

28
          special_back_slash = (special && ch == '\\');
1527
28
          if (base->flags & URL_FLAGS_HAS_PATH) {
1528
28
            url->flags |= URL_FLAGS_HAS_PATH;
1529
28
            url->path = base->path;
1530
          }
1531
28
          if (base->flags & URL_FLAGS_HAS_QUERY) {
1532
4
            url->flags |= URL_FLAGS_HAS_QUERY;
1533
4
            url->query = base->query;
1534
          }
1535
28
          if (base->flags & URL_FLAGS_HAS_FRAGMENT) {
1536
            url->flags |= URL_FLAGS_HAS_FRAGMENT;
1537
            url->fragment = base->fragment;
1538
          }
1539
28
          url->flags |= URL_FLAGS_CANNOT_BE_BASE;
1540
28
          state = kFragment;
1541

6882
        } else if (has_base &&
1542
3441
                   base->scheme != "file:") {
1543
319
          state = kRelative;
1544
319
          continue;
1545
        } else {
1546
3122
          url->scheme = "file:";
1547
3122
          url->flags |= URL_FLAGS_SPECIAL;
1548
3122
          special = true;
1549
3122
          state = kFile;
1550

3122
          special_back_slash = (special && ch == '\\');
1551
3122
          continue;
1552
        }
1553
28
        break;
1554
      case kSpecialRelativeOrAuthority:
1555

317
        if (ch == '/' && p + 1 < end && p[1] == '/') {
1556
285
          state = kSpecialAuthorityIgnoreSlashes;
1557
285
          p++;
1558
        } else {
1559
32
          state = kRelative;
1560
32
          continue;
1561
        }
1562
285
        break;
1563
      case kPathOrAuthority:
1564
682
        if (ch == '/') {
1565
522
          state = kAuthority;
1566
        } else {
1567
160
          state = kPath;
1568
160
          continue;
1569
        }
1570
522
        break;
1571
      case kRelative:
1572
351
        url->scheme = base->scheme;
1573
351
        if (IsSpecial(url->scheme)) {
1574
251
          url->flags |= URL_FLAGS_SPECIAL;
1575
251
          special = true;
1576
        } else {
1577
100
          url->flags &= ~URL_FLAGS_SPECIAL;
1578
100
          special = false;
1579
        }
1580

351
        special_back_slash = (special && ch == '\\');
1581

351
        switch (ch) {
1582
          case kEOL:
1583
18
            if (base->flags & URL_FLAGS_HAS_USERNAME) {
1584
4
              url->flags |= URL_FLAGS_HAS_USERNAME;
1585
4
              url->username = base->username;
1586
            }
1587
18
            if (base->flags & URL_FLAGS_HAS_PASSWORD) {
1588
4
              url->flags |= URL_FLAGS_HAS_PASSWORD;
1589
4
              url->password = base->password;
1590
            }
1591
18
            if (base->flags & URL_FLAGS_HAS_HOST) {
1592
16
              url->flags |= URL_FLAGS_HAS_HOST;
1593
16
              url->host = base->host;
1594
            }
1595
18
            if (base->flags & URL_FLAGS_HAS_QUERY) {
1596
              url->flags |= URL_FLAGS_HAS_QUERY;
1597
              url->query = base->query;
1598
            }
1599
18
            if (base->flags & URL_FLAGS_HAS_PATH) {
1600
18
              url->flags |= URL_FLAGS_HAS_PATH;
1601
18
              url->path = base->path;
1602
            }
1603
18
            url->port = base->port;
1604
18
            break;
1605
          case '/':
1606
76
            state = kRelativeSlash;
1607
76
            break;
1608
          case '?':
1609
38
            if (base->flags & URL_FLAGS_HAS_USERNAME) {
1610
              url->flags |= URL_FLAGS_HAS_USERNAME;
1611
              url->username = base->username;
1612
            }
1613
38
            if (base->flags & URL_FLAGS_HAS_PASSWORD) {
1614
              url->flags |= URL_FLAGS_HAS_PASSWORD;
1615
              url->password = base->password;
1616
            }
1617
38
            if (base->flags & URL_FLAGS_HAS_HOST) {
1618
34
              url->flags |= URL_FLAGS_HAS_HOST;
1619
34
              url->host = base->host;
1620
            }
1621
38
            if (base->flags & URL_FLAGS_HAS_PATH) {
1622
38
              url->flags |= URL_FLAGS_HAS_PATH;
1623
38
              url->path = base->path;
1624
            }
1625
38
            url->port = base->port;
1626
38
            state = kQuery;
1627
38
            break;
1628
          case '#':
1629
38
            if (base->flags & URL_FLAGS_HAS_USERNAME) {
1630
              url->flags |= URL_FLAGS_HAS_USERNAME;
1631
              url->username = base->username;
1632
            }
1633
38
            if (base->flags & URL_FLAGS_HAS_PASSWORD) {
1634
              url->flags |= URL_FLAGS_HAS_PASSWORD;
1635
              url->password = base->password;
1636
            }
1637
38
            if (base->flags & URL_FLAGS_HAS_HOST) {
1638
34
              url->flags |= URL_FLAGS_HAS_HOST;
1639
34
              url->host = base->host;
1640
            }
1641
38
            if (base->flags & URL_FLAGS_HAS_QUERY) {
1642
              url->flags |= URL_FLAGS_HAS_QUERY;
1643
              url->query = base->query;
1644
            }
1645
38
            if (base->flags & URL_FLAGS_HAS_PATH) {
1646
38
              url->flags |= URL_FLAGS_HAS_PATH;
1647
38
              url->path = base->path;
1648
            }
1649
38
            url->port = base->port;
1650
38
            state = kFragment;
1651
38
            break;
1652
          default:
1653
181
            if (special_back_slash) {
1654
10
              state = kRelativeSlash;
1655
            } else {
1656
171
              if (base->flags & URL_FLAGS_HAS_USERNAME) {
1657
1
                url->flags |= URL_FLAGS_HAS_USERNAME;
1658
1
                url->username = base->username;
1659
              }
1660
171
              if (base->flags & URL_FLAGS_HAS_PASSWORD) {
1661
1
                url->flags |= URL_FLAGS_HAS_PASSWORD;
1662
1
                url->password = base->password;
1663
              }
1664
171
              if (base->flags & URL_FLAGS_HAS_HOST) {
1665
151
                url->flags |= URL_FLAGS_HAS_HOST;
1666
151
                url->host = base->host;
1667
              }
1668
171
              if (base->flags & URL_FLAGS_HAS_PATH) {
1669
171
                url->flags |= URL_FLAGS_HAS_PATH;
1670
171
                url->path = base->path;
1671
171
                ShortenUrlPath(url);
1672
              }
1673
171
              url->port = base->port;
1674
171
              state = kPath;
1675
171
              continue;
1676
            }
1677
        }
1678
180
        break;
1679
      case kRelativeSlash:
1680


86
        if (IsSpecial(url->scheme) && (ch == '/' || ch == '\\')) {
1681
18
          state = kSpecialAuthorityIgnoreSlashes;
1682
68
        } else if (ch == '/') {
1683
6
          state = kAuthority;
1684
        } else {
1685
62
          if (base->flags & URL_FLAGS_HAS_USERNAME) {
1686
8
            url->flags |= URL_FLAGS_HAS_USERNAME;
1687
8
            url->username = base->username;
1688
          }
1689
62
          if (base->flags & URL_FLAGS_HAS_PASSWORD) {
1690
4
            url->flags |= URL_FLAGS_HAS_PASSWORD;
1691
4
            url->password = base->password;
1692
          }
1693
62
          if (base->flags & URL_FLAGS_HAS_HOST) {
1694
54
            url->flags |= URL_FLAGS_HAS_HOST;
1695
54
            url->host = base->host;
1696
          }
1697
62
          url->port = base->port;
1698
62
          state = kPath;
1699
62
          continue;
1700
        }
1701
24
        break;
1702
      case kSpecialAuthoritySlashes:
1703
3491
        state = kSpecialAuthorityIgnoreSlashes;
1704

3491
        if (ch == '/' && p + 1 < end && p[1] == '/') {
1705
3342
          p++;
1706
        } else {
1707
149
          continue;
1708
        }
1709
3342
        break;
1710
      case kSpecialAuthorityIgnoreSlashes:
1711

3869
        if (ch != '/' && ch != '\\') {
1712
3792
          state = kAuthority;
1713
3792
          continue;
1714
        }
1715
77
        break;
1716
      case kAuthority:
1717
96632
        if (ch == '@') {
1718
555
          if (atflag) {
1719
40
            buffer.reserve(buffer.size() + 3);
1720
40
            buffer.insert(0, "%40");
1721
          }
1722
555
          atflag = true;
1723
555
          size_t blen = buffer.size();
1724

554
          if (blen > 0 && buffer[0] != ':') {
1725
461
            url->flags |= URL_FLAGS_HAS_USERNAME;
1726
          }
1727
6522
          for (size_t n = 0; n < blen; n++) {
1728
5965
            const char bch = buffer[n];
1729
5974
            if (bch == ':') {
1730
433
              url->flags |= URL_FLAGS_HAS_PASSWORD;
1731
433
              if (!password_token_seen_flag) {
1732
421
                password_token_seen_flag = true;
1733
421
                continue;
1734
              }
1735
            }
1736
5553
            if (password_token_seen_flag) {
1737
2682
              AppendOrEscape(&url->password, bch, USERINFO_ENCODE_SET);
1738
            } else {
1739
2871
              AppendOrEscape(&url->username, bch, USERINFO_ENCODE_SET);
1740
            }
1741
          }
1742
557
          buffer.clear();
1743

96077
        } else if (ch == kEOL ||
1744
91825
                   ch == '/' ||
1745
91793
                   ch == '?' ||
1746
91775
                   ch == '#' ||
1747
                   special_back_slash) {
1748

4318
          if (atflag && buffer.size() == 0) {
1749
52
            url->flags |= URL_FLAGS_FAILED;
1750
52
            return;
1751
          }
1752
4266
          p -= buffer.size() + 1;
1753
4266
          buffer.clear();
1754
4266
          state = kHost;
1755
        } else {
1756
91759
          buffer += ch;
1757
        }
1758
96560
        break;
1759
      case kHost:
1760
      case kHostname:
1761

89049
        if (has_state_override && url->scheme == "file:") {
1762
12
          state = kFileHost;
1763
12
          continue;
1764

89037
        } else if (ch == ':' && !square_bracket_flag) {
1765
1010
          if (buffer.size() == 0) {
1766
24
            url->flags |= URL_FLAGS_FAILED;
1767
24
            return;
1768
          }
1769
986
          if (state_override == kHostname) {
1770
4
            return;
1771
          }
1772
982
          url->flags |= URL_FLAGS_HAS_HOST;
1773
982
          if (!ParseHost(buffer, &url->host, special)) {
1774
5
            url->flags |= URL_FLAGS_FAILED;
1775
5
            return;
1776
          }
1777
977
          buffer.clear();
1778
977
          state = kPort;
1779

88027
        } else if (ch == kEOL ||
1780
84566
                   ch == '/' ||
1781
84526
                   ch == '?' ||
1782
84500
                   ch == '#' ||
1783
                   special_back_slash) {
1784
3547
          p--;
1785

3547
          if (special && buffer.size() == 0) {
1786
17
            url->flags |= URL_FLAGS_FAILED;
1787
17
            return;
1788
          }
1789

3775
          if (has_state_override &&
1790

3576
              buffer.size() == 0 &&
1791

106
              ((url->username.size() > 0 || url->password.size() > 0) ||
1792
34
               url->port != -1)) {
1793
8
            url->flags |= URL_FLAGS_TERMINATED;
1794
8
            return;
1795
          }
1796
3522
          url->flags |= URL_FLAGS_HAS_HOST;
1797
3522
          if (!ParseHost(buffer, &url->host, special)) {
1798
324
            url->flags |= URL_FLAGS_FAILED;
1799
324
            return;
1800
          }
1801
3198
          buffer.clear();
1802
3198
          state = kPathStart;
1803
6231
          if (has_state_override) {
1804
165
            return;
1805
          }
1806
        } else {
1807
84480
          if (ch == '[')
1808
139
            square_bracket_flag = true;
1809
84480
          if (ch == ']')
1810
135
            square_bracket_flag = false;
1811
84480
          buffer += ch;
1812
        }
1813
88478
        break;
1814
      case kPort:
1815
5469
        if (IsASCIIDigit(ch)) {
1816
4430
          buffer += ch;
1817

1039
        } else if (has_state_override ||
1818
544
                   ch == kEOL ||
1819
36
                   ch == '/' ||
1820
36
                   ch == '?' ||
1821
36
                   ch == '#' ||
1822
                   special_back_slash) {
1823
1003
          if (buffer.size() > 0) {
1824
985
            unsigned port = 0;
1825
            // the condition port <= 0xffff prevents integer overflow
1826

5202
            for (size_t i = 0; port <= 0xffff && i < buffer.size(); i++)
1827
4217
              port = port * 10 + buffer[i] - '0';
1828
990
            if (port > 0xffff) {
1829
              // TODO(TimothyGu): This hack is currently needed for the host
1830
              // setter since it needs access to hostname if it is valid, and
1831
              // if the FAILED flag is set the entire response to JS layer
1832
              // will be empty.
1833
26
              if (state_override == kHost)
1834
2
                url->port = -1;
1835
              else
1836
24
                url->flags |= URL_FLAGS_FAILED;
1837
26
              return;
1838
            }
1839
            // the port is valid
1840
964
            url->port = NormalizePort(url->scheme, static_cast<int>(port));
1841
964
            if (url->port == -1)
1842
47
              url->flags |= URL_FLAGS_IS_DEFAULT_SCHEME_PORT;
1843
964
            buffer.clear();
1844
14
          } else if (has_state_override) {
1845
            // TODO(TimothyGu): Similar case as above.
1846
6
            if (state_override == kHost)
1847
2
              url->port = -1;
1848
            else
1849
4
              url->flags |= URL_FLAGS_TERMINATED;
1850
6
            return;
1851
          }
1852
972
          state = kPathStart;
1853
972
          continue;
1854
        } else {
1855
36
          url->flags |= URL_FLAGS_FAILED;
1856
36
          return;
1857
        }
1858
4430
        break;
1859
      case kFile:
1860
109693
        url->scheme = "file:";
1861
109693
        url->host.clear();
1862
109693
        url->flags |= URL_FLAGS_HAS_HOST;
1863

109693
        if (ch == '/' || ch == '\\') {
1864
106691
          state = kFileSlash;
1865

3002
        } else if (has_base && base->scheme == "file:") {
1866

2986
          switch (ch) {
1867
            case kEOL:
1868
4
              if (base->flags & URL_FLAGS_HAS_HOST) {
1869
4
                url->host = base->host;
1870
              }
1871
4
              if (base->flags & URL_FLAGS_HAS_PATH) {
1872
4
                url->flags |= URL_FLAGS_HAS_PATH;
1873
4
                url->path = base->path;
1874
              }
1875
4
              if (base->flags & URL_FLAGS_HAS_QUERY) {
1876
4
                url->flags |= URL_FLAGS_HAS_QUERY;
1877
4
                url->query = base->query;
1878
              }
1879
4
              break;
1880
            case '?':
1881
4
              if (base->flags & URL_FLAGS_HAS_HOST) {
1882
4
                url->host = base->host;
1883
              }
1884
4
              if (base->flags & URL_FLAGS_HAS_PATH) {
1885
4
                url->flags |= URL_FLAGS_HAS_PATH;
1886
4
                url->path = base->path;
1887
              }
1888
4
              url->flags |= URL_FLAGS_HAS_QUERY;
1889
4
              url->query.clear();
1890
4
              state = kQuery;
1891
4
              break;
1892
            case '#':
1893
4
              if (base->flags & URL_FLAGS_HAS_HOST) {
1894
4
                url->host = base->host;
1895
              }
1896
4
              if (base->flags & URL_FLAGS_HAS_PATH) {
1897
4
                url->flags |= URL_FLAGS_HAS_PATH;
1898
4
                url->path = base->path;
1899
              }
1900
4
              if (base->flags & URL_FLAGS_HAS_QUERY) {
1901
4
                url->flags |= URL_FLAGS_HAS_QUERY;
1902
4
                url->query = base->query;
1903
              }
1904
4
              url->flags |= URL_FLAGS_HAS_FRAGMENT;
1905
4
              url->fragment.clear();
1906
4
              state = kFragment;
1907
4
              break;
1908
            default:
1909
2974
              url->query.clear();
1910
2974
              if (base->flags & URL_FLAGS_HAS_HOST) {
1911
2974
                url->host = base->host;
1912
              }
1913
2974
              if (base->flags & URL_FLAGS_HAS_PATH) {
1914
2974
                url->flags |= URL_FLAGS_HAS_PATH;
1915
2974
                url->path = base->path;
1916
              }
1917
2974
              if (!StartsWithWindowsDriveLetter(p, end)) {
1918
2950
                ShortenUrlPath(url);
1919
              } else {
1920
24
                url->path.clear();
1921
              }
1922
2974
              state = kPath;
1923
2974
              continue;
1924
          }
1925
        } else {
1926
16
          state = kPath;
1927
16
          continue;
1928
        }
1929
106703
        break;
1930
      case kFileSlash:
1931

106691
        if (ch == '/' || ch == '\\') {
1932
106565
          state = kFileHost;
1933
        } else {
1934

126
          if (has_base && base->scheme == "file:") {
1935
118
            url->flags |= URL_FLAGS_HAS_HOST;
1936
118
            url->host = base->host;
1937

222
            if (!StartsWithWindowsDriveLetter(p, end) &&
1938
104
                IsNormalizedWindowsDriveLetter(base->path[0])) {
1939
4
              url->flags |= URL_FLAGS_HAS_PATH;
1940
4
              url->path.push_back(base->path[0]);
1941
            }
1942
          }
1943
126
          state = kPath;
1944
126
          continue;
1945
        }
1946
106565
        break;
1947
      case kFileHost:
1948

107663
        if (ch == kEOL ||
1949
1096
            ch == '/' ||
1950
1086
            ch == '\\' ||
1951
1086
            ch == '?' ||
1952
            ch == '#') {
1953

319719
          if (!has_state_override &&
1954

106599
              buffer.size() == 2 &&
1955
22
              IsWindowsDriveLetter(buffer)) {
1956
12
            state = kPath;
1957
106565
          } else if (buffer.size() == 0) {
1958
106374
            url->flags |= URL_FLAGS_HAS_HOST;
1959
106374
            url->host.clear();
1960
106374
            if (has_state_override)
1961
4
              return;
1962
106370
            state = kPathStart;
1963
          } else {
1964
326
            std::string host;
1965
191
            if (!ParseHost(buffer, &host, special)) {
1966
52
              url->flags |= URL_FLAGS_FAILED;
1967
52
              return;
1968
            }
1969
139
            if (host == "localhost")
1970
35
              host.clear();
1971
139
            url->flags |= URL_FLAGS_HAS_HOST;
1972
139
            url->host = host;
1973
139
            if (has_state_override)
1974
4
              return;
1975
135
            buffer.clear();
1976
135
            state = kPathStart;
1977
          }
1978
106517
          continue;
1979
        } else {
1980
1086
          buffer += ch;
1981
        }
1982
1086
        break;
1983
      case kPathStart:
1984
180657
        if (IsSpecial(url->scheme)) {
1985
180137
          state = kPath;
1986

180137
          if (ch != '/' && ch != '\\') {
1987
70882
            continue;
1988
          }
1989

522
        } else if (!has_state_override && ch == '?') {
1990
6
          url->flags |= URL_FLAGS_HAS_QUERY;
1991
6
          url->query.clear();
1992
6
          state = kQuery;
1993

516
        } else if (!has_state_override && ch == '#') {
1994
6
          url->flags |= URL_FLAGS_HAS_FRAGMENT;
1995
6
          url->fragment.clear();
1996
6
          state = kFragment;
1997
510
        } else if (ch != kEOL) {
1998
439
          state = kPath;
1999
439
          if (ch != '/') {
2000
33
            continue;
2001
          }
2002
        }
2003
109744
        break;
2004
      case kPath:
2005

12828997
        if (ch == kEOL ||
2006
11541786
            ch == '/' ||
2007
11541717
            special_back_slash ||
2008

15495151
            (!has_state_override && (ch == '?' || ch == '#'))) {
2009
1287800
          if (IsDoubleDotSegment(buffer)) {
2010
2072
            ShortenUrlPath(url);
2011

2072
            if (ch != '/' && !special_back_slash) {
2012
191
              url->flags |= URL_FLAGS_HAS_PATH;
2013
191
              url->path.emplace_back("");
2014
            }
2015

2572917
          } else if (IsSingleDotSegment(buffer) &&
2016

1286170
                     ch != '/' && !special_back_slash) {
2017
274
            url->flags |= URL_FLAGS_HAS_PATH;
2018
274
            url->path.emplace_back("");
2019
1285620
          } else if (!IsSingleDotSegment(buffer)) {
2020

3848586
            if (url->scheme == "file:" &&
2021
1423409
                url->path.empty() &&
2022

1429169
                buffer.size() == 2 &&
2023
101
                IsWindowsDriveLetter(buffer)) {
2024
99
              buffer[1] = ':';
2025
            }
2026
1284743
            url->flags |= URL_FLAGS_HAS_PATH;
2027
1284743
            url->path.emplace_back(std::move(buffer));
2028
          }
2029
1287953
          buffer.clear();
2030
2575908
          if (ch == '?') {
2031
482
            url->flags |= URL_FLAGS_HAS_QUERY;
2032
482
            url->query.clear();
2033
482
            state = kQuery;
2034
1287472
          } else if (ch == '#') {
2035
41
            url->flags |= URL_FLAGS_HAS_FRAGMENT;
2036
41
            url->fragment.clear();
2037
41
            state = kFragment;
2038
          }
2039
        } else {
2040
11541197
          AppendOrEscape(&buffer, ch, PATH_ENCODE_SET);
2041
        }
2042
12829033
        break;
2043
      case kCannotBeBase:
2044
39053
        switch (ch) {
2045
          case '?':
2046
4
            state = kQuery;
2047
4
            break;
2048
          case '#':
2049
10
            state = kFragment;
2050
10
            break;
2051
          default:
2052
39039
            if (url->path.empty())
2053
              url->path.emplace_back("");
2054
39038
            else if (ch != kEOL)
2055
34010
              AppendOrEscape(&url->path[0], ch, C0_CONTROL_ENCODE_SET);
2056
        }
2057
39053
        break;
2058
      case kQuery:
2059

5938
        if (ch == kEOL || (!has_state_override && ch == '#')) {
2060
687
          url->flags |= URL_FLAGS_HAS_QUERY;
2061
687
          url->query = std::move(buffer);
2062
687
          buffer.clear();
2063
1374
          if (ch == '#')
2064
375
            state = kFragment;
2065
        } else {
2066
5251
          AppendOrEscape(&buffer, ch, special ? QUERY_ENCODE_SET_SPECIAL :
2067
5251
                                                QUERY_ENCODE_SET_NONSPECIAL);
2068
        }
2069
5938
        break;
2070
      case kFragment:
2071
4686
        switch (ch) {
2072
          case kEOL:
2073
688
            url->flags |= URL_FLAGS_HAS_FRAGMENT;
2074
688
            url->fragment = std::move(buffer);
2075
688
            break;
2076
          default:
2077
3998
            AppendOrEscape(&buffer, ch, FRAGMENT_ENCODE_SET);
2078
        }
2079
4685
        break;
2080
      default:
2081
        url->flags |= URL_FLAGS_INVALID_PARSE_STATE;
2082
        return;
2083
    }
2084
2085
13986529
    p++;
2086
  }
2087
}  // NOLINT(readability/fn_size)
2088
2089
// https://url.spec.whatwg.org/#url-serializing
2090
32729
std::string URL::SerializeURL(const struct url_data* url,
2091
                              bool exclude = false) {
2092
32729
  std::string output = url->scheme;
2093
32729
  if (url->flags & URL_FLAGS_HAS_HOST) {
2094
32729
    output += "//";
2095

65458
    if (url->flags & URL_FLAGS_HAS_USERNAME ||
2096
32729
        url->flags & URL_FLAGS_HAS_PASSWORD) {
2097
      if (url->flags & URL_FLAGS_HAS_USERNAME) {
2098
        output += url->username;
2099
      }
2100
      if (url->flags & URL_FLAGS_HAS_PASSWORD) {
2101
        output += ":" + url->password;
2102
      }
2103
      output += "@";
2104
    }
2105
32729
    output += url->host;
2106
32729
    if (url->port != -1) {
2107
      output += ":" + std::to_string(url->port);
2108
    }
2109
  }
2110
32729
  if (url->flags & URL_FLAGS_CANNOT_BE_BASE) {
2111
    output += url->path[0];
2112
  } else {
2113

65458
    if (!(url->flags & URL_FLAGS_HAS_HOST) &&
2114

32729
          url->path.size() > 1 &&
2115
          url->path[0].empty()) {
2116
      output += "/.";
2117
    }
2118
410176
    for (size_t i = 1; i < url->path.size(); i++) {
2119
377447
      output += "/" + url->path[i];
2120
    }
2121
  }
2122
32729
  if (url->flags & URL_FLAGS_HAS_QUERY) {
2123
    output = "?" + url->query;
2124
  }
2125

32729
  if (!exclude && url->flags & URL_FLAGS_HAS_FRAGMENT) {
2126
    output = "#" + url->fragment;
2127
  }
2128
32729
  return output;
2129
}
2130
2131
namespace {
2132
124418
void SetArgs(Environment* env,
2133
             Local<Value> argv[ARG_COUNT],
2134
             const struct url_data& url) {
2135
124418
  Isolate* isolate = env->isolate();
2136
248831
  argv[ARG_FLAGS] = Integer::NewFromUnsigned(isolate, url.flags);
2137
124416
  argv[ARG_PROTOCOL] =
2138
124418
      url.flags & URL_FLAGS_SPECIAL ?
2139
118460
          GetSpecial(env, url.scheme) :
2140
491712
          OneByteString(isolate, url.scheme.c_str());
2141
124416
  if (url.flags & URL_FLAGS_HAS_USERNAME)
2142
1210
    argv[ARG_USERNAME] = Utf8String(isolate, url.username);
2143
124416
  if (url.flags & URL_FLAGS_HAS_PASSWORD)
2144
1170
    argv[ARG_PASSWORD] = Utf8String(isolate, url.password);
2145
124416
  if (url.flags & URL_FLAGS_HAS_HOST)
2146
238258
    argv[ARG_HOST] = Utf8String(isolate, url.host);
2147
124418
  if (url.flags & URL_FLAGS_HAS_QUERY)
2148
1390
    argv[ARG_QUERY] = Utf8String(isolate, url.query);
2149
124418
  if (url.flags & URL_FLAGS_HAS_FRAGMENT)
2150
1368
    argv[ARG_FRAGMENT] = Utf8String(isolate, url.fragment);
2151
124418
  if (url.port > -1)
2152
2172
    argv[ARG_PORT] = Integer::New(isolate, url.port);
2153
124418
  if (url.flags & URL_FLAGS_HAS_PATH)
2154
247587
    argv[ARG_PATH] = ToV8Value(env->context(), url.path).ToLocalChecked();
2155
124417
}
2156
2157
126614
void Parse(Environment* env,
2158
           Local<Value> recv,
2159
           const char* input,
2160
           size_t len,
2161
           enum url_parse_state state_override,
2162
           Local<Value> base_obj,
2163
           Local<Value> context_obj,
2164
           Local<Function> cb,
2165
           Local<Value> error_cb) {
2166
126614
  Isolate* isolate = env->isolate();
2167
126611
  Local<Context> context = env->context();
2168
253169
  HandleScope handle_scope(isolate);
2169
126564
  Context::Scope context_scope(context);
2170
2171
126604
  const bool has_context = context_obj->IsObject();
2172
126605
  const bool has_base = base_obj->IsObject();
2173
2174
253169
  url_data base;
2175
253172
  url_data url;
2176
126608
  if (has_context)
2177
38201
    url = HarvestContext(env, context_obj.As<Object>());
2178
126608
  if (has_base)
2179
5055
    base = HarvestBase(env, base_obj.As<Object>());
2180
2181
126603
  URL::Parse(input, len, state_override, &url, has_context, &base, has_base);
2182

126610
  if ((url.flags & URL_FLAGS_INVALID_PARSE_STATE) ||
2183
38201
      ((state_override != kUnknownState) &&
2184
38201
       (url.flags & URL_FLAGS_TERMINATED)))
2185
44
    return;
2186
2187
  // Define the return value placeholders
2188
  const Local<Value> undef = Undefined(isolate);
2189
  const Local<Value> null = Null(isolate);
2190
126566
  if (!(url.flags & URL_FLAGS_FAILED)) {
2191
    Local<Value> argv[] = {
2192
      undef,
2193
      undef,
2194
      undef,
2195
      undef,
2196
      null,  // host defaults to null
2197
      null,  // port defaults to null
2198
      undef,
2199
      null,  // query defaults to null
2200
      null,  // fragment defaults to null
2201
124416
    };
2202
124416
    SetArgs(env, argv, url);
2203
373269
    cb->Call(context, recv, arraysize(argv), argv).FromMaybe(Local<Value>());
2204
2150
  } else if (error_cb->IsFunction()) {
2205
2048
    Local<Value> argv[2] = { undef, undef };
2206
4096
    argv[ERR_ARG_FLAGS] = Integer::NewFromUnsigned(isolate, url.flags);
2207
2048
    argv[ERR_ARG_INPUT] =
2208
4096
      String::NewFromUtf8(env->isolate(), input).ToLocalChecked();
2209
8192
    error_cb.As<Function>()->Call(context, recv, arraysize(argv), argv)
2210
2048
        .FromMaybe(Local<Value>());
2211
  }
2212
}
2213
2214
126619
void Parse(const FunctionCallbackInfo<Value>& args) {
2215
126619
  Environment* env = Environment::GetCurrent(args);
2216
126617
  CHECK_GE(args.Length(), 5);
2217
379851
  CHECK(args[0]->IsString());  // input
2218


519729
  CHECK(args[2]->IsUndefined() ||  // base context
2219
        args[2]->IsNull() ||
2220
        args[2]->IsObject());
2221


570856
  CHECK(args[3]->IsUndefined() ||  // context
2222
        args[3]->IsNull() ||
2223
        args[3]->IsObject());
2224
253234
  CHECK(args[4]->IsFunction());  // complete callback
2225

556695
  CHECK(args[5]->IsUndefined() || args[5]->IsFunction());  // error callback
2226
2227
253225
  Utf8Value input(env->isolate(), args[0]);
2228
126606
  enum url_parse_state state_override = kUnknownState;
2229
253212
  if (args[1]->IsNumber()) {
2230
126604
    state_override = static_cast<enum url_parse_state>(
2231
633021
        args[1]->Uint32Value(env->context()).FromJust());
2232
  }
2233
2234
253225
  Parse(env, args.This(),
2235
126615
        *input, input.length(),
2236
        state_override,
2237
        args[2],
2238
        args[3],
2239
253225
        args[4].As<Function>(),
2240
126613
        args[5]);
2241
126597
}
2242
2243
92
void EncodeAuthSet(const FunctionCallbackInfo<Value>& args) {
2244
92
  Environment* env = Environment::GetCurrent(args);
2245
92
  CHECK_GE(args.Length(), 1);
2246
276
  CHECK(args[0]->IsString());
2247
184
  Utf8Value value(env->isolate(), args[0]);
2248
184
  std::string output;
2249
92
  size_t len = value.length();
2250
92
  output.reserve(len);
2251
756
  for (size_t n = 0; n < len; n++) {
2252
664
    const char ch = (*value)[n];
2253
664
    AppendOrEscape(&output, ch, USERINFO_ENCODE_SET);
2254
  }
2255
184
  args.GetReturnValue().Set(
2256
184
      String::NewFromUtf8(env->isolate(), output.c_str()).ToLocalChecked());
2257
92
}
2258
2259
16
void ToUSVString(const FunctionCallbackInfo<Value>& args) {
2260
16
  Environment* env = Environment::GetCurrent(args);
2261
16
  CHECK_GE(args.Length(), 2);
2262
48
  CHECK(args[0]->IsString());
2263
32
  CHECK(args[1]->IsNumber());
2264
2265
32
  TwoByteValue value(env->isolate(), args[0]);
2266
2267
64
  int64_t start = args[1]->IntegerValue(env->context()).FromJust();
2268
16
  CHECK_GE(start, 0);
2269
2270
47
  for (size_t i = start; i < value.length(); i++) {
2271
31
    char16_t c = value[i];
2272
31
    if (!IsUnicodeSurrogate(c)) {
2273
13
      continue;
2274

18
    } else if (IsUnicodeSurrogateTrail(c) || i == value.length() - 1) {
2275
15
      value[i] = kUnicodeReplacementCharacter;
2276
    } else {
2277
3
      char16_t d = value[i + 1];
2278
3
      if (IsUnicodeTrail(d)) {
2279
        i++;
2280
      } else {
2281
3
        value[i] = kUnicodeReplacementCharacter;
2282
      }
2283
    }
2284
  }
2285
2286
32
  args.GetReturnValue().Set(
2287
32
      String::NewFromTwoByte(env->isolate(),
2288
16
                             *value,
2289
                             NewStringType::kNormal,
2290
32
                             value.length()).ToLocalChecked());
2291
16
}
2292
2293
229
void DomainToASCII(const FunctionCallbackInfo<Value>& args) {
2294
229
  Environment* env = Environment::GetCurrent(args);
2295
229
  CHECK_GE(args.Length(), 1);
2296
687
  CHECK(args[0]->IsString());
2297
446
  Utf8Value value(env->isolate(), args[0]);
2298
2299
446
  URLHost host;
2300
  // Assuming the host is used for a special scheme.
2301
229
  host.ParseHost(*value, value.length(), true);
2302
229
  if (host.ParsingFailed()) {
2303
36
    args.GetReturnValue().Set(FIXED_ONE_BYTE_STRING(env->isolate(), ""));
2304
12
    return;
2305
  }
2306
434
  std::string out = host.ToStringMove();
2307
434
  args.GetReturnValue().Set(
2308
434
      String::NewFromUtf8(env->isolate(), out.c_str()).ToLocalChecked());
2309
}
2310
2311
207
void DomainToUnicode(const FunctionCallbackInfo<Value>& args) {
2312
207
  Environment* env = Environment::GetCurrent(args);
2313
207
  CHECK_GE(args.Length(), 1);
2314
621
  CHECK(args[0]->IsString());
2315
402
  Utf8Value value(env->isolate(), args[0]);
2316
2317
402
  URLHost host;
2318
  // Assuming the host is used for a special scheme.
2319
207
  host.ParseHost(*value, value.length(), true, true);
2320
207
  if (host.ParsingFailed()) {
2321
36
    args.GetReturnValue().Set(FIXED_ONE_BYTE_STRING(env->isolate(), ""));
2322
12
    return;
2323
  }
2324
390
  std::string out = host.ToStringMove();
2325
390
  args.GetReturnValue().Set(
2326
390
      String::NewFromUtf8(env->isolate(), out.c_str()).ToLocalChecked());
2327
}
2328
2329
470
void SetURLConstructor(const FunctionCallbackInfo<Value>& args) {
2330
470
  Environment* env = Environment::GetCurrent(args);
2331
470
  CHECK_EQ(args.Length(), 1);
2332
940
  CHECK(args[0]->IsFunction());
2333
940
  env->set_url_constructor_function(args[0].As<Function>());
2334
470
}
2335
2336
470
void Initialize(Local<Object> target,
2337
                Local<Value> unused,
2338
                Local<Context> context,
2339
                void* priv) {
2340
470
  Environment* env = Environment::GetCurrent(context);
2341
470
  env->SetMethod(target, "parse", Parse);
2342
470
  env->SetMethodNoSideEffect(target, "encodeAuth", EncodeAuthSet);
2343
470
  env->SetMethodNoSideEffect(target, "toUSVString", ToUSVString);
2344
470
  env->SetMethodNoSideEffect(target, "domainToASCII", DomainToASCII);
2345
470
  env->SetMethodNoSideEffect(target, "domainToUnicode", DomainToUnicode);
2346
470
  env->SetMethod(target, "setURLConstructor", SetURLConstructor);
2347
2348
#define XX(name, _) NODE_DEFINE_CONSTANT(target, name);
2349
14100
  FLAGS(XX)
2350
#undef XX
2351
2352
#define XX(name) NODE_DEFINE_CONSTANT(target, name);
2353
28200
  PARSESTATES(XX)
2354
1880
#undef XX
2355
1410
}
2356
1880
}  // namespace
2357
2820
2358
6188
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
2359
6188
  registry->Register(Parse);
2360
5718
  registry->Register(EncodeAuthSet);
2361
6658
  registry->Register(ToUSVString);
2362
6188
  registry->Register(DomainToASCII);
2363
6188
  registry->Register(DomainToUnicode);
2364
6188
  registry->Register(SetURLConstructor);
2365
6658
}
2366
2820
2367
2358
std::string URL::ToFilePath() const {
2368
1418
  if (context_.scheme != "file:") {
2369
941
    return "";
2370
1880
  }
2371
1880
2372
1410
#ifdef _WIN32
2373
1880
  const char* slash = "\\";
2374
2350
  auto is_slash = [] (char ch) {
2375
1880
    return ch == '/' || ch == '\\';
2376
1880
  };
2377
940
#else
2378
1417
  const char* slash = "/";
2379
1926
  auto is_slash = [] (char ch) {
2380
1880
    return ch == '/';
2381
986
  };
2382

954
  if ((context_.flags & URL_FLAGS_HAS_HOST) &&
2383
1417
      context_.host.length() > 0) {
2384
1411
    return "";
2385
  }
2386
#endif
2387
12
  std::string decoded_path;
2388
18
  for (const std::string& part : context_.path) {
2389
25
    std::string decoded = PercentDecode(part.c_str(), part.length());
2390
58
    for (char& ch : decoded) {
2391
46
      if (is_slash(ch)) {
2392
1
        return "";
2393
      }
2394
    }
2395
12
    decoded_path += slash + decoded;
2396
  }
2397
2398
#ifdef _WIN32
2399
  // TODO(TimothyGu): Use "\\?\" long paths on Windows.
2400
2401
  // If hostname is set, then we have a UNC path. Pass the hostname through
2402
  // ToUnicode just in case it is an IDN using punycode encoding. We do not
2403
  // need to worry about percent encoding because the URL parser will have
2404
  // already taken care of that for us. Note that this only causes IDNs with an
2405
  // appropriate `xn--` prefix to be decoded.
2406
  if ((context_.flags & URL_FLAGS_HAS_HOST) &&
2407
      context_.host.length() > 0) {
2408
    std::string unicode_host;
2409
    if (!ToUnicode(context_.host, &unicode_host)) {
2410
      return "";
2411
    }
2412
    return "\\\\" + unicode_host + decoded_path;
2413
  }
2414
  // Otherwise, it's a local path that requires a drive letter.
2415
  if (decoded_path.length() < 3) {
2416
    return "";
2417
  }
2418
  if (decoded_path[2] != ':' ||
2419
      !IsASCIIAlpha(decoded_path[1])) {
2420
    return "";
2421
  }
2422
  // Strip out the leading '\'.
2423
  return decoded_path.substr(1);
2424
#else
2425
5
  return decoded_path;
2426
#endif
2427
}
2428
2429
32729
URL URL::FromFilePath(const std::string& file_path) {
2430
32729
  URL url("file://");
2431
65458
  std::string escaped_file_path;
2432
4000213
  for (size_t i = 0; i < file_path.length(); ++i) {
2433
3967472
    escaped_file_path += file_path[i];
2434
3967480
    if (file_path[i] == '%')
2435
11
      escaped_file_path += "25";
2436
  }
2437
32729
  URL::Parse(escaped_file_path.c_str(), escaped_file_path.length(), kPathStart,
2438
32729
             &url.context_, true, nullptr, false);
2439
65458
  return url;
2440
}
2441
2442
// This function works by calling out to a JS function that creates and
2443
// returns the JS URL object. Be mindful of the JS<->Native boundary
2444
// crossing that is required.
2445
MaybeLocal<Value> URL::ToObject(Environment* env) const {
2446
  Isolate* isolate = env->isolate();
2447
  Local<Context> context = env->context();
2448
  Context::Scope context_scope(context);
2449
2450
  const Local<Value> undef = Undefined(isolate);
2451
  const Local<Value> null = Null(isolate);
2452
2453
  if (context_.flags & URL_FLAGS_FAILED)
2454
    return Local<Value>();
2455
2456
  Local<Value> argv[] = {
2457
    undef,
2458
    undef,
2459
    undef,
2460
    undef,
2461
    null,  // host defaults to null
2462
    null,  // port defaults to null
2463
    undef,
2464
    null,  // query defaults to null
2465
    null,  // fragment defaults to null
2466
  };
2467
  SetArgs(env, argv, context_);
2468
2469
  MaybeLocal<Value> ret;
2470
  {
2471
    TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
2472
2473
    // The SetURLConstructor method must have been called already to
2474
    // set the constructor function used below. SetURLConstructor is
2475
    // called automatically when the internal/url.js module is loaded
2476
    // during the internal/bootstrap/node.js processing.
2477
    ret = env->url_constructor_function()
2478
        ->Call(env->context(), undef, arraysize(argv), argv);
2479
  }
2480
2481
  return ret;
2482
}
2483
2484
}  // namespace url
2485
}  // namespace node
2486
2487
4836
NODE_MODULE_CONTEXT_AWARE_INTERNAL(url, node::url::Initialize)
2488

19310
NODE_MODULE_EXTERNAL_REFERENCE(url, node::url::RegisterExternalReferences)