Skip to content

Commit

Permalink
Merge pull request #68 from oncletom/fix-66
Browse files Browse the repository at this point in the history
Add tld.validHosts
  • Loading branch information
Thomas Parisot committed Oct 26, 2015
2 parents 308e8ea + 24580d3 commit 902cd16
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 10 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,26 @@ tld.isValid('https://user:password@example.co.uk:8080/some/path?and&query#hash')

# Troubleshouting

## Retrieving subdomain of `localhost` and custom hostnames

`tld.js` methods `getDomain` and `getSubdomain` are designed to **work only with *valid* TLDs**.
This way, you can trust what a domain is.

Unfortunately, `localhost` is a valid hostname but it is not a TLD.
`tld.js` has a concept of `validHosts` you declare

```js
var tld = require('tldjs');

tld.getDomain('localhost'); // returns null
tld.getSubdomain('vhost.localhost'); // returns null

tld.validHosts = ['localhost'];

tld.getDomain('localhost'); // returns 'localhost'
tld.getSubdomain('vhost.localhost'); // returns 'vhost'
```

## Updating the TLDs List

Many libraries offer a list of TLDs. But, are they up-to-date? And how to update them?
Expand Down
8 changes: 6 additions & 2 deletions lib/rule.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ function Rule (data){
this.exception = data.exception || false;
this.firstLevel = data.firstLevel || '';
this.secondLevel = data.secondLevel || null;
this.isHost = data.isHost || false;
this.source = data.source || '';
this.wildcard = data.wildcard || false;
}
Expand Down Expand Up @@ -62,16 +63,19 @@ Rule.prototype.getPattern = function getPattern(before, after){
var pattern = '';

before = (before === undefined) ? '(': before+'';
after = (after === undefined) ? ')$': before+'';
after = (after === undefined) ? ')$': after+'';

if (this.exception === true){
pattern = this.getExceptionPattern();
}
else if (this.isHost === true) {
pattern = this.firstLevel;
}
else{
pattern = '[^\\.]+' + (this.wildcard ? this.getWildcardPattern() : this.getNormalPattern());
}

return before + pattern + after;
};

module.exports = Rule;
module.exports = Rule;
10 changes: 5 additions & 5 deletions lib/tld.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ var URL = require('url');
*/
function tld () {
/* jshint validthis: true */
this.validHosts = [];
this.rules = [];
}

Expand Down Expand Up @@ -91,9 +92,9 @@ tld.getCandidateRule = function getCandidateRule (host, rules, options) {
_someFunction(rules, function (r) {
var pattern;

// sld matching? escape the loop immediately (except if it's an exception)
// sld matching or validHost? escape the loop immediately (except if it's an exception)
if ('.' + host === r.getNormalXld()) {
if (options.lazy || r.exception === true) {
if (options.lazy || r.exception || r.isHost) {
rule.normal = r;
}

Expand Down Expand Up @@ -243,7 +244,7 @@ tld.prototype.getDomain = function getDomain (host) {

host = tld.cleanHostValue(host);
hostTld = tld.extractTldFromHost(host);
rules = this.getRulesForTld(hostTld, new Rule({"firstLevel": hostTld}));
rules = this.getRulesForTld(hostTld, new Rule({"firstLevel": hostTld, "isHost": this.validHosts.indexOf(hostTld) !== -1}));
rule = tld.getCandidateRule(host, rules);

if (rule === null) {
Expand Down Expand Up @@ -288,12 +289,11 @@ tld.prototype.getSubdomain = function getSubdomain(host){
* Beware: it does not check if the TLD exists.
*
* @api
* @todo handle localhost, local etc.
* @param host {String}
* @return {Boolean}
*/
tld.prototype.isValid = function isValid (host) {
return !(typeof host !== 'string' || host.indexOf('.') === -1 || host[0] === '.');
return typeof host === 'string' && (this.validHosts.indexOf(host) !== -1 || (host.indexOf('.') !== -1 && host[0] !== '.'));
};

/**
Expand Down
31 changes: 28 additions & 3 deletions test/tld.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ describe('tld.js', function () {
describe('isValid method', function () {
it('should detect valid hostname', function () {
expect(tld.isValid('')).to.be(false);
expect(tld.isValid('localhost')).to.be(false);
expect(tld.isValid('google.com')).to.be(true);
expect(tld.isValid('miam.google.com')).to.be(true);
expect(tld.isValid('miam.miam.google.com')).to.be(true);
Expand All @@ -33,6 +34,7 @@ describe('tld.js', function () {
});

it('should be falsy on invalid domain syntax', function () {
expect(tld.isValid('.localhost')).to.be(false);
expect(tld.isValid('.google.com')).to.be(false);
expect(tld.isValid('.com')).to.be(false);
});
Expand Down Expand Up @@ -205,18 +207,19 @@ describe('tld.js', function () {
it('should return www.nytimes.com even with an URL as a parameter', function(){
expect(tldLib.cleanHostValue('http://www.nytimes.com/glogin?URI=http://www.notnytimes.com/2010/03/26/us/politics/26court.html&OQ=_rQ3D1Q26&OP=45263736Q2FKgi!KQ7Dr!K@@@Ko!fQ24KJg(Q3FQ5Cgg!Q60KQ60W.WKWQ22KQ60IKyQ3FKigQ24Q26!Q26(Q3FKQ60I(gyQ5C!Q2Ao!fQ24')).to.equal('www.nytimes.com');
});

it('should return punycode for international hostnames', function() {
expect(tldLib.cleanHostValue('台灣')).to.equal('xn--kpry57d');
});
});

describe('getSubdomain method', function(){
it('should return null if the domain cannot be found', function(){
expect(tld.getSubdomain('localhost')).to.equal(null);
expect(tld.getSubdomain('not-a-validHost')).to.equal(null);
});

it('should return the relevant subdomain of a hostname', function(){
expect(tld.getSubdomain('localhost')).to.equal(null);
expect(tld.getSubdomain('google.com')).to.equal('');
expect(tld.getSubdomain('fr.google.com')).to.equal('fr');
expect(tld.getSubdomain('random.fr.google.com')).to.equal('random.fr');
Expand Down Expand Up @@ -267,11 +270,33 @@ describe('tld.js', function () {
var domain = tld.getSubdomain('http://cdn.jsdelivr.net/g/jquery@1.8.2,jquery.waypoints@2.0.2,qtip2@2.2.1,typeahead.js@0.9.3,sisyphus@0.1,jquery.slick@1.3.15,fastclick@1.0.3');
expect(domain).to.equal('cdn');
});

//@see https://github.com/oncletom/tld.js/issues/35
it('should provide consistent results', function(){
expect(tld.getSubdomain('www.bl.uk')).to.equal('www');
expect(tld.getSubdomain('www.majestic12.co.uk')).to.equal('www');
});
});

describe('validHosts', function(){
before(function(){
tld.validHosts = ['localhost'];
});

it('should now be a valid host', function(){
expect(tld.isValid('localhost')).to.be(true);
});

it('should return the known valid host', function () {
expect(tld.getDomain('localhost')).to.equal('localhost');
expect(tld.getDomain('subdomain.localhost')).to.equal('localhost');
expect(tld.getDomain('subdomain.notlocalhost')).to.equal('subdomain.notlocalhost');
expect(tld.getDomain('subdomain.not-localhost')).to.equal('subdomain.not-localhost');
});

//@see https://github.com/oncletom/tld.js/issues/66
it('should return the subdomain of a validHost', function(){
expect(tld.getSubdomain('vhost.localhost')).to.equal('vhost');
});
});
});

0 comments on commit 902cd16

Please sign in to comment.