summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NOTICE4
-rw-r--r--share/Makefile.am1
-rw-r--r--share/server/mimeparse.js158
-rw-r--r--share/server/render.js102
4 files changed, 163 insertions, 102 deletions
diff --git a/NOTICE b/NOTICE
index b972b136..cbde88d0 100644
--- a/NOTICE
+++ b/NOTICE
@@ -29,3 +29,7 @@ This product also includes the following third-party components:
* ibrowse (http://github.com/cmullaparthi/ibrowse/tree/master)
Copyright 2009, Chandrashekhar Mullaparthi
+
+ * mimeparse.js (http://code.google.com/p/mimeparse/)
+
+ Copyright 2009, Chris Anderson <jchris@apache.org>
diff --git a/share/Makefile.am b/share/Makefile.am
index 8071525f..b17dcb4e 100644
--- a/share/Makefile.am
+++ b/share/Makefile.am
@@ -14,6 +14,7 @@ JS_FILE = server/main.js
JS_FILE_COMPONENTS = \
server/filter.js \
+ server/mimeparse.js \
server/render.js \
server/state.js \
server/util.js \
diff --git a/share/server/mimeparse.js b/share/server/mimeparse.js
new file mode 100644
index 00000000..3642a194
--- /dev/null
+++ b/share/server/mimeparse.js
@@ -0,0 +1,158 @@
+// mimeparse.js
+//
+// This module provides basic functions for handling mime-types. It can
+// handle matching mime-types against a list of media-ranges. See section
+// 14.1 of the HTTP specification [RFC 2616] for a complete explanation.
+//
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
+//
+// A port to JavaScript of Joe Gregorio's MIME-Type Parser:
+//
+// http://code.google.com/p/mimeparse/
+//
+// Ported by J. Chris Anderson <jchris@apache.org>, targeting the Spidermonkey runtime.
+//
+// To run the tests, open mimeparse-js-test.html in a browser.
+// Ported from version 0.1.2
+// Comments are mostly excerpted from the original.
+
+var Mimeparse = (function() {
+ // private helpers
+ function strip(string) {
+ return string.replace(/^\s+/, '').replace(/\s+$/, '')
+ };
+
+ function parseRanges(ranges) {
+ var parsedRanges = [], rangeParts = ranges.split(",");
+ for (var i=0; i < rangeParts.length; i++) {
+ parsedRanges.push(publicMethods.parseMediaRange(rangeParts[i]))
+ };
+ return parsedRanges;
+ };
+
+ var publicMethods = {
+ // Carves up a mime-type and returns an Array of the
+ // [type, subtype, params] where "params" is a Hash of all
+ // the parameters for the media range.
+ //
+ // For example, the media range "application/xhtml;q=0.5" would
+ // get parsed into:
+ //
+ // ["application", "xhtml", { "q" : "0.5" }]
+ parseMimeType : function(mimeType) {
+ var fullType, typeParts, params = {}, parts = mimeType.split(';');
+ for (var i=0; i < parts.length; i++) {
+ var p = parts[i].split('=');
+ if (p.length == 2) {
+ params[strip(p[0])] = strip(p[1]);
+ }
+ };
+ fullType = parts[0].replace(/^\s+/, '').replace(/\s+$/, '');
+ if (fullType == '*') fullType = '*/*';
+ typeParts = fullType.split('/');
+ return [typeParts[0], typeParts[1], params];
+ },
+
+ // Carves up a media range and returns an Array of the
+ // [type, subtype, params] where "params" is a Object with
+ // all the parameters for the media range.
+ //
+ // For example, the media range "application/*;q=0.5" would
+ // get parsed into:
+ //
+ // ["application", "*", { "q" : "0.5" }]
+ //
+ // In addition this function also guarantees that there
+ // is a value for "q" in the params dictionary, filling it
+ // in with a proper default if necessary.
+ parseMediaRange : function(range) {
+ var q, parsedType = this.parseMimeType(range);
+ if (!parsedType[2]['q']) {
+ parsedType[2]['q'] = '1';
+ } else {
+ q = parseFloat(parsedType[2]['q']);
+ if (isNaN(q)) {
+ parsedType[2]['q'] = '1';
+ } else if (q > 1 || q < 0) {
+ parsedType[2]['q'] = '1';
+ }
+ }
+ return parsedType;
+ },
+
+ // Find the best match for a given mime-type against
+ // a list of media_ranges that have already been
+ // parsed by parseMediaRange(). Returns an array of
+ // the fitness value and the value of the 'q' quality
+ // parameter of the best match, or (-1, 0) if no match
+ // was found. Just as for qualityParsed(), 'parsed_ranges'
+ // must be a list of parsed media ranges.
+ fitnessAndQualityParsed : function(mimeType, parsedRanges) {
+ var bestFitness = -1, bestFitQ = 0, target = this.parseMediaRange(mimeType);
+ var targetType = target[0], targetSubtype = target[1], targetParams = target[2];
+
+ for (var i=0; i < parsedRanges.length; i++) {
+ var parsed = parsedRanges[i];
+ var type = parsed[0], subtype = parsed[1], params = parsed[2];
+ if ((type == targetType || type == "*" || targetType == "*") &&
+ (subtype == targetSubtype || subtype == "*" || targetSubtype == "*")) {
+ var matchCount = 0;
+ for (param in targetParams) {
+ if (param != 'q' && params[param] && params[param] == targetParams[param]) {
+ matchCount += 1;
+ }
+ }
+
+ var fitness = (type == targetType) ? 100 : 0;
+ fitness += (subtype == targetSubtype) ? 10 : 0;
+ fitness += matchCount;
+
+ if (fitness > bestFitness) {
+ bestFitness = fitness;
+ bestFitQ = params["q"];
+ }
+ }
+ };
+ return [bestFitness, parseFloat(bestFitQ)];
+ },
+
+ // Find the best match for a given mime-type against
+ // a list of media_ranges that have already been
+ // parsed by parseMediaRange(). Returns the
+ // 'q' quality parameter of the best match, 0 if no
+ // match was found. This function bahaves the same as quality()
+ // except that 'parsedRanges' must be a list of
+ // parsed media ranges.
+ qualityParsed : function(mimeType, parsedRanges) {
+ return this.fitnessAndQualityParsed(mimeType, parsedRanges)[1];
+ },
+
+ // Returns the quality 'q' of a mime-type when compared
+ // against the media-ranges in ranges. For example:
+ //
+ // >>> Mimeparse.quality('text/html','text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5')
+ // 0.7
+ quality : function(mimeType, ranges) {
+ return this.qualityParsed(mimeType, parseRanges(ranges));
+ },
+
+ // Takes a list of supported mime-types and finds the best
+ // match for all the media-ranges listed in header. The value of
+ // header must be a string that conforms to the format of the
+ // HTTP Accept: header. The value of 'supported' is a list of
+ // mime-types.
+ //
+ // >>> bestMatch(['application/xbel+xml', 'text/xml'], 'text/*;q=0.5,*/*; q=0.1')
+ // 'text/xml'
+ bestMatch : function(supported, header) {
+ var parsedHeader = parseRanges(header);
+ var weighted = [];
+ for (var i=0; i < supported.length; i++) {
+ weighted.push([publicMethods.fitnessAndQualityParsed(supported[i], parsedHeader), i, supported[i]])
+ };
+ weighted.sort();
+ return weighted[weighted.length-1][0][1] ? weighted[weighted.length-1][2] : '';
+ }
+ }
+ return publicMethods;
+})();
diff --git a/share/server/render.js b/share/server/render.js
index 6efc9687..9537cd54 100644
--- a/share/server/render.js
+++ b/share/server/render.js
@@ -10,108 +10,6 @@
// License for the specific language governing permissions and limitations under
// the License.
-// mimeparse.js
-// http://code.google.com/p/mimeparse/
-// MIT Licensed http://www.opensource.org/licenses/mit-license.php
-// Code with comments: http://mimeparse.googlecode.com/svn/trunk/mimeparse.js
-// Tests: http://mimeparse.googlecode.com/svn/trunk/mimeparse-js-test.html
-// Ported by Chris Anderson from version 0.1.2
-
-var Mimeparse = (function() {
- function strip(string) {
- return string.replace(/^\s+/, '').replace(/\s+$/, '');
- };
- function parseRanges(ranges) {
- var parsedRanges = [], rangeParts = ranges.split(",");
- for (var i=0; i < rangeParts.length; i++) {
- parsedRanges.push(publicMethods.parseMediaRange(rangeParts[i]));
- };
- return parsedRanges;
- };
- var publicMethods = {
- parseMimeType : function(mimeType) {
- var fullType, typeParts, params = {}, parts = mimeType.split(';');
- for (var i=0; i < parts.length; i++) {
- var p = parts[i].split('=');
- if (p.length == 2) {
- params[strip(p[0])] = strip(p[1]);
- }
- };
- fullType = parts[0].replace(/^\s+/, '').replace(/\s+$/, '');
- if (fullType == '*') fullType = '*/*';
- typeParts = fullType.split('/');
- return [typeParts[0], typeParts[1], params];
- },
- parseMediaRange : function(range) {
- var q, parsedType = this.parseMimeType(range);
- if (!parsedType[2]['q']) {
- parsedType[2]['q'] = '1';
- } else {
- q = parseFloat(parsedType[2]['q']);
- if (isNaN(q)) {
- parsedType[2]['q'] = '1';
- } else if (q > 1 || q < 0) {
- parsedType[2]['q'] = '1';
- }
- }
- return parsedType;
- },
- fitnessAndQualityParsed : function(mimeType, parsedRanges) {
- var bestFitness = -1, bestFitQ = 0, target = this.parseMediaRange(mimeType);
- var targetType = target[0], targetSubtype = target[1], targetParams = target[2];
-
- for (var i=0; i < parsedRanges.length; i++) {
- var parsed = parsedRanges[i];
- var type = parsed[0], subtype = parsed[1], params = parsed[2];
- if ((type == targetType || type == "*" || targetType == "*") &&
- (subtype == targetSubtype || subtype == "*" || targetSubtype == "*")) {
- var matchCount = 0;
- for (param in targetParams) {
- if (param != 'q' && params[param] && params[param] == targetParams[param]) {
- matchCount += 1;
- }
- }
-
- var fitness = (type == targetType) ? 100 : 0;
- fitness += (subtype == targetSubtype) ? 10 : 0;
- fitness += matchCount;
-
- if (fitness > bestFitness) {
- bestFitness = fitness;
- bestFitQ = params["q"];
- }
- }
- };
- return [bestFitness, parseFloat(bestFitQ)];
- },
- qualityParsed : function(mimeType, parsedRanges) {
- return this.fitnessAndQualityParsed(mimeType, parsedRanges)[1];
- },
- quality : function(mimeType, ranges) {
- return this.qualityParsed(mimeType, parseRanges(ranges));
- },
-
- // Takes a list of supported mime-types and finds the best
- // match for all the media-ranges listed in header. The value of
- // header must be a string that conforms to the format of the
- // HTTP Accept: header. The value of 'supported' is a list of
- // mime-types.
- //
- // >>> bestMatch(['application/xbel+xml', 'text/xml'], 'text/*;q=0.5,*/*; q=0.1')
- // 'text/xml'
- bestMatch : function(supported, header) {
- var parsedHeader = parseRanges(header);
- var weighted = [];
- for (var i=0; i < supported.length; i++) {
- weighted.push([publicMethods.fitnessAndQualityParsed(supported[i], parsedHeader), supported[i]]);
- };
- weighted.sort();
- return weighted[weighted.length-1][0][1] ? weighted[weighted.length-1][1] : '';
- }
- };
- return publicMethods;
-})();
-
var respCT;
var respTail;
// this function provides a shortcut for managing responses by Accept header