Skip to content

Commit 54a475f

Browse files
committed
Fixing Issue #19 - relative scheme URLs
1 parent c1da024 commit 54a475f

4 files changed

Lines changed: 88 additions & 25 deletions

File tree

docs.html

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,16 @@ <h3 id="accessors-protocol">protocol(), scheme()</h3>
198198
// get protocol
199199
uri.protocol(); // returns string "http"
200200
// set protocol
201-
uri.protocol("ftp"); // returns the URI instance for chaining</pre>
202-
<p>NOTE: Throws a <code>TypeError</code> on illegal input</p>
201+
uri.protocol("ftp"); // returns the URI instance for chaining
202+
203+
// relative scheme
204+
uri.protocol("");
205+
uri.toString() === '//example.org/foo/hello.html';
206+
207+
// remove scheme
208+
uri.protocol(null);
209+
uri.toString() === 'example.org/foo/hello.html';</pre>
210+
<p>NOTE: Throws a <code>TypeError</code> on illegal input, that is anything but <code>[a-z0-9.+-]</code> and <code>[empty string]</code> and <code>null</code></p>
203211

204212
<h3 id="accessors-username">username()</h3>
205213
<pre class="prettyprint lang-js">var uri = new URI("http://user:pass@example.org/foo/hello.html");

src/URI.js

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -198,17 +198,25 @@ URI.parse = function(string) {
198198
}
199199

200200
// extract protocol
201-
pos = string.indexOf(':');
202-
if (pos > -1) {
203-
parts.protocol = string.substring(0, pos);
204-
if (string.substring(pos + 1, pos + 3) === '//') {
205-
string = string.substring(pos + 3);
206-
207-
// extract "user:pass@host:port"
208-
string = URI.parseAuthority(string, parts);
209-
} else {
210-
string = string.substring(pos + 1);
211-
parts.urn = true;
201+
if (string.substring(0, 2) === '//') {
202+
// relative-scheme
203+
parts.protocol = '';
204+
string = string.substring(2);
205+
// extract "user:pass@host:port"
206+
string = URI.parseAuthority(string, parts);
207+
} else {
208+
pos = string.indexOf(':');
209+
if (pos > -1) {
210+
parts.protocol = string.substring(0, pos);
211+
if (string.substring(pos + 1, pos + 3) === '//') {
212+
string = string.substring(pos + 3);
213+
214+
// extract "user:pass@host:port"
215+
string = URI.parseAuthority(string, parts);
216+
} else {
217+
string = string.substring(pos + 1);
218+
parts.urn = true;
219+
}
212220
}
213221
}
214222

@@ -316,9 +324,10 @@ URI.build = function(parts) {
316324

317325
if (typeof parts.protocol === "string" && parts.protocol.length) {
318326
t += parts.protocol + ":";
319-
if (!parts.urn) {
320-
t += '//';
321-
}
327+
}
328+
329+
if ((t || parts.protocol === '') && !parts.urn) {
330+
t += '//';
322331
}
323332

324333
t += (URI.buildAuthority(parts) || '');
@@ -705,11 +714,11 @@ var _protocol = p.protocol,
705714

706715
p.protocol = function(v, build) {
707716
if (v !== undefined) {
708-
// accept trailing :
709717
if (v) {
710-
if (v[v.length - 1] === ":") {
711-
v = v.substring(0, v.length - 1);
712-
} else if (v.match(/[^a-zA-z0-9\.+-]/)) {
718+
// accept trailing ://
719+
v = v.replace(/:(\/\/)?$/, '');
720+
721+
if (v.match(/[^a-zA-z0-9\.+-]/)) {
713722
throw new TypeError("Protocol '" + v + "' contains characters other than [A-Z0-9.+-]");
714723
}
715724
}

test/test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,12 @@ test("protocol", function() {
8282
equal(u+"", "ftp://example.org/foo.html", "ftp url");
8383

8484
u.protocol('');
85-
equal(u.protocol(), "", "missing protocol");
86-
equal(u+"", "example.org/foo.html", "no-scheme url");
85+
equal(u.protocol(), "", "relative protocol");
86+
equal(u+"", "//example.org/foo.html", "relative-scheme url");
8787

8888
u.protocol(null);
8989
equal(u.protocol(), "", "missing protocol");
90-
equal(u+"", "example.org/foo.html", "no-scheme url");
90+
equal(u+"", "example.org/foo.html", "missing-scheme url");
9191
});
9292
test("username", function() {
9393
var u = new URI("http://example.org/foo.html");

test/urls.js

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,9 +371,9 @@ var urls = [{
371371
}, {
372372
name: 'ignoring scheme',
373373
url: '://user:pass@example.org:123/some/directory/file.html?query=string#fragment',
374-
_url: 'user:pass@example.org:123/some/directory/file.html?query=string#fragment',
374+
_url: '//user:pass@example.org:123/some/directory/file.html?query=string#fragment',
375375
parts: {
376-
protocol: "", // not null
376+
protocol: "",
377377
username: 'user',
378378
password: 'pass',
379379
hostname: 'example.org',
@@ -415,6 +415,52 @@ var urls = [{
415415
idn: false,
416416
punycode: false
417417
}
418+
}, {
419+
name: 'scheme-relative URL',
420+
url: '//www.example.org/',
421+
parts: {
422+
protocol: '', // not null
423+
username: null,
424+
password: null,
425+
hostname: 'www.example.org',
426+
port: null,
427+
path: '/',
428+
query: null,
429+
fragment: null
430+
},
431+
accessors: {
432+
protocol: '',
433+
username: '',
434+
password: '',
435+
port: '',
436+
path: '/',
437+
query: '',
438+
fragment: '',
439+
authority: 'www.example.org',
440+
userinfo: '',
441+
subdomain: 'www',
442+
domain: 'example.org',
443+
tld: 'org',
444+
directory: '/',
445+
filename: '',
446+
suffix: '',
447+
hash: '',
448+
search: '',
449+
host: 'www.example.org',
450+
hostname: 'www.example.org'
451+
},
452+
is: {
453+
urn: false,
454+
url: true,
455+
relative: false,
456+
name: true,
457+
sld: false,
458+
ip: false,
459+
ip4: false,
460+
ip6: false,
461+
idn: false,
462+
punycode: false
463+
}
418464
}, {
419465
name: 'IPv4',
420466
url: 'http://user:pass@123.123.123.123:123/some/directory/file.html?query=string#fragment',

0 commit comments

Comments
 (0)