/
mediaType.js
98 lines (83 loc) · 2.05 KB
/
mediaType.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
module.exports = preferredMediaTypes;
preferredMediaTypes.preferredMediaTypes = preferredMediaTypes;
function parseAccept(accept) {
return accept.split(',').map(function(e) {
return parseMediaType(e.trim());
}).filter(function(e) {
return e && e.q > 0;
});
};
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.filter(function(a) {
return specify(type, a);
}).sort(function (a, b) {
// revsort
return a.q > b.q ? -1 : 1;
})[0] || {q:0}).q;
}
function specifies(spec, type) {
return spec === '*' || spec === type;
}
function specify(type, spec) {
var p = parseMediaType(type);
if (spec.params) {
var keys = Object.keys(spec.params);
if (keys.some(function (k) {
return !specifies(spec.params[k], p.params[k]);
})) {
// some didn't specify.
return null;
}
}
if (specifies(spec.type, p.type) &&
specifies(spec.subtype, p.subtype)) {
return spec;
}
}
function preferredMediaTypes(accept, provided) {
accept = parseAccept(accept || '');
if (provided) {
return provided.map(function(type) {
return [type, getMediaTypePriority(type, accept)];
}).filter(function(pair) {
return pair[1] > 0;
}).sort(function(a, b) {
// revsort
return a[1] === b[1] ? 0 : a[1] > b[1] ? -1 : 1;
}).map(function(pair) {
return pair[0];
});
} else {
return accept.map(function(type) {
return type.full;
});
}
}