<commit_before>var net = require('net');
var Server = require('./server');
var JID = require('./jid');
var StreamShaper = require('./../stream_shaper');
var StringPrep = require('node-stringprep').StringPrep;
var nameprep = new StringPrep('nameprep');

dbgStream = function(tag, stream) {
    stream.on('data', function(data) {
	console.log(tag + ' in: ' + data);
    });
    stream.on('error', function(e) {
	console.log(tag + ' error: ' + e.stack ? e.stack : e);
    });
    stream.on('close', function() {
	console.log(tag + ' close');
    });
    var oldSend = stream.send;
    stream.send = function(data) {
	console.log(tag + ' out: ' + data);
	oldSend.call(stream, data);
    };
};

/**
 * Represents a domain we host with connections to federated servers
 */
function DomainContext(router, domain) {
    this.router = router;
    this.domain = domain;
    this.s2sIn = {};
    this.s2sOut = {};
}

/**
 * Buffers until stream has been verified via Dialback
 */
DomainContext.prototype.send = function(stanza) {
    if (stanza.root)
	stanza = stanza.root();

    // TODO: return on empty to
    destDomain = new JID.JID(stanza.attrs.to).domain;
    var outStream = this.getOutStream(destDomain);

    if (outStream.isVerified)
	outStream.send(stanza);
    else {
	outStream.queue = outStream.queue || [];
	outStream.queue.push(stanza);
    }
};

/**
 * Does only buffer until stream is established, used for Dialback
 * communication itself.
 *
 * returns the stream
 */
DomainContext.prototype.sendRaw = function(stanza, destDomain) {
    if (stanza.root)
	stanza = stanza.root();

    var outStream = this.getOutStream(destDomain);
    var send = function() {
	outStream.send(stanza);
    };

    if (outStream.isOnline)
	send();
    else
	outStream.addListener('online', send);

    return outStream;
};

DomainContext.prototype.getOutStream = function(domain) {
    var self = this;

    // unfortunately we cannot use the incoming streams

    if (this.s2sOut.hasOwnProperty(domain)) {
	// There's one already
	return this.s2sOut[domain];
    } else {
	console.log("OUTGOING to " + domain);
	// Setup a new outgoing connection
	var outStream = Server.makeOutgoingServer(domain);
	this.s2sOut[domain] = outStream;
	dbgStream('outgoing', outStream);

	this.router.setupStream(outStream);
	this.setupStream(domain, outStream);

	outStream.addListener('close', function() {
	    // purge queue
	    if (outStream.queue) {
		outStream.queue.forEach(function(stanza) {
					    // do not provoke ping-pong effects
					    if (stanza.attrs.type === 'error')
						return;

					    var dest = stanza.attrs.to;
					    stanza.attrs.to = stanza.attrs.from;
					    stanza.attrs.from = dest;
					    stanza.attrs.type = 'error';
					    // TODO: add <error/> child if any programs wants to use that
					    self.receive(stanza);
					});
	    }
	    delete outStream.queue;

	    // remove from DomainContext
	    delete self.s2sOut[domain];
	});

	// Prepare dialback
	outStream.addListener('online', function() {
	    outStream.isOnline = true;
	    outStream.dbKey = generateKey();
	    outStream.send(Server.dialbackKey(self.domain, domain, outStream.dbKey));
	});
	outStream.addListener('dialbackResult', function(from, to, isValid) {
	    if (isValid) {
		outStream.isVerified = true;
		if (outStream.queue) {
		    outStream.queue.forEach(function(stanza) {
			outStream.send(stanza);
		    });
		    delete outStream.queue;
		}
	    } else {
		// we cannot do anything else with this stream that
		// failed dialback
		outStream.end();
	    }
	});

	return outStream;
    }
};

/**
 * Called by router when verification is done
 */
DomainContext.prototype.addInStream = function(domain, stream) {
    var self = this;

    if (this.s2sIn.hasOwnProperty(domain)) {
	// Replace old
	var oldStream = this.s2sIn[domain];
	oldStream.error('conflict', 'Connection replaced');
    }

    this.setupStream(domain, stream);
    stream.isOnline = true;
    stream.isVerified = true;
    stream.addListener('close', function() {
	if (self.s2sIn[domain] == stream)
	    delete self.s2sIn[domain];
    });
    this.s2sIn[domain] = stream;
};

DomainContext.prototype.setupStream = function(domain, stream) {
    var self = this;

    stream.addListener('stanza', function(stanza) {
	// Before verified they can send whatever they want
	if (!stream.isVerified)
	    return;

	if (!(typeof stanza.attrs.from === 'string' &&
	      typeof stanza.attrs.to === 'string')) {
	    stream.error('improper-addressing');
	    return;
	}

	// Only accept 'from' attribute JIDs that have the same domain
	// that we validated the stream for
	var fromDomain = (new JID.JID(stanza.attrs.from)).domain;
	if (fromDomain !== domain) {
	    stream.error('invalid-from');
	    return;
	}

	// Only accept 'to' attribute JIDs to this DomainContext
	var toDomain = (new JID.JID(stanza.attrs.to)).domain;
	if (toDomain !== self.domain) {
	    stream.error('improper-addressing');
	    return;
	}

	self.receive(stanza);
    });
};

DomainContext.prototype.verifyDialback = function(domain, id, key, cb) {
    var self = this;
    var outStream;
    if (this.s2sOut.hasOwnProperty(domain) &&
	(outStream = this.s2sOut[domain])) {

	if (outStream.isOnline) {
	    var isValid = outStream.streamAttrs.id === id &&
			      outStream.dbKey === key;
	    cb(isValid);
	} else {
	    // Not online, wait for outStream.streamAttrs
	    outStream.addListener('online', function() {
				      // recurse
				      self.verifyDialback(domain, id, key, cb);
				  });
	    outStream.addListener('close', function() {
				      cb(false);
				  });
	}
    } else
	cb(false);
};

DomainContext.prototype.receive = function(stanza) {
    if (this.stanzaListener)
	this.stanzaListener(stanza);
};

/**
 * TODO:
 * * TLS
 */
function Router(s2sPort) {
    var self = this;
    this.ctxs = {};

    net.createServer(function(inStream) {
	console.log('INCOMING from ' + inStream.remoteAddress);
	self.acceptConnection(inStream);
    }).listen(s2sPort || 5269);
}
exports.Router = Router;

// Defaults
Router.prototype.rateLimit = 100;  // 100 KB/s, it's S2S after all
Router.prototype.maxStanzaSize = 65536;  // 64 KB, by convention
Router.prototype.keepAlive = 30 * 1000;  // 30s
Router.prototype.streamTimeout = 5 * 60 * 1000;  // 5min
Router.prototype.credentials = undefined;  // TLS credentials

// little helper, because dealing with crypto & fs gets unwieldy
Router.prototype.loadCredentials = function(keyPath, certPath) {
    var crypto = require('crypto');
    var fs = require('fs');

    var key = fs.readFileSync(keyPath, 'ascii');
    var cert = fs.readFileSync(certPath, 'ascii');

    this.credentials = crypto.createCredentials({ key: key,
						  cert: cert });
};

Router.prototype.acceptConnection = function(inStream) {
    var self = this;

    dbgStream('incoming', inStream);
    this.setupStream(inStream);
    Server.makeIncomingServer(inStream);

    // incoming server wants to verify an outgoing connection of ours
    inStream.addListener('dialbackVerify', function(from, to, id, key) {
	from = nameprep.prepare(from);
	to = nameprep.prepare(to);
	self.verifyDialback(from, to, id, key, function(isValid) {
	    inStream.send(Server.dialbackVerified(to, from, id, isValid));
	});
    });
    // incoming connection wants to get verified
    inStream.addListener('dialbackKey', function(from, to, key) {
	from = nameprep.prepare(from);
	to = nameprep.prepare(to);
	var destDomain = to;
	if (self.hasContext(to)) {
	    var ctx = self.getContext(to);
	    var outStream = ctx.sendRaw(Server.dialbackVerify(to, from, inStream.streamId, key),
					from);

	    // TODO: hook inStream close
	    // these are needed before for removeListener()
	    var onVerified, onClose;
	    onVerified = function(from, to, id, isValid) {
		from = nameprep.prepare(from);
		to = nameprep.prepare(to);
		if (to !== destDomain ||
		    id != inStream.streamId)  // not for us
		    return;

		inStream.send(Server.dialbackResult(to, from, isValid));

		if (isValid && self.hasContext(to)) {
		    self.getContext(to).addInStream(from, inStream);
		} else {
		    // the connection isn't used for another domain, so
		    // closing is safe
		    inStream.send('</stream:stream>');
		    inStream.end();
		}

		outStream.removeListener('dialbackVerified', onVerified);
		outStream.removeListener('close', onClose);
	    };
	    onClose = function() {
		// outgoing connection didn't work out, tell the incoming
		// connection
		inStream.send(Server.dialbackResult(to, from, false));
	    };
	    outStream.addListener('dialbackVerified', onVerified);
	    outStream.addListener('close', onClose);
	} else {
	    inStream.error('host-unknown', to + ' is not served here');
	}
    });
};

Router.prototype.setupStream = function(stream) {
    stream.credentials = this.credentials;
    stream.maxStanzaSize = this.maxStanzaSize;
    StreamShaper.attach(stream, this.rateLimit);
    stream.setKeepAlive(true, this.keepAlive);
    stream.setTimeout(this.streamTimeout);
    stream.addListener('timeout', function() {
			   stream.error('connection-timeout');
		       });
};

/**
 * Create domain context & register a stanza listener callback
 */
Router.prototype.register = function(domain, listener) {
    domain = nameprep.prepare(domain);
    this.getContext(domain).stanzaListener = listener;
};

// TODO: unregister w/ connections teardown

Router.prototype.send = function(stanza) {
    if (stanza.root)
	stanza = stanza.root();

    // TODO: inner routing
    if (stanza.attrs && stanza.attrs.from) {
	var domain = (new JID.JID(stanza.attrs.from)).domain;
	this.getContext(domain).send(stanza);
    } else
	throw 'Sending stanza without destination';
};

Router.prototype.hasContext = function(domain) {
    return this.ctxs.hasOwnProperty(domain);
};

Router.prototype.getContext = function(domain) {
    if (this.ctxs.hasOwnProperty(domain))
	return this.ctxs[domain];
    else
	return (this.ctxs[domain] = new DomainContext(this, domain));
};

Router.prototype.verifyDialback = function(from, to, id, key, cb) {
    if (this.hasContext(to))
	this.getContext(to).verifyDialback(from, id, key, cb);
    else
	cb(false);
};

/**
 * TODO: According to XEP-0185 we should hash from, to & streamId
 */
