Skip to content

Commit

Permalink
Use most specific matches, not the ones with highest q
Browse files Browse the repository at this point in the history
  • Loading branch information
federomero committed Jan 16, 2014
1 parent a3ceee5 commit 8ed7607
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 49 deletions.
22 changes: 16 additions & 6 deletions lib/charset.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ function parseAcceptCharset(accept) {
return accept.split(',').map(function(e) {
return parseCharset(e.trim());
}).filter(function(e) {
return e && e.q > 0;
return e;
});
}

Expand Down Expand Up @@ -37,15 +37,23 @@ function getCharsetPriority(charset, accepted) {
return specify(charset, a);
}).sort(function (a, b) {
// revsort
return a.q === b.q ? 0 : a.q > b.q ? -1 : 1;
return a.s > b.s ? -1 : 1;
})[0] || {q:0}).q;
}

function specify(charset, spec) {
if (spec.charset === '*' || spec.charset === charset) {
return spec;
var s = 0;
if(spec.charset === charset){
s |= 1;
} else if (spec.charset !== '*' ) {
return null
}
};

return {
s: s,
q: spec.q,
}
}

function preferredCharsets(accept, provided) {
accept = parseAcceptCharset(accept || '');
Expand All @@ -56,14 +64,16 @@ function preferredCharsets(accept, provided) {
return pair[1] > 0;
}).sort(function(a, b) {
// revsort
return a[1] === b[1] ? 0 : a[1] > b[1] ? -1 : 1;
return a[1] > b[1] ? -1 : 1;
}).map(function(pair) {
return pair[0];
});
} else {
return accept.sort(function (a, b) {
// revsort
return a.q < b.q ? 1 : -1;
}).filter(function(type) {
return type.q > 0;
}).map(function(type) {
return type.charset;
});
Expand Down
24 changes: 18 additions & 6 deletions lib/encoding.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function parseAcceptEncoding(accept) {
}

return acceptableEncodings.filter(function(e) {
return e && e.q > 0;
return e;
});
}

Expand Down Expand Up @@ -64,19 +64,29 @@ function parseEncoding(s) {
}

