Пример #1
0
    _getContentType: function() {
        var res = this.get('res'),
            type = res.get('Content-Type');

        if (!type) {
            type = mime.lookup(res.mimeType);
            type = (~type.indexOf('/')) ? type : mime.lookup(type);
            type += '; charset=' + res.charset;
        }
        return type;
    },
Пример #2
0
Controller.prototype.respondWith = function(obj) {
  var keys = Object.keys(obj)
    , req = this.__req
    , res = this.__res
    , format = this.__req.params.format
    , format = format ? mime.lookup(format) : undefined;
    
  var op = obj.default;
  if (op) delete obj.default;

  // prefer format param, fallback to accept header
  var key = format ? utils.accepts(keys, format) : req.accepts(keys);
  
  if (key) {
    op = obj[key];
  }
  if (op === true) op = {};
  
  res.setHeader('Vary', 'Accept');
  
  if (typeof op == 'object') {
    op.format = op.format || key;
    this.render(op.template, op);
  } else if (typeof op == 'function') {
    op();
  } else {
    var err = new Error('Not Acceptable');
    err.status = 406;
    err.types = utils.normalizeTypes(keys);
    this.error(err);
  }
}
Пример #3
0
				it('should be set for .' + e + ' with query string', function(done) {
					helper.request()
						.get('/test.' + e + '?' + Math.random())
						.expect('Content-Type', new RegExp(
							express.mime.lookup(e).replace(/([\/\+])/g, '\\$1') + '(?:charset=UTF-8)?')
						)
						.expect(200, done);
				});