function generateKey() {
    var r = new Buffer(16);
    for(var i = 0; i < r.length; i++) {
	r[i] = 48 + Math.floor(Math.random() * 10);  // '0'..'9'
    }
    return r.toString();
}
<commit_msg>router: refuse to send to empty JID, clarify identifiers<commit_after>var net = require('net');
var Server = require('./server');
var JID = require('./jid');
var StreamShaper = require('./../stream_shaper');
var StringPrep = require('node-stringprep').StringPrep;
var nameprep = new StringPrep('nameprep');

dbgStream = function(tag, stream) {
    stream.on('data', function(data) {
	console.log(tag + ' in: ' + data);
    });
    stream.on('error', function(e) {
	console.log(tag + ' error: ' + e.stack ? e.stack : e);
    });
    stream.on('close', function() {
	console.log(tag + ' close');
    });
    var oldSend = stream.send;
    stream.send = function(data) {
	console.log(tag + ' out: ' + data);
	oldSend.call(stream, data);
    };
};

/**
 * Represents a domain we host with connections to federated servers
 */
function DomainContext(router, domain) {
    this.router = router;
    this.domain = domain;
    this.s2sIn = {};
    this.s2sOut = {};
}

/**
 * Buffers until stream has been verified via Dialback
 */
DomainContext.prototype.send = function(stanza) {
    if (stanza.root)
	stanza = stanza.root();

    // TODO: return on empty to
    destDomain = new JID.JID(stanza.attrs.to).domain;
    var outStream = this.getOutStream(destDomain);

    if (outStream.isVerified)
	outStream.send(stanza);
    else {
	outStream.queue = outStream.queue || [];
	outStream.queue.push(stanza);
    }
};

/**
 * Does only buffer until stream is established, used for Dialback
 * communication itself.
 *
 * returns the stream
 */
DomainContext.prototype.sendRaw = function(stanza, destDomain) {
    if (stanza.root)
	stanza = stanza.root();

    var outStream = this.getOutStream(destDomain);
    var send = function() {
	outStream.send(stanza);
    };

    if (outStream.isOnline)
	send();
    else
	outStream.addListener('online', send);

    return outStream;
};

DomainContext.prototype.getOutStream = function(destDomain) {
    var self = this;

    // unfortunately we cannot use the incoming streams

    if (!destDomain) {
	throw new Error('Trying to reach empty domain');
    } else if (this.s2sOut.hasOwnProperty(destDomain)) {
	// There's one already
	return this.s2sOut[destDomain];
    } else {
	console.log("OUTGOING to " + destDomain);
	// Setup a new outgoing connection
	var outStream = Server.makeOutgoingServer(destDomain);
	this.s2sOut[destDomain] = outStream;
	dbgStream('outgoing', outStream);

	this.router.setupStream(outStream);
	this.setupStream(destDomain, outStream);

	outStream.addListener('close', function() {
	    // purge queue
	    if (outStream.queue) {
		outStream.queue.forEach(function(stanza) {
					    // do not provoke ping-pong effects
					    if (stanza.attrs.type === 'error')
						return;

					    var dest = stanza.attrs.to;
					    stanza.attrs.to = stanza.attrs.from;
					    stanza.attrs.from = dest;
					    stanza.attrs.type = 'error';
					    // TODO: add <error/> child if any programs wants to use that
					    self.receive(stanza);
					});
	    }
	    delete outStream.queue;

	    // remove from DomainContext
	    delete self.s2sOut[destDomain];
	});

	// Prepare dialback
	outStream.addListener('online', function() {
	    outStream.isOnline = true;
	    outStream.dbKey = generateKey();
	    outStream.send(Server.dialbackKey(self.domain, destDomain, outStream.dbKey));
	});
	outStream.addListener('dialbackResult', function(from, to, isValid) {
	    if (isValid) {
		outStream.isVerified = true;
		if (outStream.queue) {
		    outStream.queue.forEach(function(stanza) {
			outStream.send(stanza);
		    });
		    delete outStream.queue;
		}
	    } else {
		// we cannot do anything else with this stream that
		// failed dialback
		outStream.end();
	    }
	});

	return outStream;
    }
};

/**
 * Called by router when verification is done
 */
DomainContext.prototype.addInStream = function(srcDomain, stream) {
    var self = this;

    if (this.s2sIn.hasOwnProperty(srcDomain)) {
	// Replace old
	var oldStream = this.s2sIn[srcDomain];
	oldStream.error('conflict', 'Connection replaced');
    }

    this.setupStream(srcDomain, stream);
    stream.isOnline = true;
    stream.isVerified = true;
    stream.addListener('close', function() {
	if (self.s2sIn[srcDomain] == stream)
	    delete self.s2sIn[srcDomain];
    });
    this.s2sIn[srcDomain] = stream;
};

DomainContext.prototype.setupStream = function(domain, stream) {
    var self = this;

    stream.addListener('stanza', function(stanza) {
	// Before verified they can send whatever they want
	if (!stream.isVerified)
	    return;

	if (!(typeof stanza.attrs.from === 'string' &&
	      typeof stanza.attrs.to === 'string')) {
	    stream.error('improper-addressing');
	    return;
	}

	// Only accept 'from' attribute JIDs that have the same domain
	// that we validated the stream for
	var fromDomain = (new JID.JID(stanza.attrs.from)).domain;
	if (fromDomain !== domain) {
	    stream.error('invalid-from');
	    return;
	}

	// Only accept 'to' attribute JIDs to this DomainContext
	var toDomain = (new JID.JID(stanza.attrs.to)).domain;
	if (toDomain !== self.domain) {
	    stream.error('improper-addressing');
	    return;
	}

	self.receive(stanza);
    });
};

DomainContext.prototype.verifyDialback = function(domain, id, key, cb) {
    var self = this;
    var outStream;
    if (this.s2sOut.hasOwnProperty(domain) &&
	(outStream = this.s2sOut[domain])) {

	if (outStream.isOnline) {
	    var isValid = outStream.streamAttrs.id === id &&
			      outStream.dbKey === key;
	    cb(isValid);
	} else {
	    // Not online, wait for outStream.streamAttrs
	    outStream.addListener('online', function() {
				      // recurse
				      self.verifyDialback(domain, id, key, cb);
				  });
	    outStream.addListener('close', function() {
				      cb(false);
				  });
	}
    } else
	cb(false);
};

DomainContext.prototype.receive = function(stanza) {
    if (this.stanzaListener)
	this.stanzaListener(stanza);
};

/**
 * TODO:
 * * TLS
 */
function Router(s2sPort) {
    var self = this;
    this.ctxs = {};

    net.createServer(function(inStream) {
	console.log('INCOMING from ' + inStream.remoteAddress);
	self.acceptConnection(inStream);
    }).listen(s2sPort || 5269);
}
exports.Router = Router;

// Defaults
Router.prototype.rateLimit = 100;  // 100 KB/s, it's S2S after all
Router.prototype.maxStanzaSize = 65536;  // 64 KB, by convention
Router.prototype.keepAlive = 30 * 1000;  // 30s
Router.prototype.streamTimeout = 5 * 60 * 1000;  // 5min
Router.prototype.credentials = undefined;  // TLS credentials

// little helper, because dealing with crypto & fs gets unwieldy
Router.prototype.loadCredentials = function(keyPath, certPath) {
    var crypto = require('crypto');
    var fs = require('fs');

    var key = fs.readFileSync(keyPath, 'ascii');
    var cert = fs.readFileSync(certPath, 'ascii');

    this.credentials = crypto.createCredentials({ key: key,
						  cert: cert });
};

Router.prototype.acceptConnection = function(inStream) {
    var self = this;

    dbgStream('incoming', inStream);
    this.setupStream(inStream);
    Server.makeIncomingServer(inStream);

    // incoming server wants to verify an outgoing connection of ours
    inStream.addListener('dialbackVerify', function(from, to, id, key) {
	from = nameprep.prepare(from);
	to = nameprep.prepare(to);
	self.verifyDialback(from, to, id, key, function(isValid) {
	    inStream.send(Server.dialbackVerified(to, from, id, isValid));
	});
    });
    // incoming connection wants to get verified
    inStream.addListener('dialbackKey', function(from, to, key) {
	from = nameprep.prepare(from);
	to = nameprep.prepare(to);
	var destDomain = to;
	if (self.hasContext(to)) {
	    var ctx = self.getContext(to);
	    var outStream = ctx.sendRaw(Server.dialbackVerify(to, from, inStream.streamId, key),
					from);

	    // TODO: hook inStream close
	    // these are needed before for removeListener()
	    var onVerified, onClose;
	    onVerified = function(from, to, id, isValid) {
		from = nameprep.prepare(from);
		to = nameprep.prepare(to);
		if (to !== destDomain ||
		    id != inStream.streamId)  // not for us
		    return;

		inStream.send(Server.dialbackResult(to, from, isValid));

		if (isValid && self.hasContext(to)) {
		    self.getContext(to).addInStream(from, inStream);
		} else {
		    // the connection isn't used for another domain, so
		    // closing is safe
		    inStream.send('</stream:stream>');
		    inStream.end();
		}

		outStream.removeListener('dialbackVerified', onVerified);
		outStream.removeListener('close', onClose);
	    };
	    onClose = function() {
		// outgoing connection didn't work out, tell the incoming
		// connection
		inStream.send(Server.dialbackResult(to, from, false));
	    };
	    outStream.addListener('dialbackVerified', onVerified);
	    outStream.addListener('close', onClose);
	} else {
	    inStream.error('host-unknown', to + ' is not served here');
	}
    });
};

Router.prototype.setupStream = function(stream) {
    stream.credentials = this.credentials;
    stream.maxStanzaSize = this.maxStanzaSize;
    StreamShaper.attach(stream, this.rateLimit);
    stream.setKeepAlive(true, this.keepAlive);
    stream.setTimeout(this.streamTimeout);
    stream.addListener('timeout', function() {
			   stream.error('connection-timeout');
		       });
};

/**
 * Create domain context & register a stanza listener callback
 */
Router.prototype.register = function(domain, listener) {
    domain = nameprep.prepare(domain);
    this.getContext(domain).stanzaListener = listener;
};

// TODO: unregister w/ connections teardown

Router.prototype.send = function(stanza) {
    if (stanza.root)
	stanza = stanza.root();

    // TODO: inner routing
    if (stanza.attrs && stanza.attrs.from) {
	var domain = (new JID.JID(stanza.attrs.from)).domain;
	this.getContext(domain).send(stanza);
    } else
	throw 'Sending stanza without destination';
};

Router.prototype.hasContext = function(domain) {
    return this.ctxs.hasOwnProperty(domain);
};