function getEncodingPriority(encoding, accepted) {
return (accepted.filter(function(a) {
return (accepted.map(function(a) {
return specify(encoding, a);
}).filter(function(a){
return a;
}).sort(function (a, b) {
// revsort
return a.q === b.q ? 0 : a.q > b.q ? -1 : 1;
return a.s > b.s ? -1 : 1;
})[0] || {q:0}).q;
}

function specify(encoding, spec) {
if (spec.encoding === '*' || spec.encoding === encoding) {
return spec;
var s = 0;
if(spec.encoding === encoding){
s |= 1;
} else if (spec.encoding !== '*' ) {
return null
}
}

return {
s: s,
q: spec.q,
}
};

function preferredEncodings(accept, provided) {
accept = parseAcceptEncoding(accept || '');
Expand All @@ -95,6 +105,8 @@ function preferredEncodings(accept, provided) {
return accept.sort(function (a, b) {
// revsort
return a.q < b.q ? 1 : -1;
}).filter(function(type){
return type.q > 0;
}).map(function(type) {
return type.encoding;
});
Expand Down
53 changes: 28 additions & 25 deletions lib/language.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ function parseAcceptLanguage(accept) {
return accept.split(',').map(function(e) {
return parseLanguage(e.trim());
}).filter(function(e) {
return e && e.q > 0;
return e;
});
}

Expand Down Expand Up @@ -37,33 +37,34 @@ function parseLanguage(s) {
}

function getLanguagePriority(language, accepted) {
var match = getClosestMatch(language, accepted);
return match ? match.q : 0;
return (accepted.map(function(a){
return specify(language, a);
}).filter(function(a){
return a;
}).sort(function(a, b){
// revsort
return a.s > b.s ? -1 : 1;
})[0] || {q:0}).q;
}

function getClosestMatch(language, accepted) {
var parsed = parseLanguage(language);

var matches = accepted.filter(function(a) {
return a.full === parsed.full;
});
if (matches.length) return matches[0];

matches = accepted.filter(function(a) {
return a.prefix === parsed.prefix && !a.suffix;
});
if (matches.length) return matches[0];

matches = accepted.filter(function(a) {
return a.prefix === parsed.prefix;
});
if (matches.length) return matches[0];
function specify(language, spec) {
var p = parseLanguage(language)
var s = 0;
if(spec.full === p.full){
s |= 4;
} else if (spec.prefix === p.full) {
s |= 2;
} else if (spec.full === p.prefix) {
s |= 1;
} else if (spec.full !== '*' ) {
return null
}

matches = accepted.filter(function(a) {
return a.prefix === '*';
});
return matches[0];
}
return {
s: s,
q: spec.q,
}
};

function preferredLanguages(accept, provided) {
accept = parseAcceptLanguage(accept || '');
Expand All @@ -85,6 +86,8 @@ function preferredLanguages(accept, provided) {
return accept.sort(function (a, b) {
// revsort
return a.q < b.q ? 1 : -1;
}).filter(function(type) {
return type.q > 0;
}).map(function(type) {
return type.full;
});
Expand Down
35 changes: 24 additions & 11 deletions lib/mediaType.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ function parseAccept(accept) {
return accept.split(',').map(function(e) {
return parseMediaType(e.trim());
}).filter(function(e) {
return e && e.q > 0;
return e;
});
};

Expand Down Expand Up @@ -47,31 +47,42 @@ function getMediaTypePriority(type, accepted) {
return specify(type, a);
}).sort(function (a, b) {
// revsort
return a.q > b.q ? -1 : 1;
return a.s > b.s ? -1 : 1;
})[0] || {q:0}).q;
}

function specifies(spec, type) {
return spec === '*' || spec === type;
}

function specify(type, spec) {
var p = parseMediaType(type);
var s = 0;
if(spec.type == p.type) {
s |= 4
} else if(spec.type != '*') {
return null;
}

if(spec.subtype == p.subtype) {
s |= 2
} else if(spec.subtype != '*') {
return null;
}


if (spec.params) {
var keys = Object.keys(spec.params);
if (keys.some(function (k) {
return !specifies(spec.params[k], p.params[k]);
return spec.params[k] == '*' || spec.params[k] == p.params[k];
})) {
// some didn't specify.
return null;
} else {
s |= 1;
}
}

if (specifies(spec.type, p.type) &&
specifies(spec.subtype, p.subtype)) {
return spec;
return {
q: spec.q,
s: s,
}

}

function preferredMediaTypes(accept, provided) {
Expand All @@ -92,6 +103,8 @@ function preferredMediaTypes(accept, provided) {
return accept.sort(function (a, b) {
// revsort
return a.q < b.q ? 1 : -1;
}).filter(function(type) {
return type.q > 0;
}).map(function(type) {
return type.full;
});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "negotiator",
"description": "HTTP content negotiation",
"version": "0.4.0",
"version": "0.4.1",
"author": "Federico Romero <federico.romero@outboxlabs.com>",
"contributors": ["Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)"],
"repository": {
Expand Down
4 changes: 4 additions & 0 deletions test/charset.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
accept: 'utf-8;q=0.8, ISO-8859-1',
provided: null,
selected: ['ISO-8859-1', 'utf-8']
}, {
accept: '*, utf-8;q=0',
provided: ['utf-8', 'ISO-8859-1'],
selected: ['ISO-8859-1']
}
];

Expand Down
4 changes: 4 additions & 0 deletions test/encoding.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
accept: 'gzip;q=0.8, compress',
provided: ['gzip', 'compress'],
selected: ['compress', 'gzip']
}, {
accept: '*, compress;q=0',
provided: ['gzip', 'compress'],
selected: ['gzip']
}, {
accept: 'gzip;q=0.8, compress',
provided: null,
Expand Down
4 changes: 4 additions & 0 deletions test/language.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
accept: 'en-US;q=0.8, es',
provided: ['en', 'es'],
selected: ['es', 'en']
}, {
accept: '*, en;q=0',
provided: ['en', 'es'],
selected: ['es']
}, {
accept: 'en-US;q=0.8, es',
provided: null,
Expand Down
8 changes: 8 additions & 0 deletions test/mediaType.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@
accept: 'application/json;q=0.2, text/html',
provided: null,
selected: ['text/html', 'application/json']
}, {
accept: 'text/*, text/html;q=0',
provided: ['text/html', 'text/plain'],
selected: ['text/plain']
}, {
accept: 'text/*, text/html;q=0.5',
provided: ['text/html', 'text/plain'],
selected: ['text/plain', 'text/html']
}
];

Expand Down

0 comments on commit 8ed7607

Please sign in to comment.