Пример #4
0
Controller.prototype.respondWith = function(obj) {
  var req = this.__req
    , res = this.__res
    , format = this.__req.params.format;
  format = format ? mime.lookup(format) : undefined;
  
  if (Array.isArray(obj) || typeof obj == 'string') {
    var arr = flatten([].slice.call(arguments))
      , o = {}, i, len;
    for (i = 0, len = arr.length; i < len; ++i) { o[arr[i]] = true; }
    obj = o;
  }
    
  var op = obj.default;
  if (op) { delete obj.default; }
  var keys = Object.keys(obj);

  // prefer format param, fallback to accept header
  var key = format ? utils.accepts(keys, format) : req.accepts(keys);
  var via = format ? undefined : utils.acceptedVia(keys, req.headers.accept);
  
  if (op && via && via.type == '*' && via.subtype == '*') {
    // use default format, if available and negotiated via */*
    key = undefined;
  } else if (via && via.type == '*' && via.subtype == '*') {
    // use first format, if no default and accepts anything
    key = keys[0];
  }
  
  if (key) {
    op = obj[key];
  }
  if (op === true) { op = {}; }
  else if (typeof op === 'string') { op = { format: op }; }
  
  var vary = this.__res.getHeader('Vary');
  if (!vary) {
    res.setHeader('Vary', 'Accept');
  } else {
    vary = vary.split(/ *, */);
    if (vary.indexOf('Accept') == -1) { vary.push('Accept'); }
    res.setHeader('Vary', vary.join(', '));
  }
  
  if (typeof op == 'object') {
    var template = op.template; delete op.template;
    op.format = op.format || key;
    if (key && key.indexOf('/') != -1) { op.mime = key; }
    this.render(template, op);
  } else if (typeof op == 'function') {
    op(this.localProperties());
  } else {
    var err = new Error('Not Acceptable');
    err.status = 406;
    err.types = utils.normalizeTypes(keys).map(function(o) { return o.value; });
    this.error(err);
  }
};
Пример #5
0
exports.normalizeTypes = function(types){
  var ret = [];

  for (var i = 0; i < types.length; ++i) {
    ret.push(~types[i].indexOf('/')
      ? types[i]
      : mime.lookup(types[i]));
  }

  return ret;
};
Пример #6
0
    return function(req, res, next) {
        var url = req.url,
            host = req.headers.host,
            ua = req.headers['user-agent'],
            cc = '',
            type;

        /**
         * private function to respond with the appropriate http status code.
         * @param {Number} code a valid http status code.
         */
        function respond(code) {
            var err = new Error(http.STATUS_CODES[code]);
            err.status = code;

            // early return for:
            // - redirects
            // - forbidden, prioritize 403 over 404
            if (/301|302|403/.test(err.status)) {
                res.statusCode = err.status;
                res.end(err.message);
            }
            else {
                next(err);
            }
        }

        // Block access to "hidden" directories or files whose names begin with a
        // period. This includes directories used by version control systems such as
        // Subversion or Git.

        if (RE_HIDDEN.test(url)) {
            return respond(403);
        }

        // Block access to backup and source files. These files may be left by some
        // text/html editors and pose a great security danger, when anyone can access
        // them.

        if (RE_SRCBAK.test(url)) {
            return respond(403);
        }

        /**
         * Suppress or force the "www." at the beginning of URLs
         */

        // The same content should never be available under two different URLs -
        // especially not with and without "www." at the beginning, since this can cause
        // SEO problems (duplicate content). That's why you should choose one of the
        // alternatives and redirect the other one.

        // By default option 1 (no "www.") is activated.
        // no-www.org/faq.php?q=class_b

        // If you'd prefer to use option 2, just comment out all option 1 lines
        // and uncomment option 2.

        // IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME!

        // ----------------------------------------------------------------------

        // Option 1:
        // Rewrite "www.example.com -> example.com".

        if (false === options.www && RE_WWW.test(host)) {
            res.setHeader('location', '//' + host.replace(RE_WWW, '') + url);
            return respond(301);
        }

        // ----------------------------------------------------------------------

        // Option 2:
        // Rewrite "example.com -> www.example.com".
        // Be aware that the following rule might not be a good idea if you use "real"
        // subdomains for certain parts of your website.

        if (true === options.www && !RE_WWW.test(host)) {
            res.setHeader('location', '//www.' + host.replace(RE_WWW, '') + url);
            return respond(301);
        }

        /**
         * Proper MIME type for all files
         */

            // early mime type sniffing

        type = express.mime.lookup(req.url);
        res.setHeader('Content-Type', type);

        /**
         * Better website experience for IE users
         */

        // Force the latest IE version, in various cases when it may fall back to IE7 mode
        //  github.com/rails/rails/commit/123eb25#commitcomment-118920
        // Use ChromeFrame if it's installed for a better experience for the poor IE folk

        if (RE_MSIE.test(ua) && 'text/html' == type) {
            res.setHeader('X-UA-Compatible', 'IE=Edge,chrome=1');
        }

        /**
         * Cross-domain AJAX requests
         */

        // Serve cross-domain Ajax requests, disabled by default.
        // enable-cors.org
        // code.google.com/p/html5security/wiki/CrossOriginRequestSecurity

        if (options.cors) {
            res.setHeader('Access-Control-Allow-Origin', '*');
        }

        /**
         * CORS-enabled images (@crossorigin)
         */

        // Send CORS headers if browsers request them; enabled by default for images.
        // developer.mozilla.org/en/CORS_Enabled_Image
        // blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html
        // hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/
        // wiki.mozilla.org/Security/Reviews/crossoriginAttribute

        if (RE_MIME_IMAGE.test(type)) {
            res.setHeader('Access-Control-Allow-Origin', '*');
        }

        /**
         * Webfont access
         */

        // Allow access from all domains for webfonts.
        // Alternatively you could only whitelist your
        // subdomains like "subdomain.example.com".

        if (RE_MIME_FONT.test(url)) {
            res.setHeader('Access-Control-Allow-Origin', '*');
        }

        /**
         * Allow concatenation from within specific js and css files
         */

        // e.g. Inside of script.combined.js you could have
        //   <!--#include file="libs/jquery-1.5.0.min.js" -->
        //   <!--#include file="plugins/jquery.idletimer.js" -->
        // and they would be included into this single file.

        // TODO

        /**
         * Expires headers (for better cache control)
         */

        // These are pretty far-future expires headers.
        // They assume you control versioning with filename-based cache busting
        // Additionally, consider that outdated proxies may miscache
        //   www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/

        // If you don't use filenames to version, lower the CSS and JS to something like
        // "access plus 1 week".

        // note: we don't use express.static maxAge feature because it does not allow fine tune

        // Perhaps better to whitelist expires rules? Perhaps.

        // cache.appcache needs re-requests in FF 3.6 (thanks Remy ~Introducing HTML5)
        // Your document html
        // Data
        if (RE_MIME_DATA.test(type)) {
            cc = 'public,max-age=0';
        }
        // Feed
        else if (RE_MIME_FEED.test(type)) {
            cc = 'public,max-age=' + ONE_HOUR;
        }
        // Favicon (cannot be renamed)
        else if (RE_MIME_FAVICON.test(type)) {
            cc = 'public,max-age=' + ONE_WEEK;
        }
        // Media: images, video, audio
        // HTC files  (css3pie)
        // Webfonts
        else if (RE_MIME_MEDIA.test(type)) {
            cc = 'public,max-age=' + ONE_MONTH;
        }
        // CSS and JavaScript
        else if (RE_MIME_CSSJS.test(type)) {
            cc = 'public,max-age=' + ONE_YEAR;
        }
        // Misc
        else {
            cc = 'public,max-age=' + ONE_MONTH;
        }

        /**
         * Prevent mobile network providers from modifying your site
         */

            // The following header prevents modification of your code over 3G on some
            // European providers.
            // This is the official 'bypass' suggested by O2 in the UK.

        cc += (cc ? ',' : '') + 'no-transform';
        // hack: send does not compute ETag if header is already set, this save us ETag generation
        res.setHeader('cache-control', '');

        /**
         * ETag removal
         */

            // Since we're sending far-future expires, we don't need ETags for
            // static content.
            //   developer.yahoo.com/performance/rules.html#etags

            // hack: send does not compute ETag if header is already set, this save us ETag generation
        res.setHeader('etag', '');

        // handle headers correctly after express.static

        res.on('header', function() {
            res.setHeader('cache-control', cc);
            // remote empty etag header
            res.removeHeader('etag');
        });

        /**
         * Stop screen flicker in IE on CSS rollovers
         */

        // The following directives stop screen flicker in IE on CSS rollovers - in
        // combination with the "ExpiresByType" rules for images (see above).

        // TODO

        /**
         * Set Keep-Alive Header
         */

            // Keep-Alive allows the server to send multiple requests through one
            // TCP-expression. Be aware of possible disadvantages of this setting. Turn on
            // if you serve a lot of static content.

        res.setHeader('connection', 'keep-alive');

        /**
         * Cookie setting from iframes
         */

        // Allow cookies to be set from iframes (for IE only)
        // If needed, specify a path or regex in the Location directive.

        // TODO

        /**
         * Built-in filename-based cache busting
         */

            // If you're not using the build script to manage your filename version revving,
            // you might want to consider enabling this, which will route requests for
            // /css/style.20110203.css to /css/style.css

            // To understand why this is important and a better idea than all.css?v1231,
            // read: github.com/h5bp/html5-boilerplate/wiki/cachebusting

        req.url = req.url.replace(/^(.+)\.(\d+)\.(js|css|png|jpg|gif)$/, '$1.$3');

        /**
         * A little more security
         */

        // do we want to advertise what kind of server we're running?

        if ('express' == options.server) {
            res.removeHeader('X-Powered-By');
        }

        next();
    };