Router.prototype.getContext = function(domain) {
    if (this.ctxs.hasOwnProperty(domain))
	return this.ctxs[domain];
    else
	return (this.ctxs[domain] = new DomainContext(this, domain));
};

Router.prototype.verifyDialback = function(from, to, id, key, cb) {
    if (this.hasContext(to))
	this.getContext(to).verifyDialback(from, id, key, cb);
    else
	cb(false);
};

/**
 * TODO: According to XEP-0185 we should hash from, to & streamId
 */
function generateKey() {
    var r = new Buffer(16);
    for(var i = 0; i < r.length; i++) {
	r[i] = 48 + Math.floor(Math.random() * 10);  // '0'..'9'
    }
    return r.toString();
}
<|endoftext|>


<commit_before>import CacheManager from './cacheManager.js';
import * as changeDetector from './changeDetector.js';
import Deferred from './deferred.js';

export default Pipeline;

const FAIL_BEHAVIOUR_HALT = "halt";
const FAIL_BEHAVIOUR_WARN = "warn";
const DEFAULT_PROCESSOR = "start";

function Pipeline()
{
    "use strict";

    var self = this;
    var failBehaviour = FAIL_BEHAVIOUR_WARN;
    var queue = [];
    var cache = new CacheManager();
    var isHalted = false;
    var currentlyProcessing = false;
    var history = {};

    self.processors = {};
    self.process = process;
    self.halt = halt;
    self.restart = restart;
    self.onFail = onFail;
    self.suppressConsole = false;

    ////////////////////

    function process(model, processor)
    {
        if (isHalted)
        {
            if (!self.suppressConsole)
            {
                console.error("Can't accept new process request because the pipeline is halted")
            }
            return Promise.reject("pipeline is halted");
        }

        var defer = Deferred();
        queue.push(
        {
            deferred: defer,
            model: model,
            processor: processor || DEFAULT_PROCESSOR
        });
        checkState();
        return defer.promise;
    }

    function halt()
    {
        isHalted = true;
    }

    function restart()
    {
        isHalted = false;
        queue = [];
        queue.push(
        {
            model:
            {},
            processor: cache.clear
        });
        checkState();
    }

    function checkState()
    {
        if (isHalted)
        {
            return;
        }

        if (currentlyProcessing)
        {
            return;
        }

        if (queue.length > 0)
        {
            var next = queue.shift();
            var context = {
                model: next.model,
                history: history,
                changed:
                {}
            };
            var cleanup = function()
            {
                currentlyProcessing = false;
                changeDetector.updateHistory(context);
                setTimeout(checkState, 0);
            };
            var whenDone = runProcessor(context, next.processor);
            whenDone.catch(handleError(next.deferred.reject));
            whenDone.then(cleanup, cleanup);
            whenDone.then(next.deferred.resolve, next.deferred.resolve);
        }
    }

    function handleError(reject)
    {
        return function(err)
        {
            if (failBehaviour === FAIL_BEHAVIOUR_HALT)
            {
                self.halt();
                if (!self.suppressConsole)
                {
                    console.error(err);
                }
                reject(err);
            }
            else if (failBehaviour === FAIL_BEHAVIOUR_WARN)
            {
                if (!self.suppressConsole)
                {
                    console.warn(err);
                }
            }
            else
            {
                console.error("Wait... what?");
            }
        };
    }

    function runProcessor(context, processor)
    {
        if (!processor)
        {
            throw new Error("Processor undefined");
        }
        if (isHalted)
        {
            return Promise.resolve();
        }
        var runner;
        if (typeof processor === "function")
        {
            runner = runProcessor_Function;
        }
        else if (typeof processor === "string")
        {
            runner = runProcessor_String;
        }
        else if (Array.isArray(processor))
        {
            runner = runProcessor_Array;
        }
        else if (typeof processor === "object")
        {
            runner = runProcessor_Object;
        }
        if (runner)
        {
            try
            {
                return runner(context, processor);
            }
            catch (err)
            {
                return Promise.reject(err);
            }
        }
        else
        {
            throw new Error("Not sure how to run processor", processor);
        }
    }

    function runProcessor_Function(context, processor)
    {
        return Promise.resolve(processor(
        {
            model: context.model,
            changed: context.changed,
            cache: cache.get(self, processor)
        }));
    }

    function runProcessor_String(context, processor)
    {
        var runner;
        var lname = processor.toLowerCase();
        if (context.model && context.model.processors)
        {
            runner = context.model.processors[lname];
        }
        if (!runner)
        {
            runner = self.processors[lname];
        }
        if (!runner)
        {
            throw new Error("Couldn't find processor " + lname);
        }
        return runProcessor(context, runner);
    }

    function runProcessor_Object(context, processor)
    {
        if (!processor.runs || !(typeof processor.runs === "string" || typeof processor.runs === "object" || typeof processor.runs === "function"))
        {
            throw new Error("Object based processor must have a 'runs' property containing a processor defintion");
        }
        var runThis = true;
        if (typeof processor.watches === "string")
        {
            processor.watches = [processor.watches];
        }
        if (Array.isArray(processor.watches))
        {
            runThis = changeDetector.detectChanges(processor.watches, context);
        }
        if (runThis)
        {
            return runProcessor(context, processor.runs);
        }
        else
        {
            return Promise.resolve();
        }
    }

    function runProcessor_Array(context, processor)
    {
        return new Promise(function(resolve, reject)
        {
            var temp = processor.slice();

            function processNext()
            {

                if (temp.length === 0)
                {
                    resolve();
                }
                else
                {
                    var current = runProcessor(context, temp.shift());
                    current.catch(handleError(reject));
                    current.then(processNext, processNext);
                }
            }
            processNext();
        });
    }

    function onFail(behaviour)
    {
        if (behaviour !== FAIL_BEHAVIOUR_HALT && behaviour !== FAIL_BEHAVIOUR_WARN)
        {
            throw new Error("On fail only accepts a single string value which must be exactly '" + FAIL_BEHAVIOUR_HALT + "' or '" + FAIL_BEHAVIOUR_WARN + "'");
        }
        failBehaviour = behaviour;
    }
}
<commit_msg>set currently processing flag to true when starting to process<commit_after>import CacheManager from './cacheManager.js';
import * as changeDetector from './changeDetector.js';
import Deferred from './deferred.js';

export default Pipeline;

const FAIL_BEHAVIOUR_HALT = "halt";
const FAIL_BEHAVIOUR_WARN = "warn";
const DEFAULT_PROCESSOR = "start";

function Pipeline()
{
    "use strict";

    var self = this;
    var failBehaviour = FAIL_BEHAVIOUR_WARN;
    var queue = [];
    var cache = new CacheManager();
    var isHalted = false;
    var currentlyProcessing = false;
    var history = {};

    self.processors = {};
    self.process = process;
    self.halt = halt;
    self.restart = restart;
    self.onFail = onFail;
    self.suppressConsole = false;

    ////////////////////

    function process(model, processor)
    {
        if (isHalted)
        {
            if (!self.suppressConsole)
            {
                console.error("Can't accept new process request because the pipeline is halted")
            }
            return Promise.reject("pipeline is halted");
        }

        var defer = Deferred();
        queue.push(
        {
            deferred: defer,
            model: model,
            processor: processor || DEFAULT_PROCESSOR
        });
        checkState();
        return defer.promise;
    }

    function halt()
    {
        isHalted = true;
    }

    function restart()
    {
        isHalted = false;
        queue = [];
        queue.push(
        {
            model:
            {},
            processor: cache.clear
        });
        checkState();
    }

    function checkState()
    {
        if (isHalted)
        {
            return;
        }

        if (currentlyProcessing)
        {
            return;
        }

        if (queue.length > 0)
        {
            currentlyProcessing = true;
            var next = queue.shift();
            var context = {
                model: next.model,
                history: history,
                changed:
                {}
            };
            var cleanup = function()
            {
                currentlyProcessing = false;
                changeDetector.updateHistory(context);
                setTimeout(checkState, 0);
            };
            var whenDone = runProcessor(context, next.processor);
            whenDone.catch(handleError(next.deferred.reject));
            whenDone.then(cleanup, cleanup);
            whenDone.then(next.deferred.resolve, next.deferred.resolve);
        }
    }

    function handleError(reject)
    {
        return function(err)
        {
            if (failBehaviour === FAIL_BEHAVIOUR_HALT)
            {
                self.halt();
                if (!self.suppressConsole)
                {
                    console.error(err);
                }
                reject(err);
            }
            else if (failBehaviour === FAIL_BEHAVIOUR_WARN)
            {
                if (!self.suppressConsole)
                {
                    console.warn(err);
                }
            }
            else
            {
                console.error("Wait... what?");
            }
        };
    }

    function runProcessor(context, processor)
    {
        if (!processor)
        {
            throw new Error("Processor undefined");
        }
        if (isHalted)
        {
            return Promise.resolve();
        }
        var runner;
        if (typeof processor === "function")
        {
            runner = runProcessor_Function;
        }
        else if (typeof processor === "string")
        {
            runner = runProcessor_String;
        }
        else if (Array.isArray(processor))
        {
            runner = runProcessor_Array;
        }
        else if (typeof processor === "object")
        {
            runner = runProcessor_Object;
        }
        if (runner)
        {
            try
            {
                return runner(context, processor);
            }
            catch (err)
            {
                return Promise.reject(err);
            }
        }
        else
        {
            throw new Error("Not sure how to run processor", processor);
        }
    }

    function runProcessor_Function(context, processor)
    {
        return Promise.resolve(processor(
        {
            model: context.model,
            changed: context.changed,
            cache: cache.get(self, processor)
        }));
    }

    function runProcessor_String(context, processor)
    {
        var runner;
        var lname = processor.toLowerCase();
        if (context.model && context.model.processors)
        {
            runner = context.model.processors[lname];
        }
        if (!runner)
        {
            runner = self.processors[lname];
        }
        if (!runner)
        {
            throw new Error("Couldn't find processor " + lname);
        }
        return runProcessor(context, runner);
    }

    function runProcessor_Object(context, processor)
    {
        if (!processor.runs || !(typeof processor.runs === "string" || typeof processor.runs === "object" || typeof processor.runs === "function"))
        {
            throw new Error("Object based processor must have a 'runs' property containing a processor defintion");
        }
        var runThis = true;
        if (typeof processor.watches === "string")
        {
            processor.watches = [processor.watches];
        }
        if (Array.isArray(processor.watches))
        {
            runThis = changeDetector.detectChanges(processor.watches, context);
        }
        if (runThis)
        {
            return runProcessor(context, processor.runs);
        }
        else
        {
            return Promise.resolve();
        }
    }

    function runProcessor_Array(context, processor)
    {
        return new Promise(function(resolve, reject)
        {
            var temp = processor.slice();

            function processNext()
            {

                if (temp.length === 0)
                {
                    resolve();
                }
                else
                {
                    var current = runProcessor(context, temp.shift());
                    current.catch(handleError(reject));
                    current.then(processNext, processNext);
                }
            }
            processNext();
        });
    }

    function onFail(behaviour)
    {
        if (behaviour !== FAIL_BEHAVIOUR_HALT && behaviour !== FAIL_BEHAVIOUR_WARN)
        {
            throw new Error("On fail only accepts a single string value which must be exactly '" + FAIL_BEHAVIOUR_HALT + "' or '" + FAIL_BEHAVIOUR_WARN + "'");
        }
        failBehaviour = behaviour;
    }
}
<|endoftext|>


