示例#1
0
    return function (src, filename, done) {
        const relativePath = path.join(outDir, filename);
        const modulePath = pathResolve(cwd, relativePath);
        const moduleSourcePath = pathResolve(cwd, relativePath.replace(outDir, sourceDir));
        const moduleBinPath = pathResolve(cwd, relativePath.replace(outDir, binDir));

        const pathOptions = {
            moduleBinPath,
            modulePath,
            moduleSourcePath,
            relativePath
        };

        const origin = generalSettings.staticUrl;

        return new Promise((resolveImportable, rejectImportable) => {
            createImportableModule({
                origin,

                pathOptions,

                logger,
                logLevel: 0,

                temporaryCache: false,
                binaryToModule,

                root: cwd
            }, resolveImportable, rejectImportable);
        })
            .then(() => done && done())
            .catch((err) => done && done(err));
    };
示例#2
0
    return function *serve(next){

        if (this.method == 'HEAD' || this.method == 'GET') {

            var path = this.path.substr(parse(this.path).root.length);

            try {
                path = decodeURIComponent(path);
            } catch (ex) {
                // 无效路径
                this.status = 404;
                this.body = "could not decode path";
                return;
            }

            if (options.index && '/' == this.path[this.path.length - 1])
                path += options.index;

            path = resolvePath(normalizedRoot, path);

            if (!options.hidden && isHidden(root, path))
                return;

            if (yield send(this, path, options)) return;
        }
        yield* next;
    };
示例#3
0
  // utility
  function* send(ctx, path) {
    var req = ctx.request
    var res = ctx.response

    path = path || req.path.slice(1) || ''

    // index file support
    var directory = path === '' || path.slice(-1) === '/'
    if (index && directory) path += 'index.html'

    // regular paths can not be absolute
    path = resolve(root, path)

    // hidden file support
    if (!hidden && leadingDot(path)) return

    var file = yield* get(path)
    if (!file) return // 404

    // proper method handling
    var method = req.method
    switch (method) {
      case 'HEAD':
      case 'GET':
        break // continue
      case 'OPTIONS':
        res.set('Allow', methods)
        res.status = 204
        return file
      default:
        res.set('Allow', methods)
        res.status = 405
        return file
    }

    res.status = 200
    res.etag = file.etag
    res.lastModified = file.stats.mtime
    res.type = file.type
    if (cachecontrol) res.set('Cache-Control', cachecontrol)

    if (req.fresh) {
      res.status = 304
      return file
    }

    if (method === 'HEAD') return file

    if (file.compress && req.acceptsEncodings('gzip', 'identity') === 'gzip') {
      res.set('Content-Encoding', 'gzip')
      res.length = file.compress.stats.size
      res.body = fs.createReadStream(file.compress.path)
    } else {
      res.set('Content-Encoding', 'identity')
      res.length = file.stats.size
      res.body = fs.createReadStream(path)
    }

    return file
  }
示例#4
0
 .then(function( stats ){
   if (stats.isDirectory() && $preprocessor.index) {
     fpath = resolvePath( fpath , $preprocessor.index );
     return getStats();
   }
   return stats;
 });
示例#5
0
 return function middleware( req , res , next ){
   var pathname = url.parse( req.url ).pathname;
   var fpath = resolvePath( $preprocessor.root , pathname.substr( 1 ));
   Q.fcall(function(){
     if (req.method != 'GET') {
       return Q.reject();
     }
   })
   .then(function(){
     return Q.fcall(function getStats(){
       return Q.promise(function( resolve , reject ){
         fs.stat( fpath , function( err , stats ){
           return err ? reject() : resolve( stats );
         });
       })
       .then(function( stats ){
         if (stats.isDirectory() && $preprocessor.index) {
           fpath = resolvePath( fpath , $preprocessor.index );
           return getStats();
         }
         return stats;
       });
     })
     .then(function( stats ){
       if (stats.isFile() && $preprocessor._accepts( fpath )) {
         return Q.promise(function( resolve , reject ){
           fs.readFile( fpath , 'utf-8' , function( err , content ){
             return err ? reject( err ) : resolve( content );
           });
         });
       }
       return Q.reject();
     });
   })
   .then(function( content ){
     var $req = _.extend(Object.create( req ), {
       root: fpath.substr( 0 , fpath.indexOf( pathname )),
       pathname: fpath.substr(fpath.indexOf( pathname )),
       mime: mime.lookup( fpath )
     });
     return Q.resolve().then(function(){
       return $preprocessor.engine( content , $req );
     })
     .then(function( processed ){
       res.setHeader( 'Content-Type' , $req.mime );
       res.setHeader( 'Content-Length' , Buffer.byteLength( processed ));
       return processed;
     });
   })
   .then(function( content ){
     res.end( content );
   })
   .fail( next );
 };
