Skip to content

Commit cf40145

Browse files
authored
fix: URL validation for hostnames with ports (no protocol) (#2622)
1 parent 4af6124 commit cf40145

File tree

2 files changed

+73
-4
lines changed

2 files changed

+73
-4
lines changed

src/lib/isURL.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,24 @@ export default function isURL(url, options) {
142142
}
143143
}
144144
} else {
145-
// No @ symbol, this is definitely a protocol
146-
url = cleanUpProtocol(potential_protocol);
145+
// No @ symbol found. Check if this could be a port number instead of a protocol.
146+
// If what's after the colon is numeric (or starts with a digit and contains only
147+
// valid port characters until a path separator), it's likely hostname:port, not a protocol.
148+
const looks_like_port = /^[0-9]/.test(after_colon);
147149

148-
if (url === false) {
149-
return false;
150+
if (looks_like_port) {
151+
// This looks like hostname:port, not a protocol
152+
if (options.require_protocol) {
153+
return false;
154+
}
155+
// Don't consume anything; let it be parsed as hostname:port
156+
} else {
157+
// This is definitely a protocol
158+
url = cleanUpProtocol(potential_protocol);
159+
160+
if (url === false) {
161+
return false;
162+
}
150163
}
151164
}
152165
} else {

test/validators.test.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,62 @@ describe('Validators', () => {
488488
});
489489
});
490490

491+
it('should validate URLs without protocol', () => {
492+
test({
493+
validator: 'isURL',
494+
args: [{
495+
require_tld: false,
496+
require_valid_protocol: false,
497+
}],
498+
valid: [
499+
'localhost',
500+
'localhost:3000',
501+
'service-name:8080',
502+
'https://localhost',
503+
'http://localhost:3000',
504+
'http://service-name:8080',
505+
'user:password@localhost',
506+
'user:pass@service-name:8080',
507+
],
508+
invalid: [],
509+
});
510+
511+
// Test with require_protocol: true - should reject hostnames with ports but no protocol
512+
test({
513+
validator: 'isURL',
514+
args: [{
515+
require_tld: false,
516+
require_protocol: true,
517+
require_valid_protocol: false,
518+
}],
519+
valid: [
520+
'http://localhost:3000',
521+
'https://service-name:8080',
522+
'custom://localhost',
523+
],
524+
invalid: [
525+
'localhost:3000',
526+
'service-name:8080',
527+
'user:password@localhost',
528+
],
529+
});
530+
531+
// Test non-numeric patterns after colon (should be treated as protocols)
532+
test({
533+
validator: 'isURL',
534+
args: [{
535+
require_tld: false,
536+
require_valid_protocol: false,
537+
protocols: ['custom', 'myscheme'],
538+
}],
539+
valid: [
540+
'custom:something',
541+
'myscheme:data',
542+
],
543+
invalid: [],
544+
});
545+
});
546+
491547
it('should validate URLs with custom protocols', () => {
492548
test({
493549
validator: 'isURL',

0 commit comments

Comments
 (0)