
// Express - Static - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)

var path = require('path'),
    posix = require('posix')
    
// --- InvalidPathError

InvalidPathError = ExpressError.extend({
  name: 'InvalidPathError',
  init: function(path) {
    this.message = "`" + path + "' is not a valid path"
  }
})  
  
// --- File

exports.File = Class({
  
  /**
   * Initialize with file _path_.
   *
   * @param  {string} path
   * @api public
   */
  
  init: function(path) {
    this.path = path
    if (path.indexOf('..') != -1) throw new InvalidPathError(path)
  },
  
  /**
   * Transfer static file to the given _request_.
   *
   *  - Ensures the file exists
   *  - Ensures the file is a regular file (not FIFO, Socket, etc)
   *  - Automatically assigns content type
   *
   * @param  {Request} request
   * @api public
   */
  
  send: function(request) {
    var file = this.path
    path.exists(file, function(exists){
      if (!exists) request.halt()
      posix.stat(file).addCallback(function(stats){
        if (!stats.isFile()) request.halt()
        posix.cat(file).addCallback(function(content){
          request.contentType(file)
          request.halt(200, content)
        })
      })
    })
  }
})

// Express - Static - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)

var path = require('path'),
    posix = require('posix')
    
// --- InvalidPathError

InvalidPathError = ExpressError.extend({
  name: 'InvalidPathError',
  init: function(path) {
    this.message = "`" + path + "' is not a valid path"
  }
})  
  
// --- File

exports.File = Class({
  
  /**
   * Initialize with file _path_.
   *
   * @param  {string} path
   * @api public
   */
  
  init: function(path) {
    this.path = path
    if (path.indexOf('..') != -1) throw new InvalidPathError(path)
  },
  
  /**
   * Transfer static file to the given _request_.
   *
   *  - Ensures the file exists
   *  - Ensures the file is a regular file (not FIFO, Socket, etc)
   *  - Automatically assigns content type
   *
   * @param  {Request} request
   * @api public
   */
  
  send: function(request) {
    var file = this.path
    path.exists(file, function(exists){
      if (!exists) request.halt()
      posix.stat(file).addCallback(function(stats){
        if (!stats.isFile()) request.halt()
        posix.cat(file, "binary").addCallback(function(content){
          request.contentType(file)
          request.status(200)
          request.response.body = content
          request.trigger('response')
          request.response.sendHeader(request.response.status, request.response.headers)
          request.response.sendBody(request.response.body, 'binary')
          request.response.finish()
        })
      })
    })
  }
})
Add support to StaticFile so that it works with non-textual files.
Add support to StaticFile so that it works with non-textual files.

Previously binary files were being interpreted as UTF8 encoded bytestreams
this isn't an ideal for pushing out static files such as images.

I've modified the StaticFile type so that it explicitly declares the encoding
as 'binary' and updated the mechanism used to push back to the client to
also be 'binary aware'.  I'm not happy with my approach as I've violated the
encapsulation of the logic that was previously in the request.respond method, but
without further direction on how that object is moving this was the easiest thing to do
in order to keep moving with my plan to have a full website ;)
