Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial version

  • Loading branch information...
commit 0924c6cd60d6c66e4daa313e2ddd8ed8ed42259e 0 parents
@niclashoyer authored
Showing with 300 additions and 0 deletions.
  1. +38 −0 Cakefile
  2. +22 −0 LICENCE
  3. +117 −0 lib/Accept.js
  4. +18 −0 package.json
  5. +105 −0 src/Accept.coffee
38 Cakefile
@@ -0,0 +1,38 @@
+###
+Copyright (c) 2012 Niclas Hoyer
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+###
+
+util = require 'util'
+{exec} = require 'child_process'
+
+task 'build', 'Build src files', ->
+ exec "coffee -bc -o lib src", (err, stdout, stderr) ->
+ util.log err if err
+ util.log "compilation finished"
+
+task 'docs', 'Generate documentation with docco', ->
+ exec "docco src/*.coffee", (err, stdout, stderr) ->
+ util.log err if err
+ util.log "docs generated"
+
22 LICENCE
@@ -0,0 +1,22 @@
+Copyright (c) 2011 Niclas Hoyer
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
117 lib/Accept.js
@@ -0,0 +1,117 @@
+var middleware, parseAccept, parseHeaderField, parseMediaType, parseParams, parseStandard, sortMediaType, sortQuality, trimsplit;
+
+trimsplit = function(str, delimiter) {
+ var strs, _i, _len, _results;
+ strs = str.split(delimiter);
+ _results = [];
+ for (_i = 0, _len = strs.length; _i < _len; _i++) {
+ str = strs[_i];
+ _results.push(str.trim());
+ }
+ return _results;
+};
+
+parseParams = function(str) {
+ var param, paramToObj, params, paramstrs, q, strs, _i, _len;
+ paramToObj = function(str, obj) {
+ var param;
+ param = trimsplit(str, '=');
+ return obj[param[0]] = param[1];
+ };
+ strs = trimsplit(str, ';');
+ paramstrs = strs.slice(1);
+ params = {};
+ for (_i = 0, _len = paramstrs.length; _i < _len; _i++) {
+ param = paramstrs[_i];
+ paramToObj(param, params);
+ }
+ if (params.q != null) {
+ q = Number(params.q);
+ } else {
+ q = 1;
+ }
+ return {
+ value: strs[0],
+ params: params,
+ quality: q
+ };
+};
+
+parseMediaType = function(obj) {
+ var mediarange;
+ mediarange = trimsplit(obj.value, '/');
+ return {
+ type: mediarange[0],
+ subtype: mediarange[1],
+ params: obj.params,
+ mediarange: obj.value,
+ quality: obj.quality
+ };
+};
+
+parseStandard = function(obj) {
+ return obj.value;
+};
+
+parseHeaderField = function(str, map, sort) {
+ var obj, objects, str, strs;
+ if (!(str != null)) return;
+ strs = trimsplit(str, ',');
+ objects = (function() {
+ var _i, _len, _results;
+ _results = [];
+ for (_i = 0, _len = strs.length; _i < _len; _i++) {
+ str = strs[_i];
+ _results.push(parseParams(str));
+ }
+ return _results;
+ })();
+ map = map != null ? map : parseStandard;
+ sort = sort != null ? sort : sortQuality;
+ objects = (function() {
+ var _i, _len, _results;
+ _results = [];
+ for (_i = 0, _len = objects.length; _i < _len; _i++) {
+ obj = objects[_i];
+ _results.push(map(obj));
+ }
+ return _results;
+ })();
+ return objects.sort(sort);
+};
+
+parseAccept = function(str) {
+ str = str != null ? str : '*/*';
+ return parseHeaderField(str, parseMediaType, sortMediaType);
+};
+
+sortQuality = function(a, b) {
+ if (a.quality < b.quality) return 1;
+ if (a.quality > b.quality) return -1;
+};
+
+sortMediaType = function(a, b) {
+ if (a.quality < b.quality) return 1;
+ if (a.quality > b.quality) return -1;
+ if (a.type === '*' && b.type !== '*') return 1;
+ if (a.type !== '*' && b.type === '*') return -1;
+ if (a.subtype === '*' && b.subtype !== '*') return 1;
+ if (a.subtype !== '*' && b.subtype === '*') return -1;
+ if (Object.keys(a.params).length < Object.keys(b.params).length) return 1;
+ if (Object.keys(a.params).length > Object.keys(b.params).length) return -1;
+ return 0;
+};
+
+middleware = function(req, res, next) {
+ req.types = parseAccept(req.headers.accept);
+ req.charsets = parseHeaderField(req.headers['accept-charsets']);
+ req.encodings = parseHeaderField(req.headers['accept-encodings']);
+ req.languages = parseHeaderField(req.headers['accept-language']);
+ req.ranges = parseHeaderField(req.headers['accept-ranges']);
+ return next();
+};
+
+module.exports = {
+ accept: middleware,
+ parser: parseHeaderField
+};
18 package.json
@@ -0,0 +1,18 @@
+{
+ "name": "http-accept",
+ "version": "0.1.0",
+ "description": "Connect compatible middleware that parses HTTP Accept header fields",
+ "author": {
+ "name": "Niclas Hoyer",
+ "email": "https://github.com/niclashoyer"
+ },
+ "files": [
+ "lib/"
+ ],
+ "main": "lib/Accept.js",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/niclashoyer/accept-http.git"
+ },
+ "licence": "MIT"
+}
105 src/Accept.coffee
@@ -0,0 +1,105 @@
+# Accept
+
+# ## Util Functions
+# Split a string and trim its splitted pieces.
+trimsplit = (str, delimiter) ->
+ strs = str.split delimiter
+ str.trim() for str in strs
+
+# ## Parse Functions
+
+# Parse parameters including quality `q` from `Accept` header field.
+parseParams = (str) ->
+
+ paramToObj = (str,obj) ->
+ param = trimsplit str, '='
+ obj[param[0]] = param[1]
+
+ strs = trimsplit str, ';'
+ paramstrs = strs.slice 1
+
+ params = {}
+ paramToObj param, params for param in paramstrs
+
+ if params.q?
+ q = Number params.q
+ else
+ q = 1
+
+ value: strs[0], params: params, quality: q
+
+# Parse mediatype from object.
+parseMediaType = (obj) ->
+ mediarange = trimsplit obj.value, '/'
+ type: mediarange[0]
+ subtype: mediarange[1]
+ params: obj.params
+ mediarange: obj.value
+ quality: obj.quality
+
+# Just return value from object.
+parseStandard = (obj) ->
+ obj.value
+
+# Parse custom `Accept` header field.
+parseHeaderField = (str, map, sort) ->
+
+ if not str?
+ return
+
+ strs = trimsplit str, ','
+ objects = (parseParams str for str in strs)
+
+ map = map ? parseStandard
+ sort = sort ? sortQuality
+
+ objects = (map obj for obj in objects)
+
+ objects.sort sort
+
+# Parse `Accept` header field.
+parseAccept = (str) ->
+ str = str ? '*/*'
+ parseHeaderField str, parseMediaType, sortMediaType
+
+# ## Sort functions
+
+# Sort objects by quality.
+sortQuality = (a, b) ->
+ if a.quality < b.quality
+ return 1
+ if a.quality > b.quality
+ return -1
+
+# Sort objects by media type and quality.
+sortMediaType = (a, b) ->
+ if a.quality < b.quality
+ return 1
+ if a.quality > b.quality
+ return -1
+ if a.type is '*' and b.type isnt '*'
+ return 1
+ if a.type isnt '*' and b.type is '*'
+ return -1
+ if a.subtype is '*' and b.subtype isnt '*'
+ return 1
+ if a.subtype isnt '*' and b.subtype is '*'
+ return -1
+ if Object.keys(a.params).length < Object.keys(b.params).length
+ return 1
+ if Object.keys(a.params).length > Object.keys(b.params).length
+ return -1
+ 0
+
+# Build middleware with parsers for several accept header fields.
+middleware = (req, res, next) ->
+ req.types = parseAccept req.headers.accept
+ req.charsets = parseHeaderField req.headers['accept-charsets']
+ req.encodings = parseHeaderField req.headers['accept-encodings']
+ req.languages = parseHeaderField req.headers['accept-language']
+ req.ranges = parseHeaderField req.headers['accept-ranges']
+ next()
+
+module.exports =
+ accept: middleware
+ parser: parseHeaderField
Please sign in to comment.
Something went wrong with that request. Please try again.