nxkit
Version:
This is a collection of tools, independent of any other libraries
319 lines (318 loc) • 10.4 kB
JavaScript
"use strict";
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2015, xuewen.chu
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of xuewen.chu nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL xuewen.chu BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
Object.defineProperty(exports, "__esModule", { value: true });
const cookie_1 = require("./cookie");
const service_1 = require("./service");
const static_service_1 = require("./static_service");
const session_1 = require("./session");
const zlib = require("zlib");
const incoming_form_1 = require("./incoming_form");
const errno_1 = require("./errno");
var StaticService_action = static_service_1.StaticService.prototype.action;
/**
* @private
*/
function returnJSON(self, data) {
var type = self.server.getMime(self.jsonpCallback ? 'js' : 'json');
try {
var rev = JSON.stringify(data);
}
catch (err) {
self.returnError(err);
return;
}
if (self.jsonpCallback) {
data = self.jsonpCallback + '(' + rev + ')';
}
return self.returnString(rev, type);
}
/**
* @class HttpService
* @bases staticService::StaticService
*/
class HttpService extends static_service_1.StaticService {
/**
* @constructor
* @arg req {http.IncomingMessage}
* @arg res {http.ServerResponse}
*/
constructor(req, res) {
super(req, res);
/**
* post form
* @type {IncomingForm}
*/
this.form = null;
this.jsonpCallback = this.params.callback || '';
this.data = {};
}
/**
* @func markReturnInvalid() mark action return invalid
*/
markReturnInvalid() {
this.markCompleteResponse();
}
/**
* site cookie
* @type {Cookie}
*/
get cookie() {
if (!this.m_cookie)
this.m_cookie = new cookie_1.Cookie(this.request, this.response);
return this.m_cookie;
}
get session() {
if (!this.m_session)
this.m_session = new session_1.Session(this);
return this.m_session;
}
/**
* @overwrite
*/
async action(info) {
var self = this;
var action = info.action;
if (self.request.method == 'OPTIONS') {
if (self.server.allowOrigin == '*') {
var access_headers = '';
//'Content-Type,Access-Control-Allow-Headers,Authorization,X-Requested-With';
var access_headers_req = self.request.headers['access-control-request-headers'];
if (access_headers_req) {
access_headers += access_headers_req;
}
self.response.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');
self.response.setHeader('Access-Control-Allow-Headers', access_headers);
}
self.setDefaultHeader();
self.response.writeHead(200);
self.response.end();
return;
}
/*
* Note:
* The network fault tolerance,
* the browser will cause strange the second request,
* this error only occurs on the server restart,
* the BUG caused by the request can not respond to
*/
//Filter private function
if (/^_/.test(action)) {
return StaticService_action.call(this, info);
}
var fn = this[action];
if (action in HttpService.prototype) {
return self.returnError(Error.new(errno_1.default.ERR_FORBIDDEN_ACCESS));
}
if (!fn || typeof fn != 'function') {
return StaticService_action.call(this, info);
}
var ok = async function () {
var auth = false;
try {
auth = await self.auth(info);
}
catch (e) {
console.error(e);
}
if (!auth) {
self.returnError(Error.new(errno_1.default.ERR_ILLEGAL_ACCESS));
return;
}
var { service, action, ..._info } = info;
var data = Object.assign({}, self.params, self.data, _info);
var err, r;
try {
r = await self[action](data);
}
catch (e) {
err = e;
}
if (!self.isCompleteResponse) {
if (err) {
if (self.server.printLog) {
console.error(err);
}
self.returnError(err);
}
else {
self.returnJSON(r);
}
}
};
if (this.request.method == 'POST') {
var form = this.form = new incoming_form_1.IncomingForm(this);
try {
var accept = this.hasAcceptFilestream(info);
if (accept instanceof Promise) {
this.request.pause();
form.isUpload = await accept;
this.request.resume();
}
else {
form.isUpload = accept;
}
}
catch (err) {
// this._service.request.socket.destroy();
return self.returnError(err);
}
form.onEnd.on(function () {
Object.assign(self.data, form.fields);
Object.assign(self.data, form.files);
ok();
});
form.parse();
}
else {
this.request.on('end', ok);
}
}
/**
* @func hasAcceptFilestream(info) 是否接收文件流
*/
hasAcceptFilestream(info) {
return false;
}
/**
* @func auth(info)
*/
auth(info) {
return true;
}
/**
* @fun returnData() return data to browser
* @arg type {String} # MIME type
* @arg data {Object} # data
*/
returnData(type, data) {
var res = this.response;
var ae = this.request.headers['accept-encoding'];
this.markCompleteResponse();
this.setDefaultHeader();
res.setHeader('Content-Type', type);
if (typeof data == 'string' &&
this.server.agzip && ae && ae.match(/gzip/i)) {
zlib.gzip(data, function (err, data) {
res.setHeader('Content-Encoding', 'gzip');
res.writeHead(200);
res.end(data);
});
}
else {
res.writeHead(200);
res.end(data);
}
}
/**
* @fun returnString # return string to browser
* @arg type {String} # MIME type
* @arg str {String}
*/
returnString(str, type = 'text/plain') {
return this.returnData(type + ';charset=utf-8', str);
}
/**
* @fun returnHtml # return html to browser
* @arg html {String}
*/
returnHtml(html) {
var type = this.server.getMime('html');
return this.returnString(html, type);
}
/**
* @fun rev # return data to browser
* @arg data {JSON}
*/
returnJSON(data) {
this.setNoCache();
return returnJSON(this, { data: data, errno: 0, code: 0, st: new Date().valueOf() });
}
/**
* @fun returnError() return error to browser
* @arg [err] {Error}
*/
returnError(err) {
this.setNoCache();
var accept = this.request.headers.accept || '';
if (/text\/html|application\/xhtml/.test(accept)) {
return this.returnHtmlError(err);
}
else {
return this.returnJSONError(err);
}
}
/**
* @func returnJSONError(err)
*/
returnJSONError(err) {
err = Error.toJSON(err);
err.st = new Date().valueOf();
if (!err.errno) {
err.errno = -1;
}
err.st = new Date().valueOf();
return returnJSON(this, err);
}
/**
* @func returnHtmlError()
*/
returnHtmlError(err) {
err = Error.toJSON(err);
var msg = [];
if (err.message)
msg.push(err.message);
if (err.errno)
msg.push('Errno: ' + err.errno);
if (err.exception)
msg.push('Exception: ' + err.exception);
if (err.path)
msg.push('Path: ' + err.path);
if (err.stack)
msg.push(err.stack);
var text = '<h4><pre style="color:#f00">' + msg.join('\n') + '</pre></h4>';
if (err.description) {
text += '<br/><h4>Description:</h4><br/>';
text += err.description;
}
return this.returnErrorStatus(500, text);
}
}
exports.HttpService = HttpService;
/**
* @class HttpService
*/
class Descriptors extends HttpService {
descriptors() {
return service_1.default.getServiceDescriptors();
}
}
exports.Descriptors = Descriptors;
service_1.default.set('descriptors', Descriptors);