mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
main
This commit is contained in:
745
node_modules/node-rest-client/lib/node-rest-client.js
generated
vendored
Normal file
745
node_modules/node-rest-client/lib/node-rest-client.js
generated
vendored
Normal file
@ -0,0 +1,745 @@
|
||||
var http = require('follow-redirects').http,
|
||||
https = require('follow-redirects').https,
|
||||
urlParser = require('url'),
|
||||
util = require("util"),
|
||||
events = require("events"),
|
||||
zlib = require("zlib"),
|
||||
node_debug = require("debug")("NRC");
|
||||
|
||||
exports.Client = function (options){
|
||||
var self = this,
|
||||
// parser response manager
|
||||
parserManager = require("./nrc-parser-manager")(),
|
||||
serializerManager = require("./nrc-serializer-manager")(),
|
||||
// connection manager
|
||||
connectManager = new ConnectManager(this, parserManager),
|
||||
// io facade to parsers and serailiazers
|
||||
ioFacade = function(parserManager, serializerManager){
|
||||
// error execution context
|
||||
var errorContext = function(logic){
|
||||
return function(){
|
||||
try{
|
||||
return logic.apply(this, arguments);
|
||||
}catch(err){
|
||||
self.emit('error',err);
|
||||
}
|
||||
};
|
||||
},
|
||||
result={"parsers":{}, "serializers":{}};
|
||||
|
||||
// parsers facade
|
||||
result.parsers.add = errorContext(parserManager.add);
|
||||
result.parsers.remove = errorContext(parserManager.remove);
|
||||
result.parsers.find = errorContext(parserManager.find);
|
||||
result.parsers.getAll = errorContext(parserManager.getAll);
|
||||
result.parsers.getDefault = errorContext(parserManager.getDefault);
|
||||
result.parsers.clean = errorContext(parserManager.clean);
|
||||
|
||||
// serializers facade
|
||||
result.serializers.add = errorContext(serializerManager.add);
|
||||
result.serializers.remove = errorContext(serializerManager.remove);
|
||||
result.serializers.find = errorContext(serializerManager.find);
|
||||
result.serializers.getAll = errorContext(serializerManager.getAll);
|
||||
result.serializers.getDefault = errorContext(serializerManager.getDefault);
|
||||
result.serializers.clean = errorContext(serializerManager.clean);
|
||||
|
||||
return result;
|
||||
|
||||
}(parserManager,serializerManager),
|
||||
// declare util constants
|
||||
CONSTANTS={
|
||||
HEADER_CONTENT_LENGTH:"Content-Length"
|
||||
};
|
||||
|
||||
|
||||
self.options = options || {},
|
||||
self.useProxy = (self.options.proxy || false)?true:false,
|
||||
self.useProxyTunnel = (!self.useProxy || self.options.proxy.tunnel===undefined)?false:self.options.proxy.tunnel,
|
||||
self.proxy = self.options.proxy,
|
||||
self.connection = self.options.connection || {},
|
||||
self.mimetypes = self.options.mimetypes || {},
|
||||
self.requestConfig = self.options.requestConfig || {},
|
||||
self.responseConfig = self.options.responseConfig || {};
|
||||
|
||||
// namespaces for methods, parsers y serializers
|
||||
this.methods={};
|
||||
this.parsers={};
|
||||
this.serializers={};
|
||||
|
||||
// Client Request to be passed to ConnectManager and returned
|
||||
// for each REST method invocation
|
||||
var ClientRequest =function(){
|
||||
events.EventEmitter.call(this);
|
||||
};
|
||||
|
||||
|
||||
util.inherits(ClientRequest, events.EventEmitter);
|
||||
|
||||
|
||||
ClientRequest.prototype.end = function(){
|
||||
if(this._httpRequest) {
|
||||
this._httpRequest.end();
|
||||
}
|
||||
};
|
||||
|
||||
ClientRequest.prototype.setHttpRequest=function(req){
|
||||
this._httpRequest = req;
|
||||
};
|
||||
|
||||
|
||||
|
||||
var Util = {
|
||||
createProxyPath:function(url){
|
||||
var result = url.host;
|
||||
// check url protocol to set path in request options
|
||||
if (url.protocol === "https:"){
|
||||
// port is set, leave it, otherwise use default https 443
|
||||
result = (url.host.indexOf(":") == -1?url.hostname + ":443":url.host);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
createProxyHeaders:function(url){
|
||||
var result ={};
|
||||
// if proxy requires authentication, create Proxy-Authorization headers
|
||||
if (self.proxy.user && self.proxy.password){
|
||||
result["Proxy-Authorization"] = "Basic " + new Buffer([self.proxy.user,self.proxy.password].join(":")).toString("base64");
|
||||
}
|
||||
// no tunnel proxy connection, we add the host to the headers
|
||||
if(!self.useProxyTunnel)
|
||||
result["host"] = url.host;
|
||||
|
||||
return result;
|
||||
},
|
||||
createConnectOptions:function(connectURL, connectMethod){
|
||||
debug("connect URL = ", connectURL);
|
||||
var url = urlParser.parse(connectURL),
|
||||
path,
|
||||
result={},
|
||||
protocol = url.protocol.indexOf(":") == -1?url.protocol:url.protocol.substring(0,url.protocol.indexOf(":")),
|
||||
defaultPort = protocol === 'http'?80:443;
|
||||
|
||||
result ={
|
||||
host: url.host.indexOf(":") == -1?url.host:url.host.substring(0,url.host.indexOf(":")),
|
||||
port: url.port === undefined?defaultPort:url.port,
|
||||
path: url.path,
|
||||
protocol:protocol,
|
||||
href:url.href
|
||||
};
|
||||
|
||||
if (self.useProxy) result.agent = false; // cannot use default
|
||||
// agent in proxy mode
|
||||
|
||||
if (self.options.user && self.options.password){
|
||||
result.auth = [self.options.user,self.options.password].join(":");
|
||||
|
||||
} else if (self.options.user && !self.options.password){
|
||||
// some sites only needs user with no password to
|
||||
// authenticate
|
||||
result.auth = self.options.user + ":";
|
||||
}
|
||||
|
||||
// configure proxy connection to establish a tunnel
|
||||
if (self.useProxy){
|
||||
|
||||
result.proxy ={
|
||||
host: self.proxy.host,
|
||||
port: self.proxy.port,
|
||||
method: self.useProxyTunnel?'CONNECT':connectMethod,// if
|
||||
// proxy
|
||||
// tunnel
|
||||
// use
|
||||
// 'CONNECT'
|
||||
// method,
|
||||
// else
|
||||
// get
|
||||
// method
|
||||
// from
|
||||
// request,
|
||||
path: self.useProxyTunnel?this.createProxyPath(url):connectURL, // if
|
||||
// proxy
|
||||
// tunnel
|
||||
// set
|
||||
// proxy
|
||||
// path
|
||||
// else
|
||||
// get
|
||||
// request
|
||||
// path,
|
||||
headers: this.createProxyHeaders(url) // createProxyHeaders
|
||||
// add correct
|
||||
// headers depending
|
||||
// of proxy
|
||||
// connection type
|
||||
};
|
||||
}
|
||||
|
||||
if(self.connection && typeof self.connection === 'object'){
|
||||
for(var option in self.connection){
|
||||
result[option] = self.connection[option];
|
||||
}
|
||||
}
|
||||
|
||||
// don't use tunnel to connect to proxy, direct request
|
||||
// and delete proxy options
|
||||
if (!self.useProxyTunnel){
|
||||
for (var proxyOption in result.proxy){
|
||||
result[proxyOption] = result.proxy[proxyOption];
|
||||
}
|
||||
|
||||
delete result.proxy;
|
||||
}
|
||||
|
||||
// add general request and response config to connect options
|
||||
|
||||
result.requestConfig = self.requestConfig;
|
||||
result.responseConfig = self.responseConfig;
|
||||
|
||||
|
||||
return result;
|
||||
},
|
||||
decodeQueryFromURL: function(connectURL){
|
||||
var url = urlParser.parse(connectURL),
|
||||
query = url.query.substring(1).split("&"),
|
||||
keyValue,
|
||||
result={};
|
||||
|
||||
// create decoded args from key value elements in query+
|
||||
for (var i=0;i<query.length;i++){
|
||||
keyValue = query[i].split("=");
|
||||
result[keyValue[0]] = decodeURIComponent(keyValue[1]);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
},
|
||||
serializeEncodeQueryFromArgs:function(args){
|
||||
|
||||
function serialize(obj, parent) {
|
||||
var tokens = [], propertyName;
|
||||
// iterate over all properties
|
||||
for(propertyName in obj) {
|
||||
// if object has property (it's not an array iteration)
|
||||
if (obj.hasOwnProperty(propertyName)) {
|
||||
// if property has parent, add nested reference
|
||||
var parsedProperty = parent ? parent + "[" + propertyName + "]" : propertyName, propertyValue = obj[propertyName];
|
||||
|
||||
// if property has value and is object (we must iterate
|
||||
// again, not final leaf)
|
||||
// iterate over object property passing current parsed
|
||||
// property as parent
|
||||
// else add encoded parsed property and value to result
|
||||
// array
|
||||
tokens.push((propertyValue !== null && typeof propertyValue === "object") ?
|
||||
serialize(propertyValue, parsedProperty) :
|
||||
encodeURIComponent(parsedProperty) + "=" + encodeURIComponent(propertyValue));
|
||||
}
|
||||
}
|
||||
return tokens.join("&");
|
||||
}
|
||||
|
||||
debug("args is", args);
|
||||
// check args consistency
|
||||
if (args && typeof args !== 'object' )
|
||||
self.emit('error','cannot serialize parameters: invalid type ' + (typeof args) + ' should be an object type');
|
||||
|
||||
return serialize(args);
|
||||
},
|
||||
parsePathParameters:function(args,url){
|
||||
var result = url;
|
||||
if (!args || !args.path) return url;
|
||||
|
||||
for (var placeholder in args.path){
|
||||
var regex = new RegExp("\\$\\{" + placeholder + "\\}","i");
|
||||
result = result.replace(regex,args.path[placeholder]);
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
},
|
||||
overrideClientConfig:function(connectOptions,methodOptions){
|
||||
function validateReqResOptions(reqResOption){
|
||||
return (reqResOption && typeof reqResOption === 'object');
|
||||
}
|
||||
// check if we have particular request or response config set on
|
||||
// this method invocation
|
||||
// and override general request/response config
|
||||
if (validateReqResOptions(methodOptions.requestConfig)){
|
||||
util._extend(connectOptions.requestConfig,methodOptions.requestConfig);
|
||||
}
|
||||
|
||||
if (validateReqResOptions(methodOptions.responseConfig)){
|
||||
util._extend(connectOptions.responseConfig,methodOptions.responseConfig);
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
connect : function(method, url, args, callback, clientRequest){
|
||||
//wrapper for emit function on client
|
||||
var clientEmitterWrapper = function (client){
|
||||
var client = client;
|
||||
return function(type, event){client.emit(type, event);};
|
||||
};
|
||||
|
||||
// check args type if we use it
|
||||
if (callback && args && typeof args !== 'object')self.emit('error','args should be and object');
|
||||
|
||||
// configure connect options based on url parameter parse
|
||||
var options = this.createConnectOptions(this.parsePathParameters(args,url), method);
|
||||
debug("options pre connect",options);
|
||||
options.method = method,
|
||||
clientRequest.href=options.href,
|
||||
options.clientRequest = clientRequest,
|
||||
options.headers= options.headers || {};
|
||||
|
||||
debug("args = ", args);
|
||||
debug("args.data = ", args !== undefined?args.data:undefined);
|
||||
// no args passed
|
||||
if (typeof args === 'function'){
|
||||
callback = args;
|
||||
// add Content-length to POST/PUT/DELETE/PATCH methods
|
||||
if (method === 'POST' || method === 'PUT' || method === 'DELETE' || method === 'PATCH'){
|
||||
options.headers[CONSTANTS.HEADER_CONTENT_LENGTH] = 0;
|
||||
}
|
||||
} else if (typeof args === 'object') {
|
||||
// add headers and POST/PUT/DELETE/PATCH data to connect options
|
||||
// to be passed
|
||||
// with request, but without deleting other headers like
|
||||
// non-tunnel proxy headers
|
||||
if (args.headers){
|
||||
for (var headerName in args.headers){
|
||||
if (args.headers.hasOwnProperty(headerName)) {
|
||||
options.headers[headerName] = args.headers[headerName];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// we have args, go and check if we have parameters
|
||||
if (args.parameters && Object.keys(args.parameters).length > 0){
|
||||
// validate URL consistency, and fix it adding query
|
||||
// parameter separation char
|
||||
|
||||
// check if URL already has '?' path parameter separator
|
||||
// char in any position that is not final
|
||||
// if true throw error
|
||||
var pathLength = options.path.length,
|
||||
pathParameterSepCharPos = options.path.indexOf("?");
|
||||
|
||||
if (pathParameterSepCharPos >= 0 && pathParameterSepCharPos!== pathLength -1 )
|
||||
self.emit('error','parameters argument cannot be used if parameters are already defined in URL ' + options.path);
|
||||
|
||||
options.path +=(options.path.charAt(pathLength-1) === '?'?"":"?");
|
||||
// check if we have serializable parameter container, that
|
||||
// must be serialized and encoded
|
||||
// directly, as javascript object
|
||||
options.path = options.path.concat(Util.serializeEncodeQueryFromArgs(args.parameters));
|
||||
debug("options.path after request parameters = ", options.path);
|
||||
}
|
||||
|
||||
// override client config, by the moment just for request
|
||||
// response config
|
||||
this.overrideClientConfig(options,args);
|
||||
|
||||
// always set Content-length header if not set previously
|
||||
// set Content lentgh for some servers to work (nginx, apache)
|
||||
if (args.data !== undefined && !options.headers.hasOwnProperty(CONSTANTS.HEADER_CONTENT_LENGTH)){
|
||||
serializerManager.get(options).serialize(args.data, clientEmitterWrapper(self), function(serializedData){
|
||||
options.data = serializedData;
|
||||
options.headers[CONSTANTS.HEADER_CONTENT_LENGTH] = Buffer.byteLength(options.data, 'utf8');
|
||||
});
|
||||
}else{
|
||||
options.headers[CONSTANTS.HEADER_CONTENT_LENGTH] = 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
debug("options post connect",options);
|
||||
debug("FINAL SELF object ====>", self);
|
||||
|
||||
if (self.useProxy && self.useProxyTunnel){
|
||||
connectManager.proxy(options,callback);
|
||||
}else{
|
||||
// normal connection and direct proxy connections (no tunneling)
|
||||
connectManager.normal(options,callback);
|
||||
}
|
||||
},
|
||||
mergeMimeTypes:function(mimetypes){
|
||||
// this function is left for backward compatibility, but will be
|
||||
// deleted in future releases
|
||||
var parser = null;
|
||||
// merge mime-types passed as options to parsers
|
||||
if (mimetypes && typeof mimetypes === "object"){
|
||||
try{
|
||||
if (mimetypes.json && mimetypes.json instanceof Array && mimetypes.json.length > 0){
|
||||
parser = parserManager.find("JSON");
|
||||
parser.contentTypes = mimetypes.json;
|
||||
}else if (mimetypes.xml && mimetypes.xml instanceof Array && mimetypes.xml.length > 0){
|
||||
parser = parserManager.find("XML");
|
||||
parser.contentTypes = mimetypes.xml;
|
||||
}
|
||||
}catch(err){
|
||||
self.emit('error', 'cannot assign custom content types to parser, cause: ' + err);
|
||||
}
|
||||
}
|
||||
},
|
||||
createHttpMethod:function(methodName){
|
||||
return function(url, args, callback){
|
||||
var clientRequest = new ClientRequest();
|
||||
Util.connect(methodName.toUpperCase(), url, args, callback, clientRequest);
|
||||
return clientRequest;
|
||||
};
|
||||
}
|
||||
},
|
||||
Method = function(url, method){
|
||||
var httpMethod = self[method.toLowerCase()];
|
||||
|
||||
return function(args,callback){
|
||||
var completeURL = url;
|
||||
// no args
|
||||
if (typeof args === 'function'){
|
||||
callback = args;
|
||||
args = {};
|
||||
}
|
||||
|
||||
return httpMethod(completeURL, args , callback);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
this.get = Util.createHttpMethod("get");
|
||||
|
||||
this.post = Util.createHttpMethod("post");
|
||||
|
||||
this.put = Util.createHttpMethod("put");
|
||||
|
||||
this.delete = Util.createHttpMethod("delete");
|
||||
|
||||
this.patch = Util.createHttpMethod("patch");
|
||||
|
||||
|
||||
this.registerMethod = function(name, url, method){
|
||||
// create method in method registry with preconfigured REST invocation
|
||||
// method
|
||||
this.methods[name] = new Method(url,method);
|
||||
};
|
||||
|
||||
this.unregisterMethod = function(name){
|
||||
delete this.methods[name];
|
||||
};
|
||||
|
||||
this.addCustomHttpMethod=function(methodName){
|
||||
self[methodName.toLowerCase()] = Util.createHttpMethod(methodName);
|
||||
};
|
||||
|
||||
this.parsers = ioFacade.parsers;
|
||||
|
||||
this.serializers = ioFacade.serializers;
|
||||
|
||||
// merge mime types with connect manager
|
||||
Util.mergeMimeTypes(self.mimetypes);
|
||||
debug("ConnectManager", connectManager);
|
||||
|
||||
};
|
||||
|
||||
|
||||
var ConnectManager = function(client, parserManager) {
|
||||
|
||||
var client = client,
|
||||
clientEmitterWrapper = function (client){
|
||||
var client = client;
|
||||
return function(type, event){client.emit(type, event);};
|
||||
};
|
||||
|
||||
|
||||
|
||||
this.configureRequest = function(req, config, clientRequest){
|
||||
|
||||
if (config.timeout){
|
||||
req.setTimeout(config.timeout, function(){
|
||||
clientRequest.emit('requestTimeout',req);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if(config.noDelay)
|
||||
req.setNoDelay(config.noDelay);
|
||||
|
||||
if(config.keepAlive)
|
||||
req.setSocketKeepAlive(config.noDelay,config.keepAliveDelay || 0);
|
||||
|
||||
};
|
||||
|
||||
this.configureResponse = function(res,config, clientRequest){
|
||||
if (config.timeout){
|
||||
res.setTimeout(config.timeout, function(){
|
||||
clientRequest.emit('responseTimeout',res);
|
||||
res.close();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.configureOptions = function(options){
|
||||
var followRedirectsProps =["followRedirects", "maxRedirects"];
|
||||
function configureProps(propsArray, optionsElement){
|
||||
for (var index in propsArray){
|
||||
if (optionsElement.hasOwnProperty(propsArray[index]))
|
||||
options[propsArray[index]] = optionsElement[propsArray[index]];
|
||||
}
|
||||
}
|
||||
|
||||
//add follows-redirects config
|
||||
configureProps(followRedirectsProps, options.requestConfig);
|
||||
|
||||
|
||||
// remove "protocol" and "clientRequest" option from options,
|
||||
// cos is not allowed by http/hppts node objects
|
||||
delete options.protocol;
|
||||
delete options.clientRequest;
|
||||
delete options.requestConfig;
|
||||
delete options.responseConfig;
|
||||
debug("options pre connect", options);
|
||||
};
|
||||
|
||||
this.handleEnd = function(res,buffer,callback){
|
||||
|
||||
var self = this,
|
||||
content = res.headers["content-type"],
|
||||
encoding = res.headers["content-encoding"];
|
||||
|
||||
debug("content-type: ", content);
|
||||
debug("content-encoding: ",encoding);
|
||||
|
||||
if(encoding !== undefined && encoding.indexOf("gzip") >= 0){
|
||||
debug("gunzip");
|
||||
zlib.gunzip(Buffer.concat(buffer),function(er,gunzipped){
|
||||
self.handleResponse(res,gunzipped,callback);
|
||||
});
|
||||
}else if(encoding !== undefined && encoding.indexOf("deflate") >= 0){
|
||||
debug("inflate");
|
||||
zlib.inflate(Buffer.concat(buffer),function(er,inflated){
|
||||
self.handleResponse(res,inflated,callback);
|
||||
});
|
||||
}else {
|
||||
debug("not compressed");
|
||||
self.handleResponse(res,Buffer.concat(buffer),callback);
|
||||
}
|
||||
};
|
||||
|
||||
this.handleResponse = function(res,data,callback){
|
||||
// find valid parser to be used with response content type, first one
|
||||
// found
|
||||
parserManager.get(res).parse(data, clientEmitterWrapper(client), function(parsedData){
|
||||
callback(parsedData,res);
|
||||
});
|
||||
};
|
||||
|
||||
this.prepareData = function(data){
|
||||
var result;
|
||||
if ((data instanceof Buffer) || (typeof data !== 'object')){
|
||||
result = data;
|
||||
}else{
|
||||
result = JSON.stringify(data);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
this.proxy = function(options, callback){
|
||||
|
||||
debug("proxy options",options.proxy);
|
||||
|
||||
// creare a new proxy tunnel, and use to connect to API URL
|
||||
var proxyTunnel = http.request(options.proxy),
|
||||
self = this;
|
||||
|
||||
|
||||
proxyTunnel.on('connect',function(res, socket, head){
|
||||
debug("proxy connected",socket);
|
||||
|
||||
// set tunnel socket in request options, that's the tunnel
|
||||
// itself
|
||||
options.socket = socket;
|
||||
|
||||
var buffer=[],
|
||||
protocol = (options.protocol =="http")?http:https,
|
||||
clientRequest = options.clientRequest,
|
||||
requestConfig = options.requestConfig,
|
||||
responseConfig = options.responseConfig;
|
||||
|
||||
self.configureOptions(options);
|
||||
|
||||
// add request options to request returned to calling method
|
||||
clientRequest.options = options;
|
||||
|
||||
var request = protocol.request(options, function(res){
|
||||
// configure response
|
||||
self.configureResponse(res,responseConfig, clientRequest);
|
||||
|
||||
// concurrent data chunk handler
|
||||
res.on('data',function(chunk){
|
||||
buffer.push(Buffer.from(chunk));
|
||||
});
|
||||
|
||||
res.on('end',function(){
|
||||
self.handleEnd(res,buffer,callback);
|
||||
});
|
||||
|
||||
|
||||
// handler response errors
|
||||
res.on('error',function(err){
|
||||
if (clientRequest !== undefined && typeof clientRequest === 'object'){
|
||||
// add request as property of error
|
||||
err.request = clientRequest;
|
||||
err.response = res;
|
||||
// request error handler
|
||||
clientRequest.emit('error',err);
|
||||
}else{
|
||||
// general error handler
|
||||
client.emit('error',err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// configure request and add it to clientRequest
|
||||
// and add it to request returned
|
||||
self.configureRequest(request,requestConfig, clientRequest);
|
||||
clientRequest.setHttpRequest(request);
|
||||
|
||||
|
||||
// write POST/PUT data to request body;
|
||||
// find valid serializer to be used to serialize request data,
|
||||
// first one found
|
||||
// is the one to be used.if none found for match condition,
|
||||
// default serializer is used
|
||||
|
||||
if(options.data)request.write(options.data);
|
||||
|
||||
request.end();
|
||||
|
||||
|
||||
// handle request errors and handle them by request or general
|
||||
// error handler
|
||||
request.on('error',function(err){
|
||||
if (clientRequest !== undefined && typeof clientRequest === 'object'){
|
||||
// add request as property of error
|
||||
err.request = clientRequest;
|
||||
|
||||
// request error handler
|
||||
clientRequest.emit('error',err);
|
||||
}else{
|
||||
// general error handler
|
||||
client.emit('error',err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// proxy tunnel error are only handled by general error handler
|
||||
proxyTunnel.on('error',function(e){
|
||||
client.emit('error',e);
|
||||
});
|
||||
|
||||
proxyTunnel.end();
|
||||
|
||||
};
|
||||
|
||||
this.normal = function(options, callback){
|
||||
|
||||
var buffer = [],
|
||||
protocol = (options.protocol === "http")?http:https,
|
||||
clientRequest = options.clientRequest,
|
||||
requestConfig = options.requestConfig,
|
||||
responseConfig = options.responseConfig,
|
||||
self = this;
|
||||
|
||||
self.configureOptions(options);
|
||||
|
||||
// add request options to request returned to calling method
|
||||
clientRequest.options = options;
|
||||
|
||||
var request = protocol.request(options, function(res){
|
||||
// configure response
|
||||
self.configureResponse(res,responseConfig, clientRequest);
|
||||
|
||||
// concurrent data chunk handler
|
||||
res.on('data',function(chunk){
|
||||
buffer.push(Buffer.from(chunk));
|
||||
});
|
||||
|
||||
res.on('end',function(){
|
||||
|
||||
self.handleEnd(res,buffer,callback);
|
||||
|
||||
});
|
||||
|
||||
// handler response errors
|
||||
res.on('error',function(err){
|
||||
if (clientRequest !== undefined && typeof clientRequest === 'object'){
|
||||
// add request as property of error
|
||||
err.request = clientRequest;
|
||||
err.response = res;
|
||||
// request error handler
|
||||
clientRequest.emit('error',err);
|
||||
}else{
|
||||
// general error handler
|
||||
client.emit('error',err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// configure request and add it to clientRequest
|
||||
// and add it to request returned
|
||||
self.configureRequest(request,requestConfig, clientRequest);
|
||||
debug("clientRequest",clientRequest);
|
||||
|
||||
clientRequest.setHttpRequest(request);
|
||||
|
||||
debug("options data", options.data);
|
||||
// write POST/PUT data to request body;
|
||||
// find valid serializer to be used to serialize request data,
|
||||
// first one found
|
||||
// is the one to be used.if none found for match condition,
|
||||
// default serializer is used
|
||||
if(options.data)request.write(options.data);
|
||||
request.end(); // end request when data is written
|
||||
|
||||
// handle request errors and handle them by request or general
|
||||
// error handler
|
||||
request.on('error',function(err){
|
||||
if (clientRequest !== undefined && typeof clientRequest === 'object'){
|
||||
// add request as property of error
|
||||
err.request = clientRequest;
|
||||
|
||||
// request error handler
|
||||
clientRequest.emit('error',err);
|
||||
}else{
|
||||
// general error handler
|
||||
client.emit('error',err);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// event handlers for client and ConnectManager
|
||||
util.inherits(exports.Client, events.EventEmitter);
|
||||
|
||||
|
||||
var debug = function(){
|
||||
if (!process.env.DEBUG) return;
|
||||
|
||||
var now = new Date(),
|
||||
header =now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + " [NRC CLIENT]" + arguments.callee.caller.name + " -> ",
|
||||
args = Array.prototype.slice.call(arguments);
|
||||
args.splice(0,0,header);
|
||||
node_debug.apply(console,args);
|
||||
|
||||
|
||||
};
|
156
node_modules/node-rest-client/lib/nrc-parser-manager.js
generated
vendored
Normal file
156
node_modules/node-rest-client/lib/nrc-parser-manager.js
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
var ParserManager = function(){
|
||||
var registry={}, defaultParser = null;
|
||||
|
||||
var _private={
|
||||
"validate":function(parser){
|
||||
|
||||
function validateProperties(parser, props){
|
||||
var result = true;
|
||||
for (var propIndex in props){
|
||||
var propType = props[propIndex].split(":");
|
||||
if (!parser.hasOwnProperty([propType[0]]) || typeof parser[propType[0]] !== propType[1]){
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
result = validateProperties(parser,["name:string","parse:function","isDefault:boolean"]);
|
||||
|
||||
// valid parser, check if its not default response parser, to validate non
|
||||
// default parser props
|
||||
if (result && !parser.isDefault)
|
||||
result = validateProperties(parser,["match:function"]);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
this.add = function(parser){
|
||||
if (!_private.validate(parser))
|
||||
throw "parser cannot be added: invalid parser definition";
|
||||
|
||||
if (parser.isDefault){
|
||||
defaultParser = parser;
|
||||
}else{
|
||||
registry[parser.name] = parser;
|
||||
}
|
||||
};
|
||||
|
||||
this.remove = function(parserName){
|
||||
var result = registry[parserName];
|
||||
if (!result)
|
||||
throw "cannot remove parser: " + parserName +" doesn't exists";
|
||||
|
||||
delete registry[parserName];
|
||||
};
|
||||
|
||||
this.clean = function(){
|
||||
registry={};
|
||||
};
|
||||
|
||||
this.find = function(parserName){
|
||||
var result = registry[parserName];
|
||||
if (!result)
|
||||
throw "cannot find parser: " + parserName + " doesn't exists ";
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
this.getDefault = function(){
|
||||
return defaultParser;
|
||||
};
|
||||
|
||||
this.get = function(response){
|
||||
var result = null;
|
||||
for (var parserName in registry){
|
||||
if (registry[parserName].match(response)){
|
||||
result = registry[parserName];
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if parser not found return default parser, else parser found
|
||||
return (result === null)?defaultParser:result;
|
||||
};
|
||||
|
||||
this.getAll=function(){
|
||||
var result=[];
|
||||
for (var parserName in registry){
|
||||
result.push(registry[parserName]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = function(){
|
||||
|
||||
var parserManager = new ParserManager();
|
||||
|
||||
var BaseParser = {
|
||||
"isDefault":false,
|
||||
"match":function(response){
|
||||
var result = false,
|
||||
contentType = response.headers["content-type"] && response.headers["content-type"].replace(/ /g, '');
|
||||
|
||||
if (!contentType) return result;
|
||||
|
||||
for (var i=0; i<this.contentTypes.length;i++){
|
||||
result = this.contentTypes[i].trim().toLowerCase() === contentType.trim().toLowerCase();
|
||||
if (result) break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
//add default parser managers: JSON,XML and unknown content/type
|
||||
parserManager.add(Object.assign({
|
||||
"name":"XML",
|
||||
"options":{"explicitArray":false},
|
||||
"contentTypes":["application/xml","application/xml;charset=utf-8","text/xml","text/xml;charset=utf-8"],
|
||||
"parseString":require('xml2js').parseString,
|
||||
"parse":function(byteBuffer,nrcEventEmitter,parsedCallback){
|
||||
this.parseString(byteBuffer.toString(),this.options, function (err, result) {
|
||||
parsedCallback(result);
|
||||
});
|
||||
}
|
||||
}, BaseParser));
|
||||
|
||||
parserManager.add(Object.assign({
|
||||
"name":"JSON",
|
||||
"contentTypes":["application/json","application/json;charset=utf-8"],
|
||||
"isValidData":function(data){
|
||||
return data !== undefined && (data.length !== undefined && data.length > 0);
|
||||
},
|
||||
"parse":function(byteBuffer,nrcEventEmitter,parsedCallback){
|
||||
var jsonData,
|
||||
data = byteBuffer.toString();
|
||||
|
||||
try {
|
||||
jsonData = this.isValidData(data)?JSON.parse(data):data;
|
||||
} catch (err) {
|
||||
// Something went wrong when parsing json. This can happen
|
||||
// for many reasons, including a bad implementation on the
|
||||
// server.
|
||||
nrcEventEmitter('error','Error parsing response. response: [' +data + '], error: [' + err + ']');
|
||||
}
|
||||
parsedCallback(jsonData);
|
||||
}
|
||||
},BaseParser));
|
||||
|
||||
|
||||
parserManager.add({
|
||||
"name":"DEFAULT",
|
||||
"isDefault":true,
|
||||
"parse":function(byteBuffer,nrcEventEmitter,parsedCallback){
|
||||
parsedCallback(byteBuffer);
|
||||
}
|
||||
});
|
||||
|
||||
return parserManager;
|
||||
}
|
185
node_modules/node-rest-client/lib/nrc-serializer-manager.js
generated
vendored
Normal file
185
node_modules/node-rest-client/lib/nrc-serializer-manager.js
generated
vendored
Normal file
@ -0,0 +1,185 @@
|
||||
var xmlserializer = require('xml2js');
|
||||
|
||||
var SerializerManager = function(){
|
||||
var registry={}, defaultSerializer = null;
|
||||
|
||||
var _private={
|
||||
"validate":function(serializer){
|
||||
|
||||
function validateProperties(serializer, props){
|
||||
var result = true;
|
||||
for (var propIndex in props){
|
||||
var propType = props[propIndex].split(":");
|
||||
if (!serializer.hasOwnProperty([propType[0]]) || typeof serializer[propType[0]] !== propType[1]){
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
result = validateProperties(serializer,["name:string","serialize:function","isDefault:boolean"]);
|
||||
|
||||
// valid serializer, check if its not default request serializer, to validate non
|
||||
// default serializer props
|
||||
if (result && !serializer.isDefault)
|
||||
result = validateProperties(serializer,["match:function"]);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
this.add = function(serializer){
|
||||
if (!_private.validate(serializer))
|
||||
throw "serializer cannot be added: invalid serializer definition";
|
||||
|
||||
if (serializer.isDefault){
|
||||
defaultSerializer = serializer;
|
||||
}else{
|
||||
registry[serializer.name] = serializer;
|
||||
}
|
||||
};
|
||||
|
||||
this.remove = function(serializerName){
|
||||
var result = registry[serializerName];
|
||||
if (!result)
|
||||
throw "cannot remove serializer: " + serializerName +" doesn't exists";
|
||||
|
||||
delete registry[serializerName];
|
||||
};
|
||||
|
||||
this.find = function(serializerName){
|
||||
var result = registry[serializerName];
|
||||
if (!result)
|
||||
throw "cannot find serializer: " + serializerName +" doesn't exists";
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
this.clean = function(){
|
||||
registry={};
|
||||
};
|
||||
|
||||
this.get = function(request){
|
||||
var result = null;
|
||||
for (var serializerName in registry){
|
||||
if (registry[serializerName].match(request)){
|
||||
result = registry[serializerName];
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if serializer not found return default serializer, else serializer found
|
||||
return (result === null)?defaultSerializer:result;
|
||||
};
|
||||
|
||||
this.getAll=function(){
|
||||
var result = [];
|
||||
for (var serializerName in registry){
|
||||
result.push(registry[serializerName]);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
this.getDefault = function(){
|
||||
return defaultSerializer;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports = function(){
|
||||
|
||||
var serializerManager = new SerializerManager();
|
||||
|
||||
var BaseSerializer ={
|
||||
"isDefault":false,
|
||||
"match":function(request){
|
||||
var result = false,
|
||||
contentType = request.headers["Content-Type"] && request.headers["Content-Type"].replace(/ /g, '');
|
||||
|
||||
if (!contentType) return result;
|
||||
|
||||
for (var i=0; i<this.contentTypes.length;i++){
|
||||
result = this.contentTypes[i].trim().toLowerCase() === contentType.trim().toLowerCase();
|
||||
if (result) break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//add default serializer managers: JSON,XML and unknown content/type
|
||||
serializerManager.add(Object.assign({
|
||||
"name":"XML",
|
||||
"options":{},
|
||||
"contentTypes":["application/xml","application/xml;charset=utf-8","text/xml","text/xml;charset=utf-8"],
|
||||
"xmlSerializer":new xmlserializer.Builder(this.options),
|
||||
"serialize":function(data,nrcEventEmitter,serializedCallback){
|
||||
if (typeof data === 'object')
|
||||
data = xmlSerializer.buildObject(data);
|
||||
|
||||
serializedCallback(data);
|
||||
|
||||
}
|
||||
},BaseSerializer));
|
||||
|
||||
serializerManager.add(Object.assign({
|
||||
"name":"JSON",
|
||||
"contentTypes":["application/json","application/json;charset=utf-8"],
|
||||
"serialize":function(data,nrcEventEmitter,serializedCallback){
|
||||
if(typeof data === 'object')
|
||||
data = JSON.stringify(data);
|
||||
serializedCallback(data);
|
||||
}
|
||||
},BaseSerializer));
|
||||
|
||||
|
||||
serializerManager.add(Object.assign({
|
||||
"name":"FORM-ENCODED",
|
||||
"contentTypes":["application/x-www-form-urlencoded","multipart/form-data","text/plain"],
|
||||
"encode":function (obj, parent) {
|
||||
var tokens = [], propertyName;
|
||||
//iterate over all properties
|
||||
for(propertyName in obj) {
|
||||
//if object has property (it's not an array iteration)
|
||||
if (obj.hasOwnProperty(propertyName)) {
|
||||
//if property has parent, add nested reference
|
||||
var parsedProperty = parent ? parent + "[" + propertyName + "]" : propertyName, propertyValue = obj[propertyName];
|
||||
|
||||
// if property has value and is object (we must iterate again, not final leaf)
|
||||
// iterate over object property passing current parsed property as parent
|
||||
// else add encoded parsed property and value to result array
|
||||
tokens.push((propertyValue !== null && typeof propertyValue === "object") ?
|
||||
serialize(propertyValue, parsedProperty) :
|
||||
encodeURIComponent(parsedProperty) + "=" + encodeURIComponent(propertyValue));
|
||||
}
|
||||
}
|
||||
return tokens.join("&");
|
||||
},
|
||||
"serialize":function(data,nrcEventEmitter,serializedCallback){
|
||||
if(typeof data === 'object')
|
||||
data = this.encode(data);
|
||||
|
||||
serializedCallback(data);
|
||||
}
|
||||
},BaseSerializer));
|
||||
|
||||
|
||||
serializerManager.add({
|
||||
"name":"DEFAULT",
|
||||
"isDefault":true,
|
||||
"serialize":function(data,nrcEventEmitter,serializedCallback){
|
||||
|
||||
serializedCallback(data.toString());
|
||||
}
|
||||
});
|
||||
|
||||
return serializerManager;
|
||||
|
||||
};
|
Reference in New Issue
Block a user