<commit_before>/**
  Copyright 2010-2011 Mateusz Paprocki <mattpap@gmail.com>
  Copyright 2011 Christian Iversen <ci@sikkerhed.org>

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
**/
"use strict";

var $PY = {};

var py_builtins = {};

py_builtins.PY$__python3__ = false;

function bt() {
    try {
        null();
    } catch (x) {
        py_builtins.print(x.stack);
    }
}

function iterate(obj, func) {
    if (obj.PY$__class__ === undefined) {
        for (var i in obj) {
            func(obj[i]);
        };
    } else if (obj.PY$__class__ === list || obj.PY$__class__ === tuple) {
        for (var i = 0; i < obj.items.length; i++) {
            func(obj.items[i]);
        };
    } else {
        var seq = iter(obj);
        while (true) {
            try {
                func(seq.PY$next());
            } catch (exc) {
                if (exc === $PY.StopIter || $PY.isinstance(exc, py_builtins.StopIteration)) {
                    break;
                } else {
                    throw exc;
                }
            }
        }
    }
}

var __kwargs_make = function(kw, kwargs) {
    kw.__kwargs = true;
    if (kwargs !== undefined) {
        if (kwargs.PY$__class__ !== dict) {
            throw TypeError("Keyword arguments with non-standard dictionary types not supported");
        }
        for (var key in kwargs.items) {
            kw[key] = kwargs.items[key];
        };
    };
    return kw;
};

var __varargs_make = function(vr) {
    vr = tuple(vr);
    vr.__varargs = true;
    return vr;
};

var __varargs_get = function(args) {
    if (args.length && (args[args.length-1].__varargs === true)) {
        var vargs = args[args.length-1];
        args.length -= 1;
        return vargs;
    } else {
        return tuple();
    }
};

var __kwargs_get = function(args) {
    if (args.length && (args[args.length-1].__kwargs === true)) {
        delete args[args.length-1].__kwargs;
        var res = args[args.length-1];
        delete args[args.length-1];
        args.length -= 1;
        return res;
    } else {
        return [];
    }
};

var staticmethod = function(func) {
    var res = function () {
        return func.apply(null, [null].concat(Array.prototype.slice.call(arguments)));
    };
    res.__static = true;
    return res;
};

var js = function(obj) {
    /*
       Converts (recursively) a Python object to a javascript builtin object.

       In particular:

       tuple -> Array
       list -> Array
       dict -> Object

       It uses the obj._js_() if it is defined, otherwise it just returns the
       same object. It is the responsibility of _js_() to convert recursively
       the object itself.
    */
    if ((obj != null) && obj._js_ !== undefined)
        return obj._js_();
    else
        return obj;
};

var py = function(obj) {
    if (obj && obj.PY$__class__ !== undefined) {
        return obj;
    } else if (typeof obj === 'number') {
        return int(obj);
    } else if (typeof obj == 'string') {
        return str(obj);
    } else if (obj instanceof Array) {
        var res = list();
        for (var q in obj) {
          res.PY$append(py(obj[q]));
        }
        return res;
    } else {
        var res = dict();
        for (var q in obj) {
            res.PY$__setitem__(q, py(obj[q]));
        }
        return res;
    }
};

$PY.isinstance = function(obj, cls) {
    if (cls instanceof Array) {
        for (var i = 0; i < cls.length; i++) {
            var c = obj.PY$__class__;
            while (c) {
                if (c === cls[i])
                    return true;
                c = c.PY$__super__;
            }
        }

        return false;
    } else {
        var c = obj.PY$__class__;
        while (c) {
            if (c === cls)
                return true;
            c = c.PY$__super__;
        }
        return false;
    }
};
<commit_msg> + Added code to prevent __varargs_get and __kwargs_get from causing an exception if passed an undefined object<commit_after>/**
  Copyright 2010-2011 Mateusz Paprocki <mattpap@gmail.com>
  Copyright 2011 Christian Iversen <ci@sikkerhed.org>

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
**/
"use strict";

var $PY = {};

var py_builtins = {};

py_builtins.PY$__python3__ = false;

function bt() {
    try {
        null();
    } catch (x) {
        py_builtins.print(x.stack);
    }
}

function iterate(obj, func) {
    if (obj.PY$__class__ === undefined) {
        for (var i in obj) {
            func(obj[i]);
        };
    } else if (obj.PY$__class__ === list || obj.PY$__class__ === tuple) {
        for (var i = 0; i < obj.items.length; i++) {
            func(obj.items[i]);
        };
    } else {
        var seq = iter(obj);
        while (true) {
            try {
                func(seq.PY$next());
            } catch (exc) {
                if (exc === $PY.StopIter || $PY.isinstance(exc, py_builtins.StopIteration)) {
                    break;
                } else {
                    throw exc;
                }
            }
        }
    }
}

var __kwargs_make = function(kw, kwargs) {
    kw.__kwargs = true;
    if (kwargs !== undefined) {
        if (kwargs.PY$__class__ !== dict) {
            throw TypeError("Keyword arguments with non-standard dictionary types not supported");
        }
        for (var key in kwargs.items) {
            kw[key] = kwargs.items[key];
        };
    };
    return kw;
};

var __varargs_make = function(vr) {
    vr = tuple(vr);
    vr.__varargs = true;
    return vr;
};

var __varargs_get = function(args) {
    if (args.length && (args[args.length-1] !== undefined) && (args[args.length-1].__varargs === true)) {
        var vargs = args[args.length-1];
        args.length -= 1;
        return vargs;
    } else {
        return tuple();
    }
};

var __kwargs_get = function(args) {
    if (args.length && (args[args.length-1] !== undefined) && (args[args.length-1].__kwargs === true)) {
        delete args[args.length-1].__kwargs;
        var res = args[args.length-1];
        delete args[args.length-1];
        args.length -= 1;
        return res;
    } else {
        return [];
    }
};

var staticmethod = function(func) {
    var res = function () {
        return func.apply(null, [null].concat(Array.prototype.slice.call(arguments)));
    };
    res.__static = true;
    return res;
};

var js = function(obj) {
    /*
       Converts (recursively) a Python object to a javascript builtin object.

       In particular:

       tuple -> Array
       list -> Array
       dict -> Object

       It uses the obj._js_() if it is defined, otherwise it just returns the
       same object. It is the responsibility of _js_() to convert recursively
       the object itself.
    */
    if ((obj != null) && obj._js_ !== undefined)
        return obj._js_();
    else
        return obj;
};

var py = function(obj) {
    if (obj && obj.PY$__class__ !== undefined) {
        return obj;
    } else if (typeof obj === 'number') {
        return int(obj);
    } else if (typeof obj == 'string') {
        return str(obj);
    } else if (obj instanceof Array) {
        var res = list();
        for (var q in obj) {
          res.PY$append(py(obj[q]));
        }
        return res;
    } else {
        var res = dict();
        for (var q in obj) {
            res.PY$__setitem__(q, py(obj[q]));
        }
        return res;
    }
};

$PY.isinstance = function(obj, cls) {
    if (cls instanceof Array) {
        for (var i = 0; i < cls.length; i++) {
            var c = obj.PY$__class__;
            while (c) {
                if (c === cls[i])
                    return true;
                c = c.PY$__super__;
            }
        }

        return false;
    } else {
        var c = obj.PY$__class__;
        while (c) {
            if (c === cls)
                return true;
            c = c.PY$__super__;
        }
        return false;
    }
};
<|endoftext|>


<commit_before>var selftest = require('../tool-testing/selftest.js');
var Sandbox = selftest.Sandbox;
var testUtils = require('../tool-testing/test-utils.js');

var commandTimeoutSecs = testUtils.accountsCommandTimeoutSecs;
var loginTimeoutSecs = 2;

selftest.define("login", ['net'], function () {
  var s = new Sandbox;

  var run = s.run("whoami");
  run.matchErr("Not logged in");
  run.expectExit(1);

  // Username and password prompts happen on stderr so that scripts can
  // run commands that do login interactively and still save the command
  // output with the login prompts appearing in it.
  //
  // Do this twice to confirm that the login command prints a prompt
  // even if you are already logged in.
  for (var i = 0; i < 2; i++) {
    run = s.run("login");
    run.waitSecs(loginTimeoutSecs);
    run.matchErr("Username:");
    run.write("test\n");
    run.matchErr("Password:");
    run.write("testtest\n");
    run.waitSecs(commandTimeoutSecs);
    run.matchErr("Logged in as test.");
    run.expectExit(0);
  }

  // Leaving username blank, or getting the password wrong, doesn't
  // reprompt. It also doesn't log you out.
  run = s.run("login");
  run.waitSecs(loginTimeoutSecs);
  run.matchErr("Username:");
  run.write("\n");
  run.matchErr("Password:");
  run.write("whatever\n");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("failed");
  run.expectExit(1);

  run = s.run("login");
  run.waitSecs(loginTimeoutSecs);
  run.matchErr("Username:");
  run.write("test\n");
  run.matchErr("Password:");
  run.write("whatever\n");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("failed");
  run.expectExit(1);

  run = s.run('login');
  run.waitSecs(loginTimeoutSecs);
  run.matchErr("Username:");
  run.write("test\n");
  run.matchErr("Password:");
  run.write("testtest\n");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Logged in as test.");
  run.expectExit(0);

  // XXX test login by email

  run = s.run("whoami");
  run.read("test\n");
  run.expectExit(0);

  run = s.run("logout");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Logged out");
  run.expectExit(0);

  run = s.run("logout");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Not logged in");
  run.expectExit(0);

  run = s.run("whoami");
  run.matchErr("Not logged in");
  run.expectExit(1);

  // Test login failure
  run = s.run("login");
  run.waitSecs(loginTimeoutSecs);
  run.matchErr("Username:");
  run.write("test\n");
  run.matchErr("Password:");
  run.write("badpassword\n");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Login failed");
  run.expectExit(1);

  // Logging in with a capitalized username should work (usernames are
  // case-insensitive).
  run = s.run("login");
  run.waitSecs(loginTimeoutSecs);
  run.matchErr("Username:");
  run.write("TeSt\n");
  run.matchErr("Password:");
  run.write("testtest\n");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Logged in as test.");
  run.expectExit(0);

  run = s.run("logout");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Logged out");
  run.expectExit(0);

  // Logging in with a capitalized password should NOT work (can't be
  // too safe...)
  run = s.run("login");
  run.waitSecs(loginTimeoutSecs);
  run.matchErr("Username:");
  run.write("test\n");
  run.matchErr("Password:");
  run.write("TesTTesT\n");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Login failed");
  run.expectExit(1);
});
<commit_msg>Shorten login test timeouts to avoid extremely long time to failure.<commit_after>var selftest = require('../tool-testing/selftest.js');
var Sandbox = selftest.Sandbox;
var testUtils = require('../tool-testing/test-utils.js');

