waffle
Version:
シンプルなWEBアプリケーションフレームワークです。(ALL YOUR NODE ARE BELONG TO US)
287 lines (251 loc) • 7.46 kB
JavaScript
/*
* Copyright 2012 Katsunori Koyanagi
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
/**
* @overview リクエストとレスポンスを対とした、クライアントとの対話を管理する機能を提供します。
*/
"use strict";
var parse = require("url").parse;
var util = require("../utils/Util");
var log = require("../utils/Log");
var EventEmitter = require("events").EventEmitter;
var id = 0;
/**
* コンテキストのクラスです。
* <p>
* クライアントからのリクエストとレスポンスを表現します。直接Node.jsがサポートするリクエストとレスポンスを操作するのも可能です。 その場合は{@link Context#req}と{@link Context#req}を参照してください。
* </p>
* <p>
* このクラスはEventEmitterを継承し、"close"イベントをサポートします。リスナにはタイムアウトの場合はtrueであるフラグが渡されます。
* </p>
*
* @property {Object} req リクエスト
* @property {Object} res レスポンス
* @property {Object} app アプリケーション
* @property {String} id リクエストID
* @property {Object} url URL情報
* @class コンテキストのクラスです。
* @constructor
*/
var Context = function(req, res, app) {
EventEmitter.call(this);
this.url = parse(req.url);
this.req = req;
this.res = res;
this.app = app;
this.id = "req_" + util.generateUID();
res.setHeader("X-Powered-By", "Waffle");
};
require("util").inherits(Context, EventEmitter);
//
// コンテキストクラスのプロトタイプ定義
//
/**
* リクエストボディに含まれるポストされたパラメータを示す文字列です。この値はフィルタよって設定されます。
*
* @type String
* @see Filters#postParameter
*/
Context.prototype.postParameter = null;
/**
* セッションです。この値はフィルタよって設定されます。
*
* @type SessionObject
* @see Filters#session
*/
Context.prototype.session = null;
/**
* サードパティモジュールの<a href="https://github.com/jed/cookies">cookies</a>のインスタンスです。
* この値はフィルタによって設定されます。
*
* @type Object
* @see Filters#cookies
*/
Context.prototype.cookies = null;
/**
* パラメータを取得して返します。
* <p>
* リクエストボディを取得済みであれば、自動的にリクエストボディを含めてパラメータのパースが行われます。
* </p>
*
* @param {Boolean}
* phpStyle PHPスタイルでパースする場合はtrue、省略時はfalseとみなされる
* @return {Object} パラメータ
*/
Context.prototype.getParameters = function(phpStyle) {
if (this.__parameters__) {
return this.__parameters__;
}
var query = this.url.query || "";
if (this.postParameter) {
if (query) {
query += "&";
}
query += this.postParameter;
}
var params;
if (phpStyle) {
params = util.parsePHPStyleParameters(query);
} else {
params = util.parseServletStyleParameters(query);
}
this.__parameters__ = params;
return params;
};
/**
* リクエストヘッダのAccept-Languagesに基づいて、言語を配列で返します。
*
* @return {Array} 言語の配列、存在しない場合は空の配列
*/
Context.prototype.getLanguages = function() {
var lang = this.req.headers["accept-language"];
if (!lang) {
return [];
}
var index = lang.indexOf(";");
if (index > -1) {
lang = lang.substr(0, index);
}
if (lang.length === 0) {
return [];
}
return lang.split(",");
};
/**
* ルータによって正規表現によるパスのマッチングを行った結果です。
*
* @type Array
*/
Context.prototype.matches = null;
/**
* コントローラ等で設定されたエラーです。
*
* @type String|Error
* @see Context#error
*/
Context.prototype.errorInfo = null;
/**
* エラーページへのディスパッチを行います。
*
* @param {Number}
* code エラーコード
* @param {Error|String}
* error エラー(省略可)
*/
Context.prototype.error = function(code, error) {
if (this.__callback__ == null) {
return;
}
var callback = this.__callback__;
this.__callback__ = null;
callback("error", null, null, code, error);
};
/**
* 指定のパスの処理を行うコントローラへのディスパッチを行います。
*
* @param {String}
* path パス
*/
Context.prototype.dispatch = function(path) {
if (this.__callback__ == null) {
return;
}
var callback = this.__callback__;
this.__callback__ = null;
callback("dispatch", null, path);
};
/**
* 指定のURLへのリダイレクトを行います。
*
* @param {String}
* url URL
*/
Context.prototype.redirect = function(url) {
if (this.__callback__ == null) {
return;
}
var callback = this.__callback__;
this.__callback__ = null;
callback("redirect", null, url);
};
/**
* 指定のビューのレンダリングを行います。
*
* @param {String}
* view ビューを示す文字列
* @param {Object}
* data ビューで使用するデータ
*/
Context.prototype.render = function(view, data) {
if (this.__callback__ == null) {
return;
}
var callback = this.__callback__;
this.__callback__ = null;
callback("render", data, view);
};
/**
* 何もせずにコントローラの処理を終了します。
*/
Context.prototype.complete = function() {
if (this.__callback__ == null) {
return;
}
var callback = this.__callback__;
this.__callback__ = null;
callback("complete");
};
/**
* コネクションのタイムアウトのミリ秒の時間を設定します。
*
* @param {Number}
* timeout タイムアウトまでの時間、不正な値、0以下の値の場合は120000(2分)
*/
Context.prototype.setConnectionTimeout = function(timeout) {
if (timeout * 0.0 !== 0.0) {
timeout = parseInt(timeout);
}
if (timeout * 0.0 !== 0.0) {
timeout = 0;
}
if (timeout <= 0) {
timeout = 120000;
}
this.req.socket.setTimeout(timeout);
};
/**
* @private
*/
Context.prototype.__start__ = function(timeout) {
this.setConnectionTimeout(timeout);
var self = this;
this.__onTimeout__ = function() {
self.req.socket.removeListener("timeout", self.__onTimeout__);
log.error("request timeout");
self.emit("close", true);
};
this.req.socket.on("timeout", this.__onTimeout__);
};
/**
* @private
*/
Context.prototype.__close__ = function() {
this.req.socket.removeListener("timeout", this.__onTimeout__);
this.emit("close", false);
};
//
// expose
//
module.exports = Context;