示例#6
0
文件: index.js 项目: XeCycle/send
  return function *(){
    var trailingSlash = '/' == path[path.length - 1];
    var encoding = this.acceptsEncodings('gzip', 'deflate', 'identity');

    // normalize path
    path = decode(path);

    if (-1 == path) return ctx.throw('failed to decode', 400);

    // index file support
    if (index && trailingSlash) path += index;

    path = resolvePath(root, path);

    // hidden file support, ignore
    if (!hidden && leadingDot(path)) return;

    // serve gzipped file when possible
    if (encoding === 'gzip' && gzip && (yield fs.exists(path + '.gz'))) {
      path = path + '.gz';
      ctx.set('Content-Encoding', 'gzip');
      ctx.res.removeHeader('Content-Length');
    }

    // stat
    try {
      var stats = yield fs.stat(path);
      if (stats.isDirectory()) return;
    } catch (err) {
      var notfound = ['ENOENT', 'ENAMETOOLONG', 'ENOTDIR'];
      if (~notfound.indexOf(err.code)) return;
      err.status = 500;
      throw err;
    }

    ctx.set('Last-Modified', stats.mtime.toUTCString());
    ctx.set('Cache-Control', 'max-age=' + (maxage / 1000 | 0));

    // respond 304 if mtime not newer
    var clientMtime = new Date(ctx.request.get('If-Modified-Since'));
    if (clientMtime.getTime() === clientMtime.getTime()) { // not NaN
      if (!(stats.mtime > clientMtime)) {
        ctx.response.status = 304;
        return path;
      }
    }

    // stream
    ctx.set('Content-Length', stats.size);
    ctx.type = type(path);
    ctx.body = fs.createReadStream(path);

    return path;
  }
示例#7
0
  function* push(ctx, path, opts) {
    assert(path, 'you must define a path!')
    if (!ctx.res.isSpdy) return

    opts = opts || {}

    assert(path[0] !== '/', 'you can only push relative paths')
    var uri = path // original path

    // index file support
    var directory = path === '' || path.slice(-1) === '/'
    if (index && directory) path += 'index.html'

    // regular paths can not be absolute
    path = resolve(root, path)

    var file = yield* get(path)
    assert(file, 'can not push file: ' + uri)

    var options = {
      path: '/' + uri,
      priority: opts.priority,
    }

    var headers = options.headers = {
      'content-type': file.type,
      etag: file.etag,
      'last-modified': file.stats.mtime.toUTCString(),
    }

    if (cachecontrol) headers['cache-control'] = cachecontrol

    if (file.compress) {
      headers['content-encoding'] = 'gzip'
      headers['content-length'] = file.compress.stats.size
      options.filename = file.compress.path
    } else {
      headers['content-encoding'] = 'identity'
      headers['content-length'] = file.stats.size
      options.filename = path
    }

    spdy(ctx.res)
      .push(options)
      .send()
      .catch(ctx.onerror)

    return file
  }
示例#8
0
async function send (ctx, path, opts = {}) {
  assert(ctx, 'koa context required')
  assert(path, 'pathname required')

  // options
  debug('send "%s" %j', path, opts)
  const root = opts.root ? normalize(resolve(opts.root)) : ''
  const trailingSlash = path[path.length - 1] === '/'
  path = path.substr(parse(path).root.length)
  const index = opts.index
  const maxage = opts.maxage || opts.maxAge || 0
  const immutable = opts.immutable || false
  const hidden = opts.hidden || false
  const format = opts.format !== false
  const extensions = Array.isArray(opts.extensions) ? opts.extensions : false
  const brotli = opts.brotli !== false
  const gzip = opts.gzip !== false
  const setHeaders = opts.setHeaders

  if (setHeaders && typeof setHeaders !== 'function') {
    throw new TypeError('option setHeaders must be function')
  }

  // normalize path
  path = decode(path)

  if (path === -1) return ctx.throw(400, 'failed to decode')

  // index file support
  if (index && trailingSlash) path += index

  path = resolvePath(root, path)

  // hidden file support, ignore
  if (!hidden && isHidden(root, path)) return

  let encodingExt = ''
  // serve brotli file when possible otherwise gzipped file when possible
  if (ctx.acceptsEncodings('br', 'identity') === 'br' && brotli && (await fs.exists(path + '.br'))) {
    path = path + '.br'
    ctx.set('Content-Encoding', 'br')
    ctx.res.removeHeader('Content-Length')
    encodingExt = '.br'
  } else if (ctx.acceptsEncodings('gzip', 'identity') === 'gzip' && gzip && (await fs.exists(path + '.gz'))) {
    path = path + '.gz'
    ctx.set('Content-Encoding', 'gzip')
    ctx.res.removeHeader('Content-Length')
    encodingExt = '.gz'
  }

  if (extensions && !/\.[^/]*$/.exec(path)) {
    const list = [].concat(extensions)
    for (let i = 0; i < list.length; i++) {
      let ext = list[i]
      if (typeof ext !== 'string') {
        throw new TypeError('option extensions must be array of strings or false')
      }
      if (!/^\./.exec(ext)) ext = '.' + ext
      if (await fs.exists(path + ext)) {
        path = path + ext
        break
      }
    }
  }

  // stat
  let stats
  try {
    stats = await fs.stat(path)

    // Format the path to serve static file servers
    // and not require a trailing slash for directories,
    // so that you can do both `/directory` and `/directory/`
    if (stats.isDirectory()) {
      if (format && index) {
        path += '/' + index
        stats = await fs.stat(path)
      } else {
        return
      }
    }
  } catch (err) {
    const notfound = ['ENOENT', 'ENAMETOOLONG', 'ENOTDIR']
    if (notfound.includes(err.code)) {
      throw createError(404, err)
    }
    err.status = 500
    throw err
  }

  if (setHeaders) setHeaders(ctx.res, path, stats)

  // stream
  ctx.set('Content-Length', stats.size)
  if (!ctx.response.get('Last-Modified')) ctx.set('Last-Modified', stats.mtime.toUTCString())
  if (!ctx.response.get('Cache-Control')) {
    const directives = ['max-age=' + (maxage / 1000 | 0)]
    if (immutable) {
      directives.push('immutable')
    }
    ctx.set('Cache-Control', directives.join(','))
  }
  if (!ctx.type) ctx.type = type(path, encodingExt)
  ctx.body = fs.createReadStream(path)

  return path
}