// class Stage
// express中叫 layer, 这里则称为 stage（阶段），代表某个处理阶段
const concat = Array.prototype.concat;
function Stage(stages) {
  const befores = {};
  const afters = {};

  this.stages = this.actions = stages;
  this.stageNames = stages.map(stage => {
    const name = stage.name;

    befores[name] = [];
    afters[name] = [];

    return name;
  });
  this.befores = befores;
  this.afters = afters;
  this.props = {};
}

['before', 'after'].map(filterName => {
  Stage.prototype[filterName] = function filter(stageName, action) {
    const propname = `${filterName}s`;
    const filters = this[propname][stageName]; // this.befores[stagesName];

    if (! filters) {
      throw new Error(`Stage ${name} does not exist`);
    }

    filters.push(action);

    this.merge();

    return this;
  };

  return filterName;
});
Stage.prototype.merge = function merge() {
  // 合并所有的filter、stage
  this.actions = [];
  this.stages.map((stage, i) => {
    const name = this.stageNames[i];
    const befores = this.befores[name];
    const afters = this.afters[name];
    this.actions = concat.call(this.actions, befores, [stage], afters);

    return null;
  });
};
Stage.prototype.set = function set(name, value) {
  this.props[name] = value;
  return this;
};
Stage.prototype.get = function get(name) {
  return this.props[name];
};
Stage.prototype.handle = function handle(req, res, originNext) {
  const stage = this;
  const actions = this.actions;
  const startIndex = 0;

  // 执行指定名称的action
  function to(actionName) {
    const index = actions.findIndex(action => action.name === actionName);

    if (!~index) {
      throw new Error(`Action ${actionName} does not exist!`);
    }

    invokeAction(index);
  }

  // 特别注意，nextStage不应改变全局变量
  function nextStage(error) {
    // 已响应了客户端，则不再继续任何处理
    if (res.hasSent || res.headersSent) {
      return;
    }

    // res.forward会产生多个流程，需打断原流程
    if (this.pathname !== req.pathname) {
      return;
    }

    if (error) {
      originNext(error);
      return;
    }

    const prevIndex = req.stageIndex;
    const stageIndex = prevIndex + 1;
    const isLast = stageIndex === actions.length;

    if (isLast) {
      originNext();
      return;
    }

    req.stageIndex = stageIndex;

    invokeAction(stageIndex); // eslint-disable-line no-use-before-define
  }

  function invokeAction(stageIndex) {
    const next = nextStage.bind({
      'pathname': req.pathname, stageIndex
    });
    // 提供跳过stage处理流程的功能
    next.origin = originNext;
    next.to = to;

    return actions[stageIndex].call(stage, req, res, next);
  }

  // 添加扩展属性
  // 增加一个pathname自定义属性，用于取代req.path
  // pathname可实现forward功能
  req.pathname = req.path.replace(/\/+/g, '/'); // 纠正多个/的问题
  req.stageIndex = startIndex;
  req.stage = res.stage = stage;

  res.apiData = {};
  res.apiInfo = {};
  res.forward = pathname => {
    if (pathname === req.path) {
      const error = new Error('foward path cannot be the same as req.path!');
      originNext(error);
      return;
    }

    res.forwardSent = true;
    req.pathname = pathname;
    req.stageIndex = 0;
    // 让转发前的流程先执行并在下一个next时终止
    // 然后继续转发后的流程
    // 这样可以避免两个流程的变量污染
    process.nextTick(() => {
      invokeAction(req.stageIndex);
    });
  };

  invokeAction(startIndex);
};

module.exports = Stage;

@@ -1701,16 +1701,35 @@
 (index);
+%0A%0A    return index;
 %0A  %7D%0A%0A  
@@ -3021,36 +3021,8 @@
  %7D%0A%0A
-    res.forwardSent = true;%0A
     
@@ -3046,16 +3046,16 @@
 thname;%0A
+
     req.
@@ -3141,16 +3141,16 @@
 %E6%B5%81%E7%A8%8B%E7%9A%84%E5%8F%98%E9%87%8F%E6%B1%A1%E6%9F%93%0A
-
     proc
@@ -3166,24 +3166,192 @@
 ick(() =%3E %7B%0A
+      res.forwardSent = true;%0A      // %E5%85%81%E8%AE%B8forward%E5%88%B0%E4%B8%80%E4%B8%AA%E5%A4%96%E5%9F%9F%E5%90%8D%EF%BC%8C%E4%BD%86%E5%BF%85%E9%A1%BB%E6%98%AFhttp%E6%88%96https%E5%8D%8F%E8%AE%AE%E5%BC%80%E5%A4%B4%0A      if (pathname.startsWith('http')) %7B%0A        to('requestProxy');%0A        return;%0A      %7D%0A%0A
       invoke

update can forward other site