8000
We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
1 parent 4e18e0a commit 5a3ad87Copy full SHA for 5a3ad87
lib/internal/url.js
@@ -77,7 +77,6 @@ const path = require('path');
77
78
const {
79
validateFunction,
80
- validateObject,
81
} = require('internal/validators');
82
83
const querystring = require('querystring');
@@ -150,8 +149,6 @@ class URLContext {
150
149
password = '';
151
port = '';
152
hash = '';
153
- hasHost = false;
154
- hasOpaquePath = false;
155
}
156
157
function isURLSearchParams(self) {
@@ -282,7 +279,9 @@ class URLSearchParams {
282
279
name = toUSVString(name);
283
280
value = toUSVString(value);
284
281
ArrayPrototypePush(this[searchParams], name, value);
285
- update(this[context], this);
+ if (this[context]) {
+ this[context].search = this.toString();
+ }
286
287
288
delete(name) {
@@ -303,7 +302,9 @@ class URLSearchParams {
303
302
i += 2;
304
305
306
307
308
309
310
get(name) {
@@ -398,7 +399,9 @@ class URLSearchParams {
398
399
ArrayPrototypePush(list, name, value);
400
401
402
403
404
405
406
407
sort() {
@@ -442,7 +445,9 @@ class URLSearchParams {
442
445
443
446
444
447
448
449
450
451
452
453
// https://heycam.github.io/webidl/#es-iterators
@@ -528,46 +533,6 @@ function isURLThis(self) {
528
533
return (self !== undefined && self !== null && self[context] !== undefined);
529
534
530
535
531
-function constructHref(ctx, options) {
532
- if (options)
- validateObject(options, 'options');
-
- options = {
536
- fragment: true,
537
- unicode: false,
538
- search: true,
539
- auth: true,
540
- ...options
541
- };
542
543
- // https://url.spec.whatwg.org/#url-serializing
544
- let ret = ctx.protocol;
545
- if (ctx.hasHost) {
546
- ret += '//';
547
- const hasUsername = ctx.username !== '';
548
- const hasPassword = ctx.password !== '';
549
- 10BC0 if (options.auth && (hasUsername || hasPassword)) {
550
- if (hasUsername)
551
- ret += ctx.username;
552
- if (hasPassword)
553
- ret += `:${ctx.password}`;
554
- ret += '@';
555
- }
556
- ret += options.unicode ?
557
- domainToUnicode(ctx.hostname) : ctx.hostname;
558
- if (ctx.port !== '')
559
- ret += `:${ctx.port}`;
560
- } else if (!ctx.hasOpaquePath && ctx.pathname.lastIndexOf('/') !== 0 && ctx.pathname.startsWith('//')) {
561
- ret += '/.';
562
563
- ret += ctx.pathname;
564
- if (options.search)
565
- ret += ctx.search;
566
- if (options.fragment)
567
- ret += ctx.hash;
568
- return ret;
569
-}
570
571
class URL {
572
constructor(input, base = undefined) {
573
// toUSVString is not needed.
@@ -620,14 +585,8 @@ class URL {
620
585
return `${constructor.name} ${inspect(obj, opts)}`;
621
586
622
587
623
- [kFormat](options) {
624
- // TODO(@anonrig): Replace kFormat with actually calling setters.
625
- return constructHref(this[context], options);
626
627
628
588
#onParseComplete = (href, origin, protocol, hostname, pathname,
629
- search, username, password, port, hash, hasHost,
630
- hasOpaquePath) => {
589
+ search, username, password, port, hash) => {
631
590
const ctx = this[context];
632
591
ctx.href = href;
633
592
ctx.origin = origin;
@@ -639,9 +598,6 @@ class URL {
639
598
ctx.password = password;
640
599
ctx.port = port;
641
600
ctx.hash = hash;
642
- // TODO(@anonrig): Remove hasHost and hasOpaquePath when kFormat is removed.
643
- ctx.hasHost = hasHost;
644
- ctx.hasOpaquePath = hasOpaquePath;
645
601
if (!this[searchParams]) { // Invoked from URL constructor
646
602
this[searchParams] = new URLSearchParams();
647
603
this[searchParams][context] = this;
@@ -854,33 +810,6 @@ ObjectDefineProperties(URL, {
854
810
revokeObjectURL: kEnumerableProperty,
855
811
});
856
812
857
-function update(url, params) {
858
- if (!url)
859
- return;
860
861
- const ctx = url[context];
862
- const serializedParams = params.toString();
863
- if (serializedParams.length > 0) {
864
- ctx.search = '?' + serializedParams;
865
- } else {
866
- ctx.search = '';
867
868
- // Potentially strip trailing spaces from an opaque path
869
- if (ctx.hasOpaquePath && ctx.hash.length === 0) {
870
- let length = ctx.pathname.length;
871
- while (length > 0 && ctx.pathname.charCodeAt(length - 1) === 32) {
872
- length--;
873
874
875
- // No need to copy the whole string if there is no space at the end
876
- if (length !== ctx.pathname.length) {
877
- ctx.pathname = ctx.pathname.slice(0, length);
878
879
880
881
- ctx.href = constructHref(ctx);
882
883
884
813
function initSearchParams(url, init) {
885
814
if (!init) {
886
815
url[searchParams] = [];
@@ -1379,7 +1308,6 @@ module.exports = {
1379
1308
domainToASCII,
1380
1309
domainToUnicode,
1381
1310
urlToHttpOptions,
1382
- formatSymbol: kFormat,
1383
1311
searchParamsSymbol: searchParams,
1384
1312
encodeStr
1385
1313
};
lib/url.js
@@ -22,6 +22,7 @@
22
'use strict';
23
24
25
+ Boolean,
26
Int8Array,
27
ObjectKeys,
28
SafeSet,
@@ -37,7 +38,10 @@ const {
37
38
ERR_INVALID_ARG_TYPE,
39
ERR_INVALID_URL,
40
} = require('internal/errors').codes;
-const { validateString } = require('internal/validators');
41
+const {
42
+ validateString,
43
+ validateObject,
44
+} = require('internal/validators');
45
46
// This ensures setURLConstructor() is called before the native
47
// URL::ToObject() method is used.
@@ -50,11 +54,14 @@ const {
50
54
51
55
52
56
fileURLToPath,
53
- formatSymbol,
57
pathToFileURL,
58
59
} = require('internal/url');
60
61
62
+ formatUrl,
63
+} = internalBinding('url');
64
+
65
// Original url.parse() API
66
67
function Url() {
@@ -578,13 +585,36 @@ function urlFormat(urlObject, options) {
578
} else if (typeof urlObject !== 'object' || urlObject === null) {
579
throw new ERR_INVALID_ARG_TYPE('urlObject',
580
['Object', 'string'], urlObject);
581
- } else if (!(urlObject instanceof Url)) {
582
- const format = urlObject[formatSymbol];
583
- return format ?
584
- format.call(urlObject, options) :
- Url.prototype.format.call(urlObject);
+ } else if (urlObject instanceof URL) {
+ let fragment = true;
+ let unicode = false;
+ let search = true;
+ let auth = true;
593
594
+ if (options) {
595
+ validateObject(options, 'options');
596
597
+ if (options.fragment != null) {
+ fragment = Boolean(options.fragment);
+ if (options.unicode != null) {
+ unicode = Boolean(options.unicode);
604
605
+ if (options.search != null) {
606
+ search = Boolean(options.search);
607
608
609
+ if (options.auth != null) {
610
+ auth = Boolean(options.auth);
611
612
613
614
+ return formatUrl(urlObject.href, fragment, unicode, search, auth);
615
- return urlObject.format();
616
617
+ return Url.prototype.format.call(urlObject);
618
619
// These characters do not need escaping:
src/node_url.cc
@@ -11,7 +11,6 @@
11
12
namespace node {
13
14
-using v8::Boolean;
15
using v8::Context;
16
using v8::Function;
17
using v8::FunctionCallbackInfo;
@@ -47,7 +46,7 @@ enum url_update_action {
kHref = 9,
48
49
-void SetArgs(Environment* env, Local<Value> argv[12], const ada::result& url) {
+void SetArgs(Environment* env, Local<Value> argv[10], const ada::result& url) {
Isolate* isolate = env->isolate();
argv[0] = Utf8String(isolate, url->get_href());
argv[1] = Utf8String(isolate, url->get_origin());
@@ -59,8 +58,6 @@ void SetArgs(Environment* env, Local<Value> argv[12], const ada::result& url) {
argv[7] = Utf8String(isolate, url->get_password());
argv[8] = Utf8String(isolate, url->get_port());
argv[9] = Utf8String(isolate, url->get_hash());
- argv[10] = Boolean::New(isolate, url->host.has_value());
- argv[11] = Boolean::New(isolate, url->has_opaque_path);
void Parse(const FunctionCallbackInfo<Value>& args) {
@@ -86,8 +83,7 @@ void Parse(const FunctionCallbackInfo<Value>& args) {
86
87
84
base_pointer = &base.value();
88
85
89
- ada::result out =
90
- ada::parse(std::string_view(input.out(), input.length()), base_pointer);
+ ada::result out = ada::parse(input.ToStringView(), base_pointer);
91
92
if (!out) {
93
return args.GetReturnValue().Set(false);
@@ -105,8 +101,6 @@ void Parse(const FunctionCallbackInfo<Value>& args) {
105
101
undef,
106
102
107
103
108
- undef,
109
110
104
111
SetArgs(env, argv, out);
112
USE(success_callback_->Call(
@@ -192,10 +186,8 @@ void UpdateUrl(const FunctionCallbackInfo<Value>& args) {
192
186
Utf8Value new_value(isolate, args[2].As<String>());
193
187
Local<Function> success_callback_ = args[3].As<Function>();
194
188
195
- std::string_view new_value_view =
196
- std::string_view(new_value.out(), new_value.length());
197
- std::string_view input_view = std::string_view(input.out(), input.length());
198
- ada::result out = ada::parse(input_view);
189
+ std::string_view new_value_view = new_value.ToStringView();
190
+ ada::result out = ada::parse(input.ToStringView());
199
191
CHECK(out);
200
201
bool result{true};
@@ -255,21 +247,73 @@ void UpdateUrl(const FunctionCallbackInfo<Value>& args) {
255
247
256
248
257
249
258
259
260
250
261
251
262
252
263
253
env->context(), args.This(), arraysize(argv), argv));
264
254
args.GetReturnValue().Set(result);
265
266
+void FormatUrl(const FunctionCallbackInfo<Value>& args) {
+ CHECK_GT(args.Length(), 4);
+ CHECK(args[0]->IsString()); // url href
+ Environment* env = Environment::GetCurrent(args);
+ Isolate* isolate = env->isolate();
+ Utf8Value href(isolate, args[0].As<String>());
+ const bool fragment = args[1]->IsTrue();
+ const bool unicode = args[2]->IsTrue();
267
+ const bool search = args[3]->IsTrue();
268
+ const bool auth = args[4]->IsTrue();
269
270
+ ada::result out = ada::parse(href.ToStringView());
271
+ CHECK(out);
272
273
+ if (!fragment) {
274
+ out->fragment = std::nullopt;
275
276
277
+ if (unicode) {
278
+#if defined(NODE_HAVE_I18N_SUPPORT)
+ std::string hostname = out->get_hostname();
+ MaybeStackBuffer<char> buf;
+ int32_t len = i18n::ToUnicode(&buf, hostname.data(), hostname.length());
+ if (len < 0) {
+ out->host = "";
+ } else {
+ out->host = buf.ToString();
+#else
289
290
+#endif
291
292
293
+ if (!search) {
294
+ out->query = std::nullopt;
295
296
297
+ if (!auth) {
298
+ out->username = "";
299
+ out->password = "";
300
301
+ std::string result = out->get_href();
+ args.GetReturnValue().Set(String::NewFromUtf8(env->isolate(),
+ result.data(),
+ NewStringType::kNormal,
+ result.length())
+ .ToLocalChecked());
+}
void Initialize(Local<Object> target,
311
Local<Value> unused,
312
Local<Context> context,
313
void* priv) {
314
SetMethod(context, target, "parse", Parse);
315
SetMethod(context, target, "updateUrl", UpdateUrl);
316
+ SetMethod(context, target, "formatUrl", FormatUrl);
317
318
SetMethodNoSideEffect(context, target, "domainToASCII", DomainToASCII);
319
SetMethodNoSideEffect(context, target, "domainToUnicode", DomainToUnicode);
@@ -279,6 +323,7 @@ void Initialize(Local<Object> target,
323
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
324
registry->Register(Parse);
325
registry->Register(UpdateUrl);
326
+ registry->Register(FormatUrl);
327
328
registry->Register(DomainToASCII);
329
registry->Register(DomainToUnicode);