126 lines
2.5 KiB
JavaScript
Executable File
126 lines
2.5 KiB
JavaScript
Executable File
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;
|
|
});
|
|
}
|
|
}
|