123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- module.exports = preferredMediaTypes;
- preferredMediaTypes.preferredMediaTypes = preferredMediaTypes;
- function parseAccept(accept) {
- return accept.split(',').map(function(e) {
- return parseMediaType(e.trim());
- }).filter(function(e) {
- return e;
- });
- };
- function parseMediaType(s) {
- var match = s.match(/\s*(\S+?)\/([^;\s]+)\s*(?:;(.*))?/);
- if (!match) return null;
- var type = match[1],
- subtype = match[2],
- full = "" + type + "/" + subtype,
- params = {},
- q = 1;
- if (match[3]) {
- params = match[3].split(';').map(function(s) {
- return s.trim().split('=');
- }).reduce(function (set, p) {
- set[p[0]] = p[1];
- return set
- }, params);
- if (params.q != null) {
- q = parseFloat(params.q);
- delete params.q;
- }
- }
- return {
- type: type,
- subtype: subtype,
- params: params,
- q: q,
- full: full
- };
- }
- function getMediaTypePriority(type, accepted) {
- return (accepted.map(function(a) {
- return specify(type, a);
- }).filter(Boolean).sort(function (a, b) {
- if(a.s == b.s) {
- return a.q > b.q ? -1 : 1;
- } else {
- return a.s > b.s ? -1 : 1;
- }
- })[0] || {s: 0, q: 0});
- }
- function specify(type, spec) {
- var p = parseMediaType(type);
- var s = 0;
- if (!p) {
- return null;
- }
- 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;
- }
- var keys = Object.keys(spec.params);
- if (keys.length > 0) {
- if (keys.every(function (k) {
- return spec.params[k] == '*' || spec.params[k] == p.params[k];
- })) {
- s |= 1
- } else {
- return null
- }
- }
- return {
- q: spec.q,
- s: s,
- }
- }
- function preferredMediaTypes(accept, provided) {
- // RFC 2616 sec 14.2: no header = */*
- accept = parseAccept(accept === undefined ? '*/*' : accept || '');
- if (provided) {
- return provided.map(function(type) {
- return [type, getMediaTypePriority(type, accept)];
- }).filter(function(pair) {
- return pair[1].q > 0;
- }).sort(function(a, b) {
- var pa = a[1];
- var pb = b[1];
- if(pa.q == pb.q) {
- return pa.s < pb.s ? 1 : -1;
- } else {
- return pa.q < pb.q ? 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.full;
- });
- }
- }
|