var commandTimeoutSecs = 10;
var loginTimeoutSecs = 2;

selftest.define("login", ['net'], function () {
  var s = new Sandbox;

  var run = s.run("whoami");
  run.matchErr("Not logged in");
  run.expectExit(1);

  // Username and password prompts happen on stderr so that scripts can
  // run commands that do login interactively and still save the command
  // output with the login prompts appearing in it.
  //
  // Do this twice to confirm that the login command prints a prompt
  // even if you are already logged in.
  for (var i = 0; i < 2; i++) {
    run = s.run("login");
    run.waitSecs(loginTimeoutSecs);
    run.matchErr("Username:");
    run.write("test\n");
    run.matchErr("Password:");
    run.write("testtest\n");
    run.waitSecs(commandTimeoutSecs);
    run.matchErr("Logged in as test.");
    run.expectExit(0);
  }

  // Leaving username blank, or getting the password wrong, doesn't
  // reprompt. It also doesn't log you out.
  run = s.run("login");
  run.waitSecs(loginTimeoutSecs);
  run.matchErr("Username:");
  run.write("\n");
  run.matchErr("Password:");
  run.write("whatever\n");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("failed");
  run.expectExit(1);

  run = s.run("login");
  run.waitSecs(loginTimeoutSecs);
  run.matchErr("Username:");
  run.write("test\n");
  run.matchErr("Password:");
  run.write("whatever\n");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("failed");
  run.expectExit(1);

  run = s.run('login');
  run.waitSecs(loginTimeoutSecs);
  run.matchErr("Username:");
  run.write("test\n");
  run.matchErr("Password:");
  run.write("testtest\n");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Logged in as test.");
  run.expectExit(0);

  // XXX test login by email

  run = s.run("whoami");
  run.read("test\n");
  run.expectExit(0);

  run = s.run("logout");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Logged out");
  run.expectExit(0);

  run = s.run("logout");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Not logged in");
  run.expectExit(0);

  run = s.run("whoami");
  run.matchErr("Not logged in");
  run.expectExit(1);

  // Test login failure
  run = s.run("login");
  run.waitSecs(loginTimeoutSecs);
  run.matchErr("Username:");
  run.write("test\n");
  run.matchErr("Password:");
  run.write("badpassword\n");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Login failed");
  run.expectExit(1);

  // Logging in with a capitalized username should work (usernames are
  // case-insensitive).
  run = s.run("login");
  run.waitSecs(loginTimeoutSecs);
  run.matchErr("Username:");
  run.write("TeSt\n");
  run.matchErr("Password:");
  run.write("testtest\n");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Logged in as test.");
  run.expectExit(0);

  run = s.run("logout");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Logged out");
  run.expectExit(0);

  // Logging in with a capitalized password should NOT work (can't be
  // too safe...)
  run = s.run("login");
  run.waitSecs(loginTimeoutSecs);
  run.matchErr("Username:");
  run.write("test\n");
  run.matchErr("Password:");
  run.write("TesTTesT\n");
  run.waitSecs(commandTimeoutSecs);
  run.matchErr("Login failed");
  run.expectExit(1);
});
<|endoftext|>


<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

const WebpackError = require("./WebpackError");

class UnsupportedFeatureWarning extends WebpackError {
	constructor(module, message, loc) {
		super(message);

		this.name = "UnsupportedFeatureWarning";
		this.module = module;
		this.loc = loc;
		this.hideStack = true;

		Error.captureStackTrace(this, this.constructor);
	}
}

module.exports = UnsupportedFeatureWarning;
<commit_msg>chore(types): add jsdoc types for UnsupportedFeatureWarning class<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

const WebpackError = require("./WebpackError");

/** @typedef {import("./Module")} Module */
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */

class UnsupportedFeatureWarning extends WebpackError {
	/**
	 * @param {Module} module module relevant to warning
	 * @param {string} message description of warning
	 * @param {DependencyLocation} loc location start and end positions of the module
	 */
	constructor(module, message, loc) {
		super(message);

		this.name = "UnsupportedFeatureWarning";
		this.module = module;
		this.loc = loc;
		this.hideStack = true;

		Error.captureStackTrace(this, this.constructor);
	}
}

module.exports = UnsupportedFeatureWarning;
<|endoftext|>


<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const Cache = require("../Cache");

/** @typedef {import("../Compiler")} Compiler */

const BUILD_DEPENDENCIES_KEY = Symbol();

class IdleFileCachePlugin {
	/**
	 * @param {TODO} strategy cache strategy
	 * @param {number} idleTimeout timeout
	 * @param {number} idleTimeoutForInitialStore initial timeout
	 */
	constructor(strategy, idleTimeout, idleTimeoutForInitialStore) {
		this.strategy = strategy;
		this.idleTimeout = idleTimeout;
		this.idleTimeoutForInitialStore = idleTimeoutForInitialStore;
	}

