Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mediaType.js 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /**
  2. * negotiator
  3. * Copyright(c) 2012 Isaac Z. Schlueter
  4. * Copyright(c) 2014 Federico Romero
  5. * Copyright(c) 2014-2015 Douglas Christopher Wilson
  6. * MIT Licensed
  7. */
  8. 'use strict';
  9. /**
  10. * Module exports.
  11. * @public
  12. */
  13. module.exports = preferredMediaTypes;
  14. module.exports.preferredMediaTypes = preferredMediaTypes;
  15. /**
  16. * Module variables.
  17. * @private
  18. */
  19. var simpleMediaTypeRegExp = /^\s*([^\s\/;]+)\/([^;\s]+)\s*(?:;(.*))?$/;
  20. /**
  21. * Parse the Accept header.
  22. * @private
  23. */
  24. function parseAccept(accept) {
  25. var accepts = splitMediaTypes(accept);
  26. for (var i = 0, j = 0; i < accepts.length; i++) {
  27. var mediaType = parseMediaType(accepts[i].trim(), i);
  28. if (mediaType) {
  29. accepts[j++] = mediaType;
  30. }
  31. }
  32. // trim accepts
  33. accepts.length = j;
  34. return accepts;
  35. }
  36. /**
  37. * Parse a media type from the Accept header.
  38. * @private
  39. */
  40. function parseMediaType(str, i) {
  41. var match = simpleMediaTypeRegExp.exec(str);
  42. if (!match) return null;
  43. var params = Object.create(null);
  44. var q = 1;
  45. var subtype = match[2];
  46. var type = match[1];
  47. if (match[3]) {
  48. var kvps = splitParameters(match[3]).map(splitKeyValuePair);
  49. for (var j = 0; j < kvps.length; j++) {
  50. var pair = kvps[j];
  51. var key = pair[0].toLowerCase();
  52. var val = pair[1];
  53. // get the value, unwrapping quotes
  54. var value = val && val[0] === '"' && val[val.length - 1] === '"'
  55. ? val.substr(1, val.length - 2)
  56. : val;
  57. if (key === 'q') {
  58. q = parseFloat(value);
  59. break;
  60. }
  61. // store parameter
  62. params[key] = value;
  63. }
  64. }
  65. return {
  66. type: type,
  67. subtype: subtype,
  68. params: params,
  69. q: q,
  70. i: i
  71. };
  72. }
  73. /**
  74. * Get the priority of a media type.
  75. * @private
  76. */
  77. function getMediaTypePriority(type, accepted, index) {
  78. var priority = {o: -1, q: 0, s: 0};
  79. for (var i = 0; i < accepted.length; i++) {
  80. var spec = specify(type, accepted[i], index);
  81. if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
  82. priority = spec;
  83. }
  84. }
  85. return priority;
  86. }
  87. /**
  88. * Get the specificity of the media type.
  89. * @private
  90. */
  91. function specify(type, spec, index) {
  92. var p = parseMediaType(type);
  93. var s = 0;
  94. if (!p) {
  95. return null;
  96. }
  97. if(spec.type.toLowerCase() == p.type.toLowerCase()) {
  98. s |= 4
  99. } else if(spec.type != '*') {
  100. return null;
  101. }
  102. if(spec.subtype.toLowerCase() == p.subtype.toLowerCase()) {
  103. s |= 2
  104. } else if(spec.subtype != '*') {
  105. return null;
  106. }
  107. var keys = Object.keys(spec.params);
  108. if (keys.length > 0) {
  109. if (keys.every(function (k) {
  110. return spec.params[k] == '*' || (spec.params[k] || '').toLowerCase() == (p.params[k] || '').toLowerCase();
  111. })) {
  112. s |= 1
  113. } else {
  114. return null
  115. }
  116. }
  117. return {
  118. i: index,
  119. o: spec.i,
  120. q: spec.q,
  121. s: s,
  122. }
  123. }
  124. /**
  125. * Get the preferred media types from an Accept header.
  126. * @public
  127. */
  128. function preferredMediaTypes(accept, provided) {
  129. // RFC 2616 sec 14.2: no header = */*
  130. var accepts = parseAccept(accept === undefined ? '*/*' : accept || '');
  131. if (!provided) {
  132. // sorted list of all types
  133. return accepts
  134. .filter(isQuality)
  135. .sort(compareSpecs)
  136. .map(getFullType);
  137. }
  138. var priorities = provided.map(function getPriority(type, index) {
  139. return getMediaTypePriority(type, accepts, index);
  140. });
  141. // sorted list of accepted types
  142. return priorities.filter(isQuality).sort(compareSpecs).map(function getType(priority) {
  143. return provided[priorities.indexOf(priority)];
  144. });
  145. }
  146. /**
  147. * Compare two specs.
  148. * @private
  149. */
  150. function compareSpecs(a, b) {
  151. return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0;
  152. }
  153. /**
  154. * Get full type string.
  155. * @private
  156. */
  157. function getFullType(spec) {
  158. return spec.type + '/' + spec.subtype;
  159. }
  160. /**
  161. * Check if a spec has any quality.
  162. * @private
  163. */
  164. function isQuality(spec) {
  165. return spec.q > 0;
  166. }
  167. /**
  168. * Count the number of quotes in a string.
  169. * @private
  170. */
  171. function quoteCount(string) {
  172. var count = 0;
  173. var index = 0;
  174. while ((index = string.indexOf('"', index)) !== -1) {
  175. count++;
  176. index++;
  177. }
  178. return count;
  179. }
  180. /**
  181. * Split a key value pair.
  182. * @private
  183. */
  184. function splitKeyValuePair(str) {
  185. var index = str.indexOf('=');
  186. var key;
  187. var val;
  188. if (index === -1) {
  189. key = str;
  190. } else {
  191. key = str.substr(0, index);
  192. val = str.substr(index + 1);
  193. }
  194. return [key, val];
  195. }
  196. /**
  197. * Split an Accept header into media types.
  198. * @private
  199. */
  200. function splitMediaTypes(accept) {
  201. var accepts = accept.split(',');
  202. for (var i = 1, j = 0; i < accepts.length; i++) {
  203. if (quoteCount(accepts[j]) % 2 == 0) {
  204. accepts[++j] = accepts[i];
  205. } else {
  206. accepts[j] += ',' + accepts[i];
  207. }
  208. }
  209. // trim accepts
  210. accepts.length = j + 1;
  211. return accepts;
  212. }
  213. /**
  214. * Split a string of parameters.
  215. * @private
  216. */
  217. function splitParameters(str) {
  218. var parameters = str.split(';');
  219. for (var i = 1, j = 0; i < parameters.length; i++) {
  220. if (quoteCount(parameters[j]) % 2 == 0) {
  221. parameters[++j] = parameters[i];
  222. } else {
  223. parameters[j] += ';' + parameters[i];
  224. }
  225. }
  226. // trim parameters
  227. parameters.length = j + 1;
  228. for (var i = 0; i < parameters.length; i++) {
  229. parameters[i] = parameters[i].trim();
  230. }
  231. return parameters;
  232. }