Permalink
Browse files

Use most specific matches, not the ones with highest q

  • Loading branch information...
federomero committed Jan 16, 2014
1 parent a3ceee5 commit 8ed7607a13ec301133cef24d07b5c266dbdd39c4
Showing with 107 additions and 49 deletions.
  1. +16 −6 lib/charset.js
  2. +18 −6 lib/encoding.js
  3. +28 −25 lib/language.js
  4. +24 −11 lib/mediaType.js
  5. +1 −1 package.json
  6. +4 −0 test/charset.js
  7. +4 −0 test/encoding.js
  8. +4 −0 test/language.js
  9. +8 −0 test/mediaType.js
View
@@ -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;
});
}
@@ -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 || '');
@@ -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;
});
View
@@ -35,7 +35,7 @@ function parseAcceptEncoding(accept) {
}
return acceptableEncodings.filter(function(e) {
- return e && e.q > 0;
+ return e;
});
}
@@ -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 || '');
@@ -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;
});
View
@@ -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;
});
}
@@ -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 || '');
@@ -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;
});
View
@@ -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;
});
};
@@ -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) {
@@ -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;
});
View
@@ -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": {
View
@@ -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']
}
];
View
@@ -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,
View
@@ -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,
View
@@ -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']
}
];

0 comments on commit 8ed7607

Please sign in to comment.