	/**
	 * @param {Compiler} compiler Webpack compiler
	 * @returns {void}
	 */
	apply(compiler) {
		const strategy = this.strategy;
		const idleTimeout = this.idleTimeout;
		const idleTimeoutForInitialStore = Math.min(
			idleTimeout,
			this.idleTimeoutForInitialStore
		);

		const resolvedPromise = Promise.resolve();

		/** @type {Map<string | typeof BUILD_DEPENDENCIES_KEY, () => Promise>} */
		const pendingIdleTasks = new Map();

		compiler.cache.hooks.store.tap(
			{ name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
			(identifier, etag, data) => {
				pendingIdleTasks.set(identifier, () =>
					strategy.store(identifier, etag, data)
				);
			}
		);

		compiler.cache.hooks.get.tapPromise(
			{ name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
			(identifier, etag, gotHandlers) => {
				return strategy.restore(identifier, etag).then(cacheEntry => {
					if (cacheEntry === undefined) {
						gotHandlers.push((result, callback) => {
							if (result !== undefined) {
								pendingIdleTasks.set(identifier, () =>
									strategy.store(identifier, etag, result)
								);
							}
							callback();
						});
					} else {
						return cacheEntry;
					}
				});
			}
		);

		compiler.cache.hooks.storeBuildDependencies.tap(
			{ name: "IdleFile", stage: Cache.STAGE_DISK },
			dependencies => {
				pendingIdleTasks.set(BUILD_DEPENDENCIES_KEY, () =>
					strategy.storeBuildDependencies(dependencies)
				);
			}
		);

		compiler.cache.hooks.shutdown.tapPromise(
			{ name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
			() => {
				if (idleTimer) {
					clearTimeout(idleTimer);
					idleTimer = undefined;
				}
				isIdle = false;
				const promises = Array.from(pendingIdleTasks.values()).map(fn => fn());
				pendingIdleTasks.clear();
				promises.push(currentIdlePromise);
				let promise = Promise.all(promises);
				currentIdlePromise = promise.then(() => strategy.afterAllStored());
				return currentIdlePromise;
			}
		);

		/** @type {Promise<any>} */
		let currentIdlePromise = resolvedPromise;
		let isIdle = false;
		let isInitialStore = true;
		const processIdleTasks = () => {
			if (isIdle) {
				if (pendingIdleTasks.size > 0) {
					const promises = [currentIdlePromise];
					const maxTime = Date.now() + 100;
					let maxCount = 100;
					for (const [filename, factory] of pendingIdleTasks) {
						pendingIdleTasks.delete(filename);
						promises.push(factory());
						if (maxCount-- <= 0 || Date.now() > maxTime) break;
					}
					currentIdlePromise = Promise.all(promises);
					currentIdlePromise.then(() => {
						// Allow to exit the process inbetween
						setTimeout(processIdleTasks, 0).unref();
					});
					return;
				}
				currentIdlePromise = currentIdlePromise.then(() =>
					strategy.afterAllStored()
				);
				isInitialStore = false;
			}
		};
		let idleTimer = undefined;
		compiler.cache.hooks.beginIdle.tap(
			{ name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
			() => {
				idleTimer = setTimeout(
					() => {
						idleTimer = undefined;
						isIdle = true;
						resolvedPromise.then(processIdleTasks);
					},
					isInitialStore ? idleTimeoutForInitialStore : idleTimeout
				);
				idleTimer.unref();
			}
		);
		compiler.cache.hooks.endIdle.tap(
			{ name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
			() => {
				if (idleTimer) {
					clearTimeout(idleTimer);
					idleTimer = undefined;
				}
				isIdle = false;
			}
		);
	}
}

module.exports = IdleFileCachePlugin;
<commit_msg>Fix branding violation IdleFileCachePlugin.js<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const Cache = require("../Cache");

/** @typedef {import("../Compiler")} Compiler */

const BUILD_DEPENDENCIES_KEY = Symbol();

class IdleFileCachePlugin {
	/**
	 * @param {TODO} strategy cache strategy
	 * @param {number} idleTimeout timeout
	 * @param {number} idleTimeoutForInitialStore initial timeout
	 */
	constructor(strategy, idleTimeout, idleTimeoutForInitialStore) {
		this.strategy = strategy;
		this.idleTimeout = idleTimeout;
		this.idleTimeoutForInitialStore = idleTimeoutForInitialStore;
	}

	/**
	 * @param {Compiler} compiler webpack compiler
	 * @returns {void}
	 */
	apply(compiler) {
		const strategy = this.strategy;
		const idleTimeout = this.idleTimeout;
		const idleTimeoutForInitialStore = Math.min(
			idleTimeout,
			this.idleTimeoutForInitialStore
		);

		const resolvedPromise = Promise.resolve();

		/** @type {Map<string | typeof BUILD_DEPENDENCIES_KEY, () => Promise>} */
		const pendingIdleTasks = new Map();

		compiler.cache.hooks.store.tap(
			{ name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
			(identifier, etag, data) => {
				pendingIdleTasks.set(identifier, () =>
					strategy.store(identifier, etag, data)
				);
			}
		);

		compiler.cache.hooks.get.tapPromise(
			{ name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
			(identifier, etag, gotHandlers) => {
				return strategy.restore(identifier, etag).then(cacheEntry => {
					if (cacheEntry === undefined) {
						gotHandlers.push((result, callback) => {
							if (result !== undefined) {
								pendingIdleTasks.set(identifier, () =>
									strategy.store(identifier, etag, result)
								);
							}
							callback();
						});
					} else {
						return cacheEntry;
					}
				});
			}
		);

		compiler.cache.hooks.storeBuildDependencies.tap(
			{ name: "IdleFile", stage: Cache.STAGE_DISK },
			dependencies => {
				pendingIdleTasks.set(BUILD_DEPENDENCIES_KEY, () =>
					strategy.storeBuildDependencies(dependencies)
				);
			}
		);

		compiler.cache.hooks.shutdown.tapPromise(
			{ name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
			() => {
				if (idleTimer) {
					clearTimeout(idleTimer);
					idleTimer = undefined;
				}
				isIdle = false;
				const promises = Array.from(pendingIdleTasks.values()).map(fn => fn());
				pendingIdleTasks.clear();
				promises.push(currentIdlePromise);
				let promise = Promise.all(promises);
				currentIdlePromise = promise.then(() => strategy.afterAllStored());
				return currentIdlePromise;
			}
		);

		/** @type {Promise<any>} */
		let currentIdlePromise = resolvedPromise;
		let isIdle = false;
		let isInitialStore = true;
		const processIdleTasks = () => {
			if (isIdle) {
				if (pendingIdleTasks.size > 0) {
					const promises = [currentIdlePromise];
					const maxTime = Date.now() + 100;
					let maxCount = 100;
					for (const [filename, factory] of pendingIdleTasks) {
						pendingIdleTasks.delete(filename);
						promises.push(factory());
						if (maxCount-- <= 0 || Date.now() > maxTime) break;
					}
					currentIdlePromise = Promise.all(promises);
					currentIdlePromise.then(() => {
						// Allow to exit the process inbetween
						setTimeout(processIdleTasks, 0).unref();
					});
					return;
				}
				currentIdlePromise = currentIdlePromise.then(() =>
					strategy.afterAllStored()
				);
				isInitialStore = false;
			}
		};
		let idleTimer = undefined;
		compiler.cache.hooks.beginIdle.tap(
			{ name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
			() => {
				idleTimer = setTimeout(
					() => {
						idleTimer = undefined;
						isIdle = true;
						resolvedPromise.then(processIdleTasks);
					},
					isInitialStore ? idleTimeoutForInitialStore : idleTimeout
				);
				idleTimer.unref();
			}
		);
		compiler.cache.hooks.endIdle.tap(
			{ name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
			() => {
				if (idleTimer) {
					clearTimeout(idleTimer);
					idleTimer = undefined;
				}
				isIdle = false;
			}
		);
	}
}

module.exports = IdleFileCachePlugin;
<|endoftext|>


<commit_before>var Podcast = require("podcast");
var Promise = require("bluebird");
var _ = require("lodash");
var express = require("express");
var fs = Promise.promisifyAll(require("fs"));
var id3 = require('id3js');
var path = require('path');
var id3Async = Promise.promisify(id3);
var PodcastServer = function () {

    var defaults = {
        "serverName" : "localhost",
        "port" : "3000",
        "documentRoot" : "www",
        "mediaExtensions" : [".mp3"]
    };

    var options = defaults;
    var app = express();
    var serverUrl = "http://" + options.serverName + ":" + options.port + "/";

    app.use(express.static(path.join(__dirname, options.documentRoot)));
    app.listen(options.port);
    console.log ("Listening at " + serverUrl + " ...");

    function isMediaFile(filename) {
        return _.contains(options.mediaExtensions, path.extname(filename));
    }

    function getSubDirs(root) {
        return fs.readdirAsync(root)
            .map(function getPath(fileName) {
                return path.join(root, fileName);
            })
            .filter(function(filePath) {
                return fs.statAsync(filePath).then(function(stat) {
                    stat.filePath = filePath;
                    return stat.isDirectory();
                });
            }).each(function(x) {
                return path.join(root, x);
            });
    }

    function getId3(fileName) {
        var file = {};
        file.name = path.basename(fileName);
        if (path.extname(fileName) == ".mp3") {
            file.tags = id3Async({"file": fileName, "type": id3.OPEN_LOCAL});
        }
        return file;
    }

    function getFiles(folder) {
        var fileSet = {
            "folderName": folder
        };
        return fs.readdirAsync(folder)
            .filter(isMediaFile)
            .map(function(x) {
                return path.join(folder, x);
            })
            .map(getId3)
            .then(
                function(files) {
                    fileSet.files = files;
                    return fileSet;
                }
            );
    }

    function createFeed(fileSet) {
        var dirName = fileSet.folderName;
        var feedTitle = dirName.split(path.sep)[1];
        var feedOptions = {
            title: feedTitle,
            description: feedTitle,
            feed_url: serverUrl + encodeURIComponent(feedTitle) + ".xml"
        };
        var feed = new Podcast(feedOptions);
        for (var i = 0, len = fileSet.files.length; i < len; i++) {
            var baseFileName = fileSet.files[i].name;
            var fileName = path.join(dirName, baseFileName);
            var cleanName = path.basename(baseFileName, path.extname(fileName));
            var itemOptions = {
                title: cleanName,
                description: cleanName,
                url: serverUrl + encodeURIComponent(path.join(feedTitle, cleanName) + ".html"),
                date: Date.now(),
                enclosure: {
                    url: serverUrl + encodeURIComponent(path.join(feedTitle, baseFileName)),
                    file: fileName
                }
            };
            feed.item(itemOptions);
        }
        console.log("Creating feed for " + dirName);
        var xml = feed.xml();
        fs.writeFile(dirName + ".xml", xml);
    }

    getSubDirs(options.documentRoot)
        .map(getFiles)
        .map(createFeed);

}();
<commit_msg>Don't write xml to disk, just serve it from memory<commit_after>var Podcast = require("podcast");
var Promise = require("bluebird");
var _ = require("lodash");
var express = require("express");
var fs = Promise.promisifyAll(require("fs"));
var id3 = require('id3js');
var path = require('path');
var id3Async = Promise.promisify(id3);
var PodcastServer = function () {

    var defaults = {
        "serverName" : "localhost",
        "port" : "3000",
        "documentRoot" : "public",
        "mediaExtensions" : [".mp3"]
    };

    var options = defaults;
    var app = express();
    var serverUrl = "http://" + options.serverName + ":" + options.port + "/";
    var feeds = {
        route: function (req, res) {

        },
        xml: []
    };

    app.use('/media', express.static(path.join(__dirname, options.documentRoot)));
    app.listen(options.port);
    console.log ("Listening at " + serverUrl + " ...");

    function isMediaFile(filename) {
        return _.contains(options.mediaExtensions, path.extname(filename));
    }

    function getSubDirs(root) {
        return fs.readdirAsync(root)
            .map(function getPath(fileName) {
                return path.join(root, fileName);
            })
            .filter(function(filePath) {
                return fs.statAsync(filePath).then(function(stat) {
                    stat.filePath = filePath;
                    return stat.isDirectory();
                });
            }).each(function(x) {
                return path.join(root, x);
            });
    }

    function getId3(fileName) {
        var file = {};
        file.name = path.basename(fileName);
        if (path.extname(fileName) == ".mp3") {
            file.tags = id3Async({"file": fileName, "type": id3.OPEN_LOCAL});
        }
        return file;
    }

    function getFiles(folder) {
        var fileSet = {
            "folderName": folder
        };
        return fs.readdirAsync(folder)
            .filter(isMediaFile)
            .map(function(x) {
                return path.join(folder, x);
            })
            .map(getId3)
            .then(
                function(files) {
                    fileSet.files = files;
                    return fileSet;
                }
            );
    }

    function createFeedObject(fileSet) {
        var dirName = fileSet.folderName;
        var feedTitle = dirName.split(path.sep)[1];
        var feedOptions = {
            title: feedTitle,
            description: feedTitle,
            feed_url: serverUrl + encodeURIComponent(feedTitle) + ".xml"
        };
        var feed = new Podcast(feedOptions);
        for (var i = 0, len = fileSet.files.length; i < len; i++) {
            var baseFileName = fileSet.files[i].name;
            var fileName = path.join(dirName, baseFileName);
            var cleanName = path.basename(baseFileName, path.extname(fileName));
            var itemOptions = {
                title: cleanName,
                description: cleanName,
                url: serverUrl + ['feeds', feedTitle, cleanName + ".html"].map(encodeURIComponent).join('/'),
                date: Date.now(),
                enclosure: {
                    url: serverUrl + ['media', feedTitle, baseFileName].map(encodeURIComponent).join('/'),
                    file: fileName
                }
            };
            feed.item(itemOptions);
        }
        console.log("Creating feed for " + dirName);
        var xml = feed.xml();
        return {"name": feedTitle,
                "feed": xml
               };
    }

    function routeFeeds(feedObjects) {
        var i = 0,
            length = feedObjects.length;
            router = express.Router();
        for (; i < length; i++) {
            makeRouter(feedObjects[i].name, feedObjects[i].feed);
        }
        function makeRouter(name, xml) {
            router.get('/' + encodeURIComponent(name) + ".xml", function(req, res) {
                res.set('Content-Type', 'text/xml');
                res.send(new Buffer(xml));
            });
            console.log(name);
        }
        app.use('/feeds', router);
        return feedObjects;
    }

    getSubDirs(options.documentRoot)
        .map(getFiles)
        .map(createFeedObject)
        .then(routeFeeds);

}();
<|endoftext|>


<commit_before>/**
 * Copyright JS Foundation and other contributors, http://js.foundation
 *
 * 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.
 **/

module.exports = function (RED) {
    "use strict";

    const http = require("follow-redirects").http;
    const https = require("follow-redirects").https;
    const urllib = require("url");
    const mustache = require("mustache");
    const querystring = require("querystring");
    const util = require('../lib/util.js');

    function HTTPRequest(n) {
        RED.nodes.createNode(this, n);

        var node = this;
        var nodeUrl = n.url;
        var isTemplatedUrl = (nodeUrl || "").indexOf("{{") != -1;
        var nodeMethod = n.method || "GET";
        this.ret = n.ret || "txt";

        if (RED.settings.httpRequestTimeout) {
            this.reqTimeout = parseInt(RED.settings.httpRequestTimeout) || 120000;
        } else {
            this.reqTimeout = 120000;
        }

        var prox, noprox;
        if (process.env.http_proxy != null) {
            prox = process.env.http_proxy;
        }
        if (process.env.HTTP_PROXY != null) {
            prox = process.env.HTTP_PROXY;
        }
        if (process.env.no_proxy != null) {
            noprox = process.env.no_proxy.split(",");
        }
        if (process.env.NO_PROXY != null) {
            noprox = process.env.NO_PROXY.split(",");
        }

        this.on("input", function (msg) {
            var preRequestTimestamp = process.hrtime();
            util.statusProgress("httpin.status.requesting");

            var url = nodeUrl || msg.url;
            if (msg.url && nodeUrl && (nodeUrl !== msg.url)) {
                // revert change below when warning is finally removed
                node.warn(RED._("node-red:common.errors.nooverride"));
            }
            if (isTemplatedUrl) {
                url = mustache.render(nodeUrl, msg);
            }
            if (!url) {
                node.error(RED._("node-red:httpin.errors.no-url"), msg);
                return;
            }
            // url must start https://
            if (!(url.indexOf("https://") === 0)) {
                url = "https://" + url;
            }

            var method = nodeMethod.toUpperCase() || "GET";
            if (msg.method && n.method && (n.method !== "use")) {
                // warn if override option not set
                node.warn(RED._("node-red:common.errors.nooverride"));
            }
            if (msg.method && n.method && (n.method === "use")) {
                // use the msg parameter
                method = msg.method.toUpperCase();
            }

            var opts = urllib.parse(url);
            opts.method = method;
            opts.headers = {};
            opts.port = 443;
            opts.rejectUnauthorized = false;
            opts.agent = new https.Agent({
                keepAlive: false,
                maxCachedSessions: 0,
                rejectUnauthorized: false
            });
            var ctSet = "Content-Type"; // set default camel case
            var clSet = "Content-Length";
            if (msg.headers) {
                for (var v in msg.headers) {
                    if (msg.headers.hasOwnProperty(v)) {
                        var name = v.toLowerCase();
                        if (name !== "content-type" && name !== "content-length") {
                            // only normalise the known headers used later in this
                            // function. Otherwise leave them alone.
                            name = v;
                        } else if (name === 'content-type') {
                            ctSet = v;
                        } else {
                            clSet = v;
                        }
                        opts.headers[name] = msg.headers[v];
                    }
                }
            }
            if (this.credentials && this.credentials.user) {
                opts.auth =
                    this.credentials.user +
                    ":" +
                    (this.credentials.password || "");
            }
            var payload = null;

            if (msg.payload &&
                (method == "POST" || method == "PUT" || method == "PATCH")) {
                if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
                    payload = msg.payload;
                } else if (typeof msg.payload == "number") {
                    payload = msg.payload + "";
                } else {
                    if (opts.headers['content-type'] ==
                        'application/x-www-form-urlencoded') {
                        payload = querystring.stringify(msg.payload);
                    } else {
                        payload = JSON.stringify(msg.payload);
                        if (opts.headers['content-type'] == null) {
                            opts.headers[ctSet] = "application/json";
                        }
                    }
                }
                if (opts.headers['content-length'] == null) {
                    if (Buffer.isBuffer(payload)) {
                        opts.headers[clSet] = payload.length;
                    } else {
                        opts.headers[clSet] = Buffer.byteLength(payload);
                    }
                }
            }
            // revert to user supplied Capitalisation if needed.
            if (opts.headers.hasOwnProperty('content-type') && (ctSet !==
                'content-type')) {
                opts.headers[ctSet] = opts.headers['content-type'];
                delete opts.headers['content-type'];
            }
            if (opts.headers.hasOwnProperty('content-length') && (clSet !==
                'content-length')) {
                opts.headers[clSet] = opts.headers['content-length'];
                delete opts.headers['content-length'];
            }
            var urltotest = url;
            var noproxy;
            if (noprox) {
                for (var i in noprox) {
                    if (url.indexOf(noprox[i]) !== -1) {
                        noproxy = true;
                    }
                }
            }
            if (prox && !noproxy) {
                var match = prox.match(/^(http:\/\/)?(.+)?:([0-9]+)?/i);
                if (match) {
                    //opts.protocol = "http:";
                    //opts.host = opts.hostname = match[2];
                    //opts.port = (match[3] != null ? match[3] : 80);
                    opts.headers['Host'] = opts.host;
                    var heads = opts.headers;
                    var path = opts.pathname = opts.href;
                    opts = urllib.parse(prox);
                    opts.path = opts.pathname = path;
                    opts.headers = heads;
                    opts.method = method;
                    urltotest = match[0];
                } else {
                    node.warn("Bad proxy url: " + process.env.http_proxy);
                }
            }
            var req = https.request(opts, function (res) {
                (node.ret === "bin") ? res.setEncoding('binary') : res.setEncoding(
                    'utf8');
                msg.statusCode = res.statusCode;
                msg.headers = res.headers;
                msg.responseUrl = res.responseUrl;
                msg.payload = "";

                // add the `cert`
                msg.cert = res.socket.getPeerCertificate(false);
                if (msg.cert != null) {
                    delete msg.cert.raw;
                }

                res.on('data', function (chunk) {
                    msg.payload += chunk;
                });

                res.on('end', function () {
                    if (node.metric()) {
                        // Calculate request time
                        var diff = process.hrtime(preRequestTimestamp);
                        var ms = diff[0] * 1e3 + diff[1] * 1e-6;
                        var metricRequestDurationMillis = ms.toFixed(3);
                        node.metric("duration.millis", msg,
                            metricRequestDurationMillis);
                        if (res.client && res.client.bytesRead) {
                            node.metric("size.bytes", msg, res.client.bytesRead);
                        }
                    }

                    if (node.ret === "bin") {
                        msg.payload = Buffer.from(msg.payload, "binary");
                    } else if (node.ret === "obj") {
                        try {
                            msg.payload = JSON.parse(msg.payload);
                        } catch (e) {
                            node.warn(RED._("node-red:httpin.errors.json-error"));
                        }
                    }

                    msg.authorized = res.socket.authorized;
                    node.send(msg);
                    node.status({});
                });
            });

            req.setTimeout(node.reqTimeout, function () {
                node.error(RED._(
                    "node-red:common.notification.errors.no-response"), msg);
                setTimeout(function () {
                    util.statusFail("common.notification.errors.no-response");
                }, 10);
                req.abort();
            });

            req.on('socket', function (socket) {
                socket.on('secureConnect', function () {
                    // add the `cert`
                    msg.cert = socket.getPeerCertificate(false);
                    if (msg.cert != null) {
                        delete msg.cert.raw;
                    }
                });
            });

            req.on('error', function (err) {
                node.error(err, msg);
                msg.payload = err.toString() + " : " + url;
                msg.statusCode = err.code;
                node.send(msg);
                util.statusFail(err.code);
            });

            if (payload) {
                req.write(payload);
            }
            req.end();
        });

        this.on("close", function () {
            node.status({});
        });
    }

    // !REGISTER
    RED.nodes.registerType("https eval", HTTPRequest, {
        credentials: {
            user: {
                type: "text"
            },
            password: {
                type: "password"
            }
        }
    });
};
<commit_msg>Fix bug on https-eval node<commit_after>/**
 * Copyright JS Foundation and other contributors, http://js.foundation
 *
 * 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.
 **/

module.exports = function (RED) {
    "use strict";

    const https = require("follow-redirects").https;
    const urlLib = require("url");
    const mustache = require("mustache");
    const querystring = require("querystring");
    const util = require('../lib/util.js');

    function HTTPRequest(n) {
        RED.nodes.createNode(this, n);

        var node = this;
        var nodeUrl = n.url;
        var isTemplatedUrl = (nodeUrl || "").indexOf("{{") !== -1;
        var nodeMethod = n.method || "GET";
        this.ret = n.ret || "txt";

        if (RED.settings.httpRequestTimeout) {
            this.reqTimeout = parseInt(RED.settings.httpRequestTimeout) || 120000;
        } else {
            this.reqTimeout = 120000;
        }

        var prox, noprox;
        if (process.env.http_proxy != null) {
            prox = process.env.http_proxy;
        }
        if (process.env.HTTP_PROXY != null) {
            prox = process.env.HTTP_PROXY;
        }
        if (process.env.no_proxy != null) {
            noprox = process.env.no_proxy.split(",");
        }
        if (process.env.NO_PROXY != null) {
            noprox = process.env.NO_PROXY.split(",");
        }

        this.on("input", function (msg) {
            var preRequestTimestamp = process.hrtime();
            util.statusProgress(node,"httpin.status.requesting");

            var url = nodeUrl || msg.url;
            if (msg.url && nodeUrl && (nodeUrl !== msg.url)) {
                // revert change below when warning is finally removed
                node.warn(RED._("node-red:common.errors.nooverride"));
            }
            if (isTemplatedUrl) {
                url = mustache.render(nodeUrl, msg);
            }
            if (!url) {
                node.error(RED._("node-red:httpin.errors.no-url"), msg);
                return;
            }
            // url must start https://
            if (!(url.indexOf("https://") === 0)) {
                url = "https://" + url;
            }

            var method = nodeMethod.toUpperCase() || "GET";
            if (msg.method && n.method && (n.method !== "use")) {
                // warn if override option not set
                node.warn(RED._("node-red:common.errors.nooverride"));
            }
            if (msg.method && n.method && (n.method === "use")) {
                // use the msg parameter
                method = msg.method.toUpperCase();
            }

            var opts = urlLib.parse(url);
            opts.method = method;
            opts.headers = {};
            opts.port = 443;
            opts.rejectUnauthorized = false;
            opts.agent = new https.Agent({
                keepAlive: false,
                maxCachedSessions: 0,
                rejectUnauthorized: false
            });
            var ctSet = "Content-Type"; // set default camel case
            var clSet = "Content-Length";
            if (msg.headers) {
                for (var v in msg.headers) {
                    if (msg.headers.hasOwnProperty(v)) {
                        var name = v.toLowerCase();
                        if (name !== "content-type" && name !== "content-length") {
                            // only normalise the known headers used later in this
                            // function. Otherwise leave them alone.
                            name = v;
                        } else if (name === 'content-type') {
                            ctSet = v;
                        } else {
                            clSet = v;
                        }
                        opts.headers[name] = msg.headers[v];
                    }
                }
            }
            if (this.credentials && this.credentials.user) {
                opts.auth =
                    this.credentials.user +
                    ":" +
                    (this.credentials.password || "");
            }
            var payload = null;

            if (msg.payload &&
                (method === "POST" || method === "PUT" || method === "PATCH")) {
                if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
                    payload = msg.payload;
                } else if (typeof msg.payload == "number") {
                    payload = msg.payload + "";
                } else {
                    if (opts.headers['content-type'] === 'application/x-www-form-urlencoded') {
                        payload = querystring.stringify(msg.payload);
                    } else {
                        payload = JSON.stringify(msg.payload);
                        if (opts.headers['content-type'] == null) {
                            opts.headers[ctSet] = "application/json";
                        }
                    }
                }
                if (opts.headers['content-length'] == null) {
                    if (Buffer.isBuffer(payload)) {
                        opts.headers[clSet] = payload.length;
                    } else {
                        opts.headers[clSet] = Buffer.byteLength(payload);
                    }
                }
            }
            // revert to user supplied Capitalisation if needed.
            if (opts.headers.hasOwnProperty('content-type') && (ctSet !==
                'content-type')) {
                opts.headers[ctSet] = opts.headers['content-type'];
                delete opts.headers['content-type'];
            }
            if (opts.headers.hasOwnProperty('content-length') && (clSet !==
                'content-length')) {
                opts.headers[clSet] = opts.headers['content-length'];
                delete opts.headers['content-length'];
            }
            var urltotest = url;
            var noproxy;
            if (noprox) {
                for (var i in noprox) {
                    if (url.indexOf(noprox[i]) !== -1) {
                        noproxy = true;
                    }
                }
            }
            if (prox && !noproxy) {
                var match = prox.match(/^(http:\/\/)?(.+)?:([0-9]+)?/i);
                if (match) {
                    //opts.protocol = "http:";
                    //opts.host = opts.hostname = match[2];
                    //opts.port = (match[3] != null ? match[3] : 80);
                    opts.headers['Host'] = opts.host;
                    var heads = opts.headers;
                    var path = opts.pathname = opts.href;
                    opts = urlLib.parse(prox);
                    opts.path = opts.pathname = path;
                    opts.headers = heads;
                    opts.method = method;
                    urltotest = match[0];
                } else {
                    node.warn("Bad proxy url: " + process.env.http_proxy);
                }
            }
            var req = https.request(opts, function (res) {
                (node.ret === "bin") ? res.setEncoding('binary') : res.setEncoding(
                    'utf8');
                msg.statusCode = res.statusCode;
                msg.headers = res.headers;
                msg.responseUrl = res.responseUrl;
                msg.payload = "";

                // add the `cert`
                msg.cert = res.socket.getPeerCertificate(false);
                if (msg.cert != null) {
                    delete msg.cert.raw;
                }

                res.on('data', function (chunk) {
                    msg.payload += chunk;
                });

                res.on('end', function () {
                    if (node.metric()) {
                        // Calculate request time
                        var diff = process.hrtime(preRequestTimestamp);
                        var ms = diff[0] * 1e3 + diff[1] * 1e-6;
                        var metricRequestDurationMillis = ms.toFixed(3);
                        node.metric("duration.millis", msg, metricRequestDurationMillis);
                        if (res.client && res.client.bytesRead) {
                            node.metric("size.bytes", msg, res.client.bytesRead);
                        }
                    }

                    if (node.ret === "bin") {
                        msg.payload = Buffer.from(msg.payload, "binary");
                    } else if (node.ret === "obj") {
                        try {
                            msg.payload = JSON.parse(msg.payload);
                        } catch (e) {
                            node.warn(RED._("node-red:httpin.errors.json-error"));
                        }
                    }

                    msg.authorized = res.socket.authorized;
                    node.send(msg);
                    node.status({});
                });
            });

            req.setTimeout(node.reqTimeout, function () {
                node.error(RED._(
                    "node-red:common.notification.errors.no-response"), msg);
                setTimeout(function () {
                    util.statusFail(node,"common.notification.errors.no-response");
                }, 10);
                req.abort();
            });

            req.on('socket', function (socket) {
                socket.on('secureConnect', function () {
                    // add the `cert`
                    msg.cert = socket.getPeerCertificate(false);
                    if (msg.cert != null) {
                        delete msg.cert.raw;
                    }
                });
            });

            req.on('error', function (err) {
                node.error(err, msg);
                msg.payload = err.toString() + " : " + url;
                msg.statusCode = err.code;
                node.send(msg);
                util.statusFail(node, err.code);
            });

            if (payload) {
                req.write(payload);
            }
            req.end();
        });

        this.on("close", function () {
            node.status({});
        });
    }

    // !REGISTER
    RED.nodes.registerType("https eval", HTTPRequest, {
        credentials: {
            user: {
                type: "text"
            },
            password: {
                type: "password"
            }
        }
    });
};
<|endoftext|>


<commit_before>// ==UserScript==
// @name           List Filter
// @namespace      http://niw.at/
// @description    Filtering the list elements
// @include        *
// ==/UserScript==

(function() {
try {
	Array.prototype.each = function(f) {
		for(var i = 0; i < this.length; i++) {
			f(this[i]);
		}
	}
	Array.prototype.map = function(f) {
		var result = []; //new Array(this.length);
		for(var i = 0; i < this.length; i++) {
			result[i] = f(this[i]);
		}
		return result;
	}
	Object.prototype.each = function(f) {
		for(var key in this) {
			if(!(this[key] && this[key] == this.__proto__[key])) {
				f(key, this[key]);
			}
		}
	}
	function xpath(xpath, context) {
		var result = [];
		var elements = document.evaluate(xpath, context, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
		for(var i = 0; i < elements.snapshotLength; i++) {
			result.push(elements.snapshotItem(i));
		}
		return result;
	}

	function dofilter(listtag, childtagnames) {
		return function(e) {
			var terms = this.value.split(" ");
			var collection = xpath(".//*[" + childtagnames.map(function(a){ return "(name() = '" + a + "')" }).join(" or ") + "]", listtag);
			collection.each(function(node) {
				var display = "";
				var innerText = node.innerHTML.replace(/<[^>]+>/g, "");
				for (var i = 0; i < terms.length; i++) {
					var text = innerText;
					if (terms[i].toLowerCase() == terms[i]) {
						text = text.toLowerCase();
					}
					if (text.indexOf(terms[i]) < 0) {
						display = "none";
					}
				}
				node.style.display = display;
			});
		}
	}

	var listtags = {
		"table": ["td", "th"],
		"ol": ["li"],
		"ul": ["li"],
		"dl": ["dt", "dd"]
	}
	var inputs = [];
	listtags.each(function(tagname, childtagnames) {
		xpath("//" + tagname + "[" + childtagnames.map(function(a){ return "(count(.//" + a + ") > 10)" }).join(" or ") + "]", document).each(function(listtag) {
			var input = document.createElement('INPUT');
			input.setAttribute("type", "search");
			input.setAttribute("placeholder", "Filter");
			input.setAttribute("autosave", location.href);
			input.setAttribute("results", 5);
			input.setAttribute("incremental", true);
			with (input.style) {
				fontSize = "8px";
				border = "1px solid #ddd";
				margin = "2px";
				//display = "none";
			}
			input.addEventListener("search", dofilter(listtag, childtagnames), true);
			listtag.parentNode.insertBefore(input, listtag);
			inputs.push(input);
		});
	});
	document.body.addEventListener("keydown", function(e) {
		document.body.appendChild(document.createTextNode(e.keyCode));
		if(e.ctrlKey && e.keyCode == 70) {
			inputs.each(function(input) {
				input.style.display = (input.style.display == "none") ? "" : "none";
			});
		}
	});
} catch(exception) {
	var tag = document.createElement("div");
	tag.setAttribute("style", "padding: 4px; font-size: 10px; color: #fff; border: 1px solid #f00; background: #c00;");
	tag.appendChild(document.createTextNode(exception));
	document.body.insertBefore(tag, document.body.firstChild);
}
})();
<commit_msg> * remove debug code<commit_after>// ==UserScript==
// @name           List Filter
// @namespace      http://niw.at/
// @description    Filtering the list elements
// @include        *
// ==/UserScript==

(function() {
try {
	Array.prototype.each = function(f) {
		for(var i = 0; i < this.length; i++) {
			f(this[i]);
		}
	}
	Array.prototype.map = function(f) {
		var result = []; //new Array(this.length);
		for(var i = 0; i < this.length; i++) {
			result[i] = f(this[i]);
		}
		return result;
	}
	Object.prototype.each = function(f) {
		for(var key in this) {
			if(!(this[key] && this[key] == this.__proto__[key])) {
				f(key, this[key]);
			}
		}
	}
	function xpath(xpath, context) {
		var result = [];
		var elements = document.evaluate(xpath, context, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
		for(var i = 0; i < elements.snapshotLength; i++) {
			result.push(elements.snapshotItem(i));
		}
		return result;
	}

	function dofilter(listtag, childtagnames) {
		return function(e) {
			var terms = this.value.split(" ");
			var collection = xpath(".//*[" + childtagnames.map(function(a){ return "(name() = '" + a + "')" }).join(" or ") + "]", listtag);
			collection.each(function(node) {
				var display = "";
				var innerText = node.innerHTML.replace(/<[^>]+>/g, "");
				for (var i = 0; i < terms.length; i++) {
					var text = innerText;
					if (terms[i].toLowerCase() == terms[i]) {
						text = text.toLowerCase();
					}
					if (text.indexOf(terms[i]) < 0) {
						display = "none";
					}
				}
				node.style.display = display;
			});
		}
	}

	var listtags = {
		"table": ["td", "th"],
		"ol": ["li"],
		"ul": ["li"],
		"dl": ["dt", "dd"]
	}
	var inputs = [];
	listtags.each(function(tagname, childtagnames) {
		xpath("//" + tagname + "[" + childtagnames.map(function(a){ return "(count(.//" + a + ") > 10)" }).join(" or ") + "]", document).each(function(listtag) {
			var input = document.createElement('INPUT');
			input.setAttribute("type", "search");
			input.setAttribute("placeholder", "Filter");
			input.setAttribute("autosave", location.href);
			input.setAttribute("results", 5);
			input.setAttribute("incremental", true);
			with (input.style) {
				fontSize = "8px";
				border = "1px solid #ddd";
				margin = "2px";
				//display = "none";
			}
			input.addEventListener("search", dofilter(listtag, childtagnames), true);
			listtag.parentNode.insertBefore(input, listtag);
			inputs.push(input);
		});
	});
	document.body.addEventListener("keydown", function(e) {
		// press Ctrl+F to switch filter field
		if(e.ctrlKey && e.keyCode == 70) {
			inputs.each(function(input) {
				input.style.display = (input.style.display == "none") ? "" : "none";
			});
		}
	});
} catch(exception) {
	var tag = document.createElement("div");
	tag.setAttribute("style", "padding: 4px; font-size: 10px; color: #fff; border: 1px solid #f00; background: #c00;");
	tag.appendChild(document.createTextNode(exception));
	document.body.insertBefore(tag, document.body.firstChild);
}
})();
<|endoftext|>