Пример #7
0
 it('should be set for .' + e, function(done) {
     helper.request()
         .get('/test.' + e)
         .expect('Content-Type', express.mime.lookup(e))
         .expect(200, done);
 });
Пример #8
0
const HTML = 'html htm'.split(' ');
const IMAGE = 'bmp gif jpeg jpg jpe png svg svgz tiff tif ico'.split(' ');
const ICON = 'ico'.split(' ');
const VIDEO = 'ogv mp4 m4v f4v f4p webm flv'.split(' ');
const AUDIO = 'oga ogg m4a f4a f4b'.split(' ');
const FONT = 'ttf ttc otf eot woff'.split(' ');
const RSS = 'rss atom'.split(' ');
const MISC = 'txt crx oex xpi safariextz webapp vcf swf vtt'.split(' ');

const FEED = RSS;
const MEDIA = IMAGE.concat(VIDEO.concat(AUDIO));
const DATA = 'appcache manifest html htm xml rdf json';
const ALL = [].concat(HTML, IMAGE, ICON, VIDEO, AUDIO, FONT, RSS, 'js jsonp css'.split(' '));

express.mime.load(path.join(__dirname, '..', 'lib', 'h5bp.types'));

describe('h5bp', function() {
    describe('with express/connect', function() {
        before(function() {
            helper.stop();
            helper.create();
            helper.start();
        });

        describe('proper MIME type for all files', function() {
            ALL.forEach(function(e) {
                it('should be set for .' + e, function(done) {
                    helper.request()
                        .get('/test.' + e)
                        .expect('Content-Type', express.mime.lookup(e))
Пример #9
0
exports.normalizeType = function(type){
  return ~type.indexOf('/') ? type : mime.lookup(type);
};
Пример #10
0
exports.extensionizeType = function(type){
  return type.indexOf('/') != -1 ? mime.extension(type) : type;
};