<commit_before>'use strict';

var R_PATH = /^(?:\w+:\/\/[^\/]*)?([\s\S]*)$/;
var STATUS_CODES = require('http').STATUS_CODES;

var Track = /** @type Track */ require('./track');

var _ = require('lodash-node');
var accepts = require('accepts');
var cookieparser = require('cookieparser');
var hasProperty = Object.prototype.hasOwnProperty;
var libUrl = require('url');
var libFastUrl = require('fast-url-parser');
var urlParse = libUrl.parse;
var urlFastParse = libFastUrl.parse;
var urlFastFormat = libFastUrl.format;
var f = require('util').format;
var proxyAddr = require('proxy-addr');

/**
 * @class Connect
 * @extends Track
 *
 * @param {Server} agent
 * @param {Logger} logger
 * @param {IncomingMessage} req
 * @param {ServerResponse} res
 * */
function Connect(agent, logger, req, res) {
    //  TODO give connect and track same signature
    Track.call(this, agent, logger);

    /**
     * @public
     * @memberOf {Connect}
     * @property
     * @type {IncomingMessage}
     * */
    this.req = req;

    /**
     * @public
     * @memberOf {Connect}
     * @property
     * @type {ServerResponse}
     * */
    this.res = res;

    /**
     * @public
     * @memberOf {Connect}
     * @property
     * @type {String}
     * */
    this.route = null;

    /**
     * @public
     * @memberOf {Connect}
     * @property
     * @type {Array<String>}
     * */
    this.matches = [];

    /**
     * @public
     * @memberOf {Connect}
     * @property
     * @type {Number}
     * */
    this.routeIndex = -1;

    /**
     * @private
     * @memberOf {Connect}
     * @property
     * @type {Object}
     * */
    this._url = null;
}

Connect.prototype = Object.create(Track.prototype);

/**
 * @public
 * @memberOf {Connect}
 * @property
 * @type {Object}
 * */
Object.defineProperty(Connect.prototype, 'url', {
    get: function () {
        if (!this._url) {
            this._url = urlParse(this.getProtocol() +
                '://' + this.getHost() + R_PATH.exec(this.req.url)[1], true);
        }
        return this._url;
    }
});
/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @constructs
 * */
Connect.prototype.constructor = Connect;

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {Boolean}
 * */
Connect.prototype.wasSent = function () {
    return this.res.headersSent || !this.req.socket.writable;
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {Boolean}
 * */
Connect.prototype.isFlushed = function () {
    return Track.prototype.isFlushed.call(this) || this.wasSent();
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {Number} [statusCode]
 *
 * @returns {Number|Connect}
 * */
Connect.prototype.status = function (statusCode) {
    if (!arguments.length) {
        return this.res.statusCode;
    }

    this.res.statusCode = statusCode;

    return this;
};

/**
 * Читает заголовок запроса или ставит заголовок ответа
 *
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String} [name]
 * @param {*} [value]
 *
 * @returns {*}
 * */
Connect.prototype.header = function (name, value) {
    var req = this.req;
    var res = this.res;

    if (!arguments.length) {
        return req.headers;
    }

    if (name && typeof name === 'object') {
        value = name;

        for (name in value) {
            if (hasProperty.call(value, name)) {
                res.setHeader(name, value[name]);
            }
        }

        return this;
    }

    if (arguments.length === 1) {
        return req.headers[String(name).toLowerCase()];
    }

    res.setHeader(name, value);

    return this;
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String} [name]
 * @param {String} [value]
 * @param {Object} [opts]
 * */
Connect.prototype.cookie = function (name, value, opts) {
    var res = this.res;
    var setCookie;
    var l = arguments.length;

    if (!l) {
        return this._getCookies();
    }

    if (l === 1) {
        return this._getCookies()[name];
    }

    setCookie = res.getHeader('Set-Cookie');
    value = cookieparser.serialize(name, value, opts);

    if (!setCookie) {
        res.setHeader('Set-Cookie', value);
    } else if (!Array.isArray(setCookie)) {
        res.setHeader('Set-Cookie', [setCookie, value]);
    } else {
        setCookie[setCookie.length] = value;
    }

    return this;
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String|Array<String>} types
 *
 * @returns {String}
 * */
Connect.prototype.acceptTypes = function (types) {
    return accepts(this.req).types(types);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String|Array<String>} encodings
 *
 * @returns {String}
 * */
Connect.prototype.acceptEncodings = function (encodings) {
    return accepts(this.req).encodings(encodings);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String|Array<String>} charsets
 *
 * @returns {String}
 * */
Connect.prototype.acceptCharsets = function (charsets) {
    return accepts(this.req).charsets(charsets);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String|Array<String>} languages
 *
 * @returns {String}
 * */
Connect.prototype.acceptLanguages = function (languages) {
    return accepts(this.req).languages(languages);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String} url
 * @param {Number} [status]
 * */
Connect.prototype.redirect = function (url, status) {
    var redirectUrl = urlFastParse(url, false, true);

    //   make URL absolute
    redirectUrl = urlFastFormat({
        // inherit protocol from incoming request if needed
        protocol: redirectUrl.protocol || this.url.protocol,
        // inherit host from incoming request if needed
        host: redirectUrl.host || this.url.host,
        // may be encoded while parsing
        pathname: decodeURIComponent(redirectUrl.pathname),
        search: redirectUrl.search,
        hash: redirectUrl.hash
    });

    this.res.statusCode = status || 302;
    this.res.setHeader('Location', redirectUrl);

    if (this.acceptTypes(['html'])) {
        redirectUrl = _.escape(redirectUrl);
        this.res.setHeader('Content-Type', 'text/html; charset=utf-8');
        this.res.end(f('%s', redirectUrl, redirectUrl));
    } else {
        this.res.setHeader('Content-Type', 'text/plain; charset=utf-8');
        this.res.end(redirectUrl);
    }

    return this;
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {*} data
 * */
Connect.prototype.send = function (data) {
    if (data === void 0) {
        return this._sendUndefined();
    }

    if (typeof data === 'string') {
        return this._sendString(data);
    }

    if (Buffer.isBuffer(data)) {
        return this._sendBuffer(data);
    }

    if (data && typeof data === 'object' && typeof data.pipe === 'function') {
        return this._sendReadable(data);
    }

    if (data instanceof Error) {
        return this._sendError(data);
    }

    return this._sendJSON(data);
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @returns {Object}
 * */
Connect.prototype._getCookies = function () {
    if (!this.__cookies) {
        this.__cookies = cookieparser.parse(this.req.headers.cookie || '');
    }

    return this.__cookies;
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 */
Connect.prototype._sendUndefined = function () {
    return this._sendString(STATUS_CODES[this.res.statusCode]);
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @param {String} data
 */
Connect.prototype._sendString = function (data) {
    var res = this.res;

    if (!res.getHeader('Content-Type')) {
        res.setHeader('Content-Type', 'text/plain');
    }

    res.removeHeader('Content-Length');
    res.setHeader('Content-Length', Buffer.byteLength(data));

    res.end(data);
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @param {Buffer} data
 */
Connect.prototype._sendBuffer = function (data) {
    var res = this.res;

    if (!res.getHeader('Content-Type')) {
        res.setHeader('Content-Type', 'application/octet-stream');
    }

    res.removeHeader('Content-Length');
    res.setHeader('Content-Length', data.length);

    res.end(data);
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @param {Stream.Readable} data
 */
Connect.prototype._sendReadable = function (data) {
    var res = this.res;

    if (!res.getHeader('Content-Type')) {
        res.setHeader('Content-Type', 'application/octet-stream');
    }

    data.pipe(res);
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @param {Error} data
 */
Connect.prototype._sendError = function (data) {
    if (typeof data.stack === 'string') {
        return this._sendString(data.stack);
    }

    return this._sendString(String(data));
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @param {*} data
 */
Connect.prototype._sendJSON = function (data) {
    var outgoing = this.res;

    data = JSON.stringify(data);

    if (!outgoing.getHeader('Content-Type')) {
        outgoing.setHeader('Content-Type', 'application/json');
    }

    outgoing.removeHeader('Content-Length');
    outgoing.setHeader('Content-Length', Buffer.byteLength(data));

    outgoing.end(data);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {String}
 * */
Connect.prototype.getIp = function () {
    return proxyAddr(this.req, this._app.params.trustProxy);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {String}
 * */
Connect.prototype.getIps = function () {
    return proxyAddr.all(this.req, this._app.params.trustProxy);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {String}
 * */
Connect.prototype.getHost = function () {
    var req = this.req;
    var connection = req.connection;
    var headers = req.headers;
    var host = headers['x-forwarded-host'];

    if (!host || !this._app.params.trustProxy(connection.remoteAddress)) {
        host = headers.host;
    }

    return host || 'localhost';
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {String}
 * */
Connect.prototype.getHostname = function () {
    var host = this.getHost();

    if (host.charAt(0) === '[') {
        return (host.match(/\[([^\[\]]+)]/) || [0, host])[1];
    }

    return (host.match(/([^:]+)/) || [0, host])[1];
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {String}
 * */
Connect.prototype.getProtocol = function () {
    var req = this.req;
    var connection = req.connection;
    var protocol = connection.encrypted ? 'https' : 'http';

    if (req.headers['x-forwarded-proto'] && this._app.params.trustProxy(connection.remoteAddress)) {
        return req.headers['x-forwarded-proto'].split(/\s*,\s*/)[0];
    }

    return protocol;
};

//  aliases
Connect.prototype.acceptEncoding = Connect.prototype.acceptEncodings;
Connect.prototype.acceptType = Connect.prototype.acceptTypes;
Connect.prototype.acceptCharset = Connect.prototype.acceptCharsets;
Connect.prototype.acceptLanguage = Connect.prototype.acceptLanguages;

module.exports = Connect;
<commit_msg>connect: Little refactor the class<commit_after>'use strict';

var R_PATH = /^(?:\w+:\/\/[^\/]*)?([\s\S]*)$/;
var STATUS_CODES = require('http').STATUS_CODES;

var Track = /** @type Track */ require('./track');

var _ = require('lodash-node');
var accepts = require('accepts');
var cookieparser = require('cookieparser');
var hasProperty = Object.prototype.hasOwnProperty;
var libFastUrl = require('fast-url-parser');
var urlFastParse = libFastUrl.parse;
var urlFastFormat = libFastUrl.format;
var f = require('util').format;
var proxyAddr = require('proxy-addr');

/**
 * @class Connect
 * @extends Track
 *
 * @param {Server} app
 * @param {Logger} logger
 * @param {IncomingMessage} req
 * @param {ServerResponse} res
 * */
function Connect(app, logger, req, res) {
    //  TODO give connect and track same signature
    Track.call(this, app, logger);

    /**
     * @public
     * @memberOf {Connect}
     * @property
     * @type {IncomingMessage}
     * */
    this.req = req;

    /**
     * @public
     * @memberOf {Connect}
     * @property
     * @type {ServerResponse}
     * */
    this.res = res;

    /**
     * @public
     * @memberOf {Connect}
     * @property
     * @type {String}
     * */
    this.route = null;

    /**
     * @public
     * @memberOf {Connect}
     * @property
     * @type {Array<String>}
     * */
    this.matches = [];

    /**
     * @public
     * @memberOf {Connect}
     * @property
     * @type {Number}
     * */
    this.routeIndex = -1;

    /**
     * @private
     * @memberOf {Connect}
     * @property
     * @type {Object}
     * */
    this._url = null;
}

Connect.prototype = Object.create(Track.prototype);

/**
 * @public
 * @memberOf {Connect}
 * @getter
 * @type {Object}
 * */
Object.defineProperty(Connect.prototype, 'url', {
    get: function () {
        if (!this._url) {
            this._url = this._getUrlObj();
        }
        return this._url;
    }
});

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @constructs
 * */
Connect.prototype.constructor = Connect;

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {Boolean}
 * */
Connect.prototype.wasSent = function () {
    return this.res.headersSent || !this.req.socket.writable;
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {Boolean}
 * */
Connect.prototype.isFlushed = function () {
    return Track.prototype.isFlushed.call(this) || this.wasSent();
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {Number} [statusCode]
 *
 * @returns {Number|Connect}
 * */
Connect.prototype.status = function (statusCode) {
    if (!arguments.length) {
        return this.res.statusCode;
    }

    this.res.statusCode = statusCode;

    return this;
};

/**
 * Читает заголовок запроса или ставит заголовок ответа
 *
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String} [name]
 * @param {*} [value]
 *
 * @returns {*}
 * */
Connect.prototype.header = function (name, value) {
    var req = this.req;
    var res = this.res;

    if (!arguments.length) {
        return req.headers;
    }

    if (name && typeof name === 'object') {
        value = name;

        for (name in value) {
            if (hasProperty.call(value, name)) {
                res.setHeader(name, value[name]);
            }
        }

        return this;
    }

    if (arguments.length === 1) {
        return req.headers[String(name).toLowerCase()];
    }

    res.setHeader(name, value);

    return this;
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String} [name]
 * @param {String} [value]
 * @param {Object} [opts]
 * */
Connect.prototype.cookie = function (name, value, opts) {
    var res = this.res;
    var setCookie;
    var l = arguments.length;

    if (!l) {
        return this._getCookies();
    }

    if (l === 1) {
        return this._getCookies()[name];
    }

    setCookie = res.getHeader('Set-Cookie');
    value = cookieparser.serialize(name, value, opts);

    if (!setCookie) {
        res.setHeader('Set-Cookie', value);
    } else if (!Array.isArray(setCookie)) {
        res.setHeader('Set-Cookie', [setCookie, value]);
    } else {
        setCookie[setCookie.length] = value;
    }

    return this;
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String|Array<String>} types
 *
 * @returns {String}
 * */
Connect.prototype.acceptTypes = function (types) {
    return accepts(this.req).types(types);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String|Array<String>} encodings
 *
 * @returns {String}
 * */
Connect.prototype.acceptEncodings = function (encodings) {
    return accepts(this.req).encodings(encodings);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String|Array<String>} charsets
 *
 * @returns {String}
 * */
Connect.prototype.acceptCharsets = function (charsets) {
    return accepts(this.req).charsets(charsets);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String|Array<String>} languages
 *
 * @returns {String}
 * */
Connect.prototype.acceptLanguages = function (languages) {
    return accepts(this.req).languages(languages);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {String} url
 * @param {Number} [status]
 * */
Connect.prototype.redirect = function (url, status) {
    var redirectUrl = urlFastParse(url, false, true);

    //   make URL absolute
    redirectUrl = urlFastFormat({
        // inherit protocol from incoming request if needed
        protocol: redirectUrl.protocol || this.url.protocol,
        // inherit host from incoming request if needed
        host: redirectUrl.host || this.url.host,
        // may be encoded while parsing
        pathname: decodeURIComponent(redirectUrl.pathname),
        search: redirectUrl.search,
        hash: redirectUrl.hash
    });

    this.res.statusCode = status || 302;
    this.res.setHeader('Location', redirectUrl);

    if (this.acceptTypes(['html'])) {
        redirectUrl = _.escape(redirectUrl);
        this.res.setHeader('Content-Type', 'text/html; charset=utf-8');
        this.res.end(f('%s', redirectUrl, redirectUrl));
    } else {
        this.res.setHeader('Content-Type', 'text/plain; charset=utf-8');
        this.res.end(redirectUrl);
    }

    return this;
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @param {*} data
 * */
Connect.prototype.send = function (data) {
    if (data === void 0) {
        return this._sendUndefined();
    }

    if (typeof data === 'string') {
        return this._sendString(data);
    }

    if (Buffer.isBuffer(data)) {
        return this._sendBuffer(data);
    }

    if (data && typeof data === 'object' && typeof data.pipe === 'function') {
        return this._sendReadable(data);
    }

    if (data instanceof Error) {
        return this._sendError(data);
    }

    return this._sendJSON(data);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {String}
 * */
Connect.prototype.getIp = function () {
    return proxyAddr(this.req, this._app.params.trustProxy);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {String}
 * */
Connect.prototype.getIps = function () {
    return proxyAddr.all(this.req, this._app.params.trustProxy);
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {String}
 * */
Connect.prototype.getHost = function () {
    var host = this.req.headers['x-forwarded-host'];

    if (host && this._isAddressTrusted()) {
        return host;
    }

    return this.req.headers.host || 'localhost';
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {String}
 * */
Connect.prototype.getHostname = function () {
    var host = this.getHost();

    if (host.charAt(0) === '[') {
        return (host.match(/\[([^\[\]]+)]/) || [0, host])[1];
    }

    return (host.match(/([^:]+)/) || [0, host])[1];
};

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {String}
 * */
Connect.prototype.getProtocol = function () {
    var headers = this.req.headers;
    var protocol = this.req.connection.encrypted ? 'https' : 'http';

    if (headers['x-forwarded-proto'] && this._isAddressTrusted()) {
        return headers['x-forwarded-proto'].split(/\s*,\s*/)[0];
    }

    return protocol;
};

//  aliases
Connect.prototype.acceptEncoding = Connect.prototype.acceptEncodings;
Connect.prototype.acceptType = Connect.prototype.acceptTypes;
Connect.prototype.acceptCharset = Connect.prototype.acceptCharsets;
Connect.prototype.acceptLanguage = Connect.prototype.acceptLanguages;

/**
 * @public
 * @memberOf {Connect}
 * @method
 *
 * @returns {Boolean}
 * */
Connect.prototype._isAddressTrusted = function () {
    return this._app.params.trustProxy(this.req.connection.remoteAddress);
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @returns {Object}
 * */
Connect.prototype._getUrlObj = function $Connect$getUrlObj() {
    return urlFastParse(this._getUrlHref(), true);
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @returns {String}
 * */
Connect.prototype._getUrlHref = function $Connect$getUrlHref() {
    return this.getProtocol() + '://' + this.getHost() + R_PATH.exec(this.req.url)[1];
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @returns {Object}
 * */
Connect.prototype._getCookies = function () {
    if (!this.__cookies) {
        this.__cookies = cookieparser.parse(this.req.headers.cookie || '');
    }

    return this.__cookies;
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 */
Connect.prototype._sendUndefined = function () {
    return this._sendString(STATUS_CODES[this.res.statusCode]);
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @param {String} data
 */
Connect.prototype._sendString = function (data) {
    var res = this.res;

    if (!res.getHeader('Content-Type')) {
        res.setHeader('Content-Type', 'text/plain');
    }

    res.removeHeader('Content-Length');
    res.setHeader('Content-Length', Buffer.byteLength(data));

    res.end(data);
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @param {Buffer} data
 */
Connect.prototype._sendBuffer = function (data) {
    var res = this.res;

    if (!res.getHeader('Content-Type')) {
        res.setHeader('Content-Type', 'application/octet-stream');
    }

    res.removeHeader('Content-Length');
    res.setHeader('Content-Length', data.length);

    res.end(data);
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @param {Stream.Readable} data
 */
Connect.prototype._sendReadable = function (data) {
    var res = this.res;

    if (!res.getHeader('Content-Type')) {
        res.setHeader('Content-Type', 'application/octet-stream');
    }

    data.pipe(res);
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @param {Error} data
 */
Connect.prototype._sendError = function (data) {
    if (typeof data.stack === 'string') {
        return this._sendString(data.stack);
    }

    return this._sendString(String(data));
};

/**
 * @protected
 * @memberOf {Connect}
 * @method
 *
 * @param {*} data
 */
Connect.prototype._sendJSON = function (data) {
    var outgoing = this.res;

    data = JSON.stringify(data);

    if (!outgoing.getHeader('Content-Type')) {
        outgoing.setHeader('Content-Type', 'application/json');
    }

    outgoing.removeHeader('Content-Length');
    outgoing.setHeader('Content-Length', Buffer.byteLength(data));

    outgoing.end(data);
};

module.exports = Connect;
<|endoftext|>


<commit_before>// -------/// ---------------1---------------------------------///////////////////2-----3--------//////// ------4----2/////5---------------------------------------------------6-----------------------------------------------------------------------------//////////////-7--5///8-------9----------//10--11---10///--12-----8//
var reg = /^([^\:\/\\\?#\[]+\:(?![^\:\/\\\?\#]*@|[\/\\][^\/\\]))?(?:\/\/|\\\\)?(?:(([^\:\/\\\?#]+)?(?:\:([^\/\\\?#]+))?)@)?(([^\/\\@\?\#\.]*?[^\/\\@\:\?\#\.\d][^\/\\@\:\?\#\.]*?|[^\/\\@\:\?\#\.]+(?:\:[\@\/\\\?#\.]*[^\d\@\:\/\\\?#\.]+|\.[^\/\\@\:\?\#]+?))?(?:(?:\:|^)(\d+))?)(((?:\/|\\|^)[^\?#]*)?(\?([^#]*))?(#[\s\S]*)?)$/;
function parseURL(url) {
    if (url === undefined || url === null) url = '';
    var [__, protocol, auth, username, password, host, hostname, port, path, pathname, search, query, hash] = reg.exec(url);
    return { protocol, auth, username, password, host, hostname, port, path, pathname, search, query, hash, href: __ };
}
module.exports = parseURL;<commit_msg>已解析部分与nodejs保持一致<commit_after>// 下图来自 https://nodejs.org/dist/latest-v16.x/docs/api/url.html#urlobjectauth
// ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
// │                                              href                                              │
// ├──────────┬──┬─────────────────────┬────────────────────────┬───────────────────────────┬───────┤
// │ protocol │  │        auth         │          host          │           path            │ hash  │
// │          │  │                     ├─────────────────┬──────┼──────────┬────────────────┤       │
// │          │  │                     │    hostname     │ port │ pathname │     search     │       │
// │          │  │                     │                 │      │          ├─┬──────────────┤       │
// │          │  │                     │                 │      │          │ │    query     │       │
// "  https:   //    user   :   pass   @ sub.example.com : 8080   /p/a/t/h  ?  query=string   #hash "
// │          │  │          │          │    hostname     │ port │          │                │       │
// │          │  │          │          ├─────────────────┴──────┤          │                │       │
// │ protocol │  │ username │ password │          host          │          │                │       │
// ├──────────┴──┼──────────┴──────────┼────────────────────────┤          │                │       │
// │   origin    │                     │         origin         │ pathname │     search     │ hash  │
// ├─────────────┴─────────────────────┴────────────────────────┴──────────┴────────────────┴───────┤
// │                                              href                                              │
// └────────────────────────────────────────────────────────────────────────────────────────────────┘

// -------/// ---------------1---------------------------------///////////////////2-----3--------//////// ------4----2/////5---------------------------------------------------6-----------------------------------------------------------------------------//////////////-7--5///8-------9----------//10--11---10/8/--12----////
var reg = /^([^\:\/\\\?#\[]+\:(?![^\:\/\\\?\#]*@|[\/\\][^\/\\]))?(?:\/\/|\\\\)?(?:(([^\:\/\\\?#]+)?(?:\:([^\/\\\?#]+))?)@)?(([^\/\\@\?\#\.]*?[^\/\\@\:\?\#\.\d][^\/\\@\:\?\#\.]*?|[^\/\\@\:\?\#\.]+(?:\:[\@\/\\\?#\.]*[^\d\@\:\/\\\?#\.]+|\.[^\/\\@\:\?\#]+?))?(?:(?:\:|^)(\d+))?)(((?:\/|\\|^)[^\?#]*)?(\?([^#]*))?)(#[\s\S]*)?$/;
function parseURL(url) {
    if (url === undefined || url === null) url = '';
    var [__, protocol, auth, username, password, host, hostname, port, path, pathname, search, query, hash] = reg.exec(url);
    return { protocol, auth, username, password, host, hostname, port, path, pathname, search, query, hash, href: __ };
}
module.exports = parseURL;<|endoftext|>


<commit_before>/**
	The MIT License (MIT)

	Copyright (c) 2014 MyChannel-Apps.de

	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.

	@author		Adrian Preuß <Bizarrus>
	@docs		http://www.mychannel-apps.de/documentation/core/channel
*/

var Background = {
	/* Strecken */
	SCALED:							0,

	/* Skaliert (Füllend, Zentriert, Mode1) */
	SCALE_FILLED_MODE1:				6,

	/* Skaliert (Füllend, Zentriert, Mode2) */
	SCALE_FILLED_MODE2:				10,

	/* Skaliert (Füllend, Zentriert, Mode3) */
	SCALE_FILLED_MODE3:				54,

	/* Skaliert (Komplett sichtbar, Zentriert) */
	SCALE_COMPLETE_CENTERED:		7,

	/* Skaliert auf Höhe (Rechts) */
	SCALE_HEIGHT_RIGHT:				61,

	/* Skaliert auf Breite (Oben) */
	SCALE_HEIGHT_TOP:				40,

	/* Skaliert auf Breite (Unten) */
	SCALE_HEIGHT_BOTTOM:			56,

	/* Gekachelt */
	TILED:							17,

	/* Gekachelt (2fache Größe) */
	TILED_ZOOM_X2:					33,

	/* Gekachelt (3fache Größe) */
	TILED_ZOOM_X3:					59,

	/* Gekachelt (Zeilenweise versetzt) */
	TILED_OFFSET_HORIZONTAL:		18,

	/* Gekachelt (Zeilenweise, 2fache Größe) */
	TILED_OFFSET_ZOOM_X2:			34,

	/* Gekachelt (Zeilenweise, 3fache Größe) */
	TILED_OFFSET_ZOOM_X3:			50,

	/* Gekachelt (Spaltenweise) */
	TILED_OFFSET_VERTICAL:			19,

	/* Gekachelt (Spaltenweise, 2fache Größe) */
	TILED_OFFSET_VERTICAL_ZOOM_X2:	34,

	/* Gekachelt (Spaltenweise, 3fache Größe) */
	TILED_OFFSET_VERTICAL_ZOOM_X3:	50,

	/* Zentriert */
	CENTERED:						20,

	/* Zentriert (2fache Größe) */
	CENTERED_ZOOM_X2:				36,

	/* Zentriert (3fache Größe) */
	CENTERED_ZOOM_X3:				52
};

var Channel = (new function Channel() {
	var _channel		= KnuddelsServer.getChannel();
	var _configuration	= _channel.getChannelConfiguration();
	var _restrictions	= _channel.getChannelRestrictions();
	var _rights			= _configuration.getChannelRights();
	var _info			= _configuration.getChannelInformation();

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getChannel
	*/
	this.getName = function getName() {
		return _channel.getChannelName();
	};

	/*
		@docs	TODO
	*/
	this.usersOnline = function usersOnline(filter) {
		return Channel.getUsers(filter).size();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getOwner
	*/
	this.getOwner = function getOwner() {
		var owners	= this.getOwners();
		var owner	= undefined;

		owners.each(function OwnersEach(user, index) {
			if(user.isOnlineInChannel()) {
				owner = user;
				return;
			}
		});

		return owner;
	};

	/*
		@docs	TODO
	*/
	this.setBackground = function setBackground(image, style, user, text) {
		Bot.private(user, '°>{bgimage}' + image + '|' + (style == undefined ? Background.SCALED : style) + '<°' + (text == undefined ? 'Das Hintergrundbild wird geändert' : text));
	};

	/*
		@docs	TODO
	*/
	this.getTopic = function getTopic() {
		return _info.getTopic();
	};

	/*
		@docs	TODO
	*/
	this.setTopic = function setTopic(text, showLive) {
		_info.setTopic(text || '', showLive || true);
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getModerators
	*/
	this.getModerators = function getModerators() {
		return _rights.getChannelModerators();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getOwners
	*/
	this.getOwners = function getOwners() {
		return _rights.getChannelOwners();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getMods
	*/
	this.getMods = function getMods() {
		return _rights.getEventModerators();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getCMutes
	*/
	this.getCMutes = function getCMutes() {
		return _restrictions.getColorMutedUsers();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getMutes
	*/
	this.getMutes = function getMutes() {
		return _restrictions.getMutedUsers();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getCLs
	*/
	this.getCLs = function getCLs() {
		return _restrictions.getLockedUsers();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_onDev
	*/
	this.onDev = function onDev() {
		return KnuddelsServer.getChatServerInfo().isTestSystem();
	};

	/*
		@docs	TODO
	*/
	this.isVideoChannel = function isVideoChannel() {
		return _channel.isVideoChannel();
	};

	/*
		@docs	TODO
	*/
	this.getServer = function getServer() {
		return KnuddelsServer.getChatServerInfo().getServerId();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getUsers
		@docs	TODO
		Example Filter:
		{
			bot:		true,		// AppBot or SystemBot
			cm:			true,
			owner:		true,
			event:		true,
			away:		true,
			developer:	true,
			include:	[], //array of uid´s or User-Objects
			exclude:	[], //array of uid´s or User-Objects
			status:		[
							Status.Newbie,
							Status.Family,
							Status.Stammi,
							Status.Ehrenz,
							Status.Admin,
							Status.Sysadmin,
							Status.Bot
						],
			gender:		[
							Gender.Male,
							Gender.Female,
							Gender.Unknown
						]
			video:		true,
			appContent: AppContent.overlayContent,
			clientType:	[ClientType.Applet],
			costum:		function(user) {
				return user.getNick().startsWith('Penis');
			}
		}
	*/
	this.getUsers = function getUsers(filter, randomOne) {
		filter 		= filter || {};
		var types	= [UserType.Human];

		if(filter.bot != undefined) {
			if(filter.bot) {
				types.push(UserType.AppBot);
				types.push(UserType.SystemBot);
			}
		}

		var users = [];
		var _users	= _channel.getOnlineUsers(types);

		// Return users if no other filters available
		if(!filter.size()) {
			return (randomOne) ? RandomOperations.getRandomObject(_users) : _users;
		}

		//_users.each(function(user, index) {
		for(var index = 0; index < _users.length; index++) {
			// Is Away
			if(filter.away != undefined && filter.away != _users[index].isAway()) {
				continue;
			}

			// Is CMuted
			if(filter.cmute != undefined && filter.cmute != _users[index].isColorMuted()) {
				continue;
			}

			// Is Muted
			if(filter.mute != undefined && filter.mute != _users[index].isMuted()) {
				continue;
			}

			// Is CMuted
			if(filter.cl != undefined && filter.cl != _users[index].isLocked()) {
				continue;
			}

			// App Developer
			if(filter.developer != undefined && filter.developer != _users[index].isAppDeveloper()) {
				continue;
			}

			// App Manager
			if(filter.manager != undefined && filter.manager != _users[index].isAppManager()) {
				continue;
			}

			// Channel Owner
			if(filter.owner != undefined && filter.owner != _users[index].isChannelOwner()) {
				continue;
			}

			// Event Moderator
			if(filter.event != undefined && filter.event != _users[index].isEventModerator()) {
				continue;
			}

			// ChannelModerator
			if(filter.cm != undefined && filter.cm != _users[index].isChannelModerator()) {
				continue;
			}

			// Status
			if(filter.status != undefined && !filter.status.exists(_users[index].getUserStatus())) {
				continue;
			}

			// Blacklist Filter
			if(filter.exclude != undefined && filter.exclude.size()) {
				var result = filter.exclude.each(function FilterExcludeEach(entry) {
					if(isTypeOf(entry) == 'User' && _users[index].equals(entry)) {
						return false;
					} else if(_users[index].getUserId() == entry) {
						return false;
					}
				});

				if(!result) {
					continue;
				}
			}

			// Whitelist Filter
			if(filter.include != undefined && filter.include.size()) {
				filter.include.each(function FilterIncludeEach(entry) {
					if(isTypeOf(entry) == 'User' && _users[index].equals(entry)) {
						return false;
					} else if(_users[index].getUserId() == entry) {
						return false;
					}
				});

				if(result) {
					continue;
				}
			}

			// Gender
			if(filter.gender != undefined && !filter.gender.exists(_users[index].getGender())) {
				continue;
			}

			// isStreamingVideo
			if(filter.video != undefined && filter.video != _users[index].isStreamingVideo()) {
				continue;
			}

			//getClientType
			if(filter.clientType != undefined && !filter.clientType.exists(_users[index].getClientType())) {
				continue;
			}

			// canSendAppContent
			if(filter.appContent != undefined && !_users[index].canSendAppContent(filter.appContent)) {
				continue;
			}

			if(filter.custom != undefined && typeof(filter.custom) == 'function' && !filter.custom.call(_users[index], [_users[index]])) {
				continue;
			}

			users.push(_users[index]);
		}
		return (randomOne) ? RandomOperations.getRandomObject(users) : users;
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_toString
	*/
	this.toString = function toString() {
		return '[KFramework Channel]';
	};
}());<commit_msg>Fixing class name problem<commit_after>/**
	The MIT License (MIT)

	Copyright (c) 2014 MyChannel-Apps.de

	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.

	@author		Adrian Preuß <Bizarrus>
	@docs		http://www.mychannel-apps.de/documentation/core/channel
*/

var Background = {
	/* Strecken */
	SCALED:							0,

	/* Skaliert (Füllend, Zentriert, Mode1) */
	SCALE_FILLED_MODE1:				6,

	/* Skaliert (Füllend, Zentriert, Mode2) */
	SCALE_FILLED_MODE2:				10,

	/* Skaliert (Füllend, Zentriert, Mode3) */
	SCALE_FILLED_MODE3:				54,

	/* Skaliert (Komplett sichtbar, Zentriert) */
	SCALE_COMPLETE_CENTERED:		7,

	/* Skaliert auf Höhe (Rechts) */
	SCALE_HEIGHT_RIGHT:				61,

	/* Skaliert auf Breite (Oben) */
	SCALE_HEIGHT_TOP:				40,

	/* Skaliert auf Breite (Unten) */
	SCALE_HEIGHT_BOTTOM:			56,

	/* Gekachelt */
	TILED:							17,

	/* Gekachelt (2fache Größe) */
	TILED_ZOOM_X2:					33,

	/* Gekachelt (3fache Größe) */
	TILED_ZOOM_X3:					59,

	/* Gekachelt (Zeilenweise versetzt) */
	TILED_OFFSET_HORIZONTAL:		18,

	/* Gekachelt (Zeilenweise, 2fache Größe) */
	TILED_OFFSET_ZOOM_X2:			34,

	/* Gekachelt (Zeilenweise, 3fache Größe) */
	TILED_OFFSET_ZOOM_X3:			50,

	/* Gekachelt (Spaltenweise) */
	TILED_OFFSET_VERTICAL:			19,

	/* Gekachelt (Spaltenweise, 2fache Größe) */
	TILED_OFFSET_VERTICAL_ZOOM_X2:	34,

	/* Gekachelt (Spaltenweise, 3fache Größe) */
	TILED_OFFSET_VERTICAL_ZOOM_X3:	50,

	/* Zentriert */
	CENTERED:						20,

	/* Zentriert (2fache Größe) */
	CENTERED_ZOOM_X2:				36,

	/* Zentriert (3fache Größe) */
	CENTERED_ZOOM_X3:				52
};

var Channel = (new function() {
	var _channel		= KnuddelsServer.getChannel();
	var _configuration	= _channel.getChannelConfiguration();
	var _restrictions	= _channel.getChannelRestrictions();
	var _rights			= _configuration.getChannelRights();
	var _info			= _configuration.getChannelInformation();

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getChannel
	*/
	this.getName = function getName() {
		return _channel.getChannelName();
	};

	/*
		@docs	TODO
	*/
	this.usersOnline = function usersOnline(filter) {
		return Channel.getUsers(filter).size();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getOwner
	*/
	this.getOwner = function getOwner() {
		var owners	= this.getOwners();
		var owner	= undefined;

		owners.each(function OwnersEach(user, index) {
			if(user.isOnlineInChannel()) {
				owner = user;
				return;
			}
		});

		return owner;
	};

	/*
		@docs	TODO
	*/
	this.setBackground = function setBackground(image, style, user, text) {
		Bot.private(user, '°>{bgimage}' + image + '|' + (style == undefined ? Background.SCALED : style) + '<°' + (text == undefined ? 'Das Hintergrundbild wird geändert' : text));
	};

	/*
		@docs	TODO
	*/
	this.getTopic = function getTopic() {
		return _info.getTopic();
	};

	/*
		@docs	TODO
	*/
	this.setTopic = function setTopic(text, showLive) {
		_info.setTopic(text || '', showLive || true);
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getModerators
	*/
	this.getModerators = function getModerators() {
		return _rights.getChannelModerators();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getOwners
	*/
	this.getOwners = function getOwners() {
		return _rights.getChannelOwners();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getMods
	*/
	this.getMods = function getMods() {
		return _rights.getEventModerators();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getCMutes
	*/
	this.getCMutes = function getCMutes() {
		return _restrictions.getColorMutedUsers();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getMutes
	*/
	this.getMutes = function getMutes() {
		return _restrictions.getMutedUsers();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getCLs
	*/
	this.getCLs = function getCLs() {
		return _restrictions.getLockedUsers();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_onDev
	*/
	this.onDev = function onDev() {
		return KnuddelsServer.getChatServerInfo().isTestSystem();
	};

	/*
		@docs	TODO
	*/
	this.isVideoChannel = function isVideoChannel() {
		return _channel.isVideoChannel();
	};

	/*
		@docs	TODO
	*/
	this.getServer = function getServer() {
		return KnuddelsServer.getChatServerInfo().getServerId();
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_getUsers
		@docs	TODO
		Example Filter:
		{
			bot:		true,		// AppBot or SystemBot
			cm:			true,
			owner:		true,
			event:		true,
			away:		true,
			developer:	true,
			include:	[], //array of uid´s or User-Objects
			exclude:	[], //array of uid´s or User-Objects
			status:		[
							Status.Newbie,
							Status.Family,
							Status.Stammi,
							Status.Ehrenz,
							Status.Admin,
							Status.Sysadmin,
							Status.Bot
						],
			gender:		[
							Gender.Male,
							Gender.Female,
							Gender.Unknown
						]
			video:		true,
			appContent: AppContent.overlayContent,
			clientType:	[ClientType.Applet],
			costum:		function(user) {
				return user.getNick().startsWith('Penis');
			}
		}
	*/
	this.getUsers = function getUsers(filter, randomOne) {
		filter 		= filter || {};
		var types	= [UserType.Human];

		if(filter.bot != undefined) {
			if(filter.bot) {
				types.push(UserType.AppBot);
				types.push(UserType.SystemBot);
			}
		}

		var users = [];
		var _users	= _channel.getOnlineUsers(types);

		// Return users if no other filters available
		if(!filter.size()) {
			return (randomOne) ? RandomOperations.getRandomObject(_users) : _users;
		}

		//_users.each(function(user, index) {
		for(var index = 0; index < _users.length; index++) {
			// Is Away
			if(filter.away != undefined && filter.away != _users[index].isAway()) {
				continue;
			}

			// Is CMuted
			if(filter.cmute != undefined && filter.cmute != _users[index].isColorMuted()) {
				continue;
			}

			// Is Muted
			if(filter.mute != undefined && filter.mute != _users[index].isMuted()) {
				continue;
			}

			// Is CMuted
			if(filter.cl != undefined && filter.cl != _users[index].isLocked()) {
				continue;
			}

			// App Developer
			if(filter.developer != undefined && filter.developer != _users[index].isAppDeveloper()) {
				continue;
			}

			// App Manager
			if(filter.manager != undefined && filter.manager != _users[index].isAppManager()) {
				continue;
			}

			// Channel Owner
			if(filter.owner != undefined && filter.owner != _users[index].isChannelOwner()) {
				continue;
			}

			// Event Moderator
			if(filter.event != undefined && filter.event != _users[index].isEventModerator()) {
				continue;
			}

			// ChannelModerator
			if(filter.cm != undefined && filter.cm != _users[index].isChannelModerator()) {
				continue;
			}

			// Status
			if(filter.status != undefined && !filter.status.exists(_users[index].getUserStatus())) {
				continue;
			}

			// Blacklist Filter
			if(filter.exclude != undefined && filter.exclude.size()) {
				var result = filter.exclude.each(function FilterExcludeEach(entry) {
					if(isTypeOf(entry) == 'User' && _users[index].equals(entry)) {
						return false;
					} else if(_users[index].getUserId() == entry) {
						return false;
					}
				});

				if(!result) {
					continue;
				}
			}

			// Whitelist Filter
			if(filter.include != undefined && filter.include.size()) {
				filter.include.each(function FilterIncludeEach(entry) {
					if(isTypeOf(entry) == 'User' && _users[index].equals(entry)) {
						return false;
					} else if(_users[index].getUserId() == entry) {
						return false;
					}
				});

				if(result) {
					continue;
				}
			}

			// Gender
			if(filter.gender != undefined && !filter.gender.exists(_users[index].getGender())) {
				continue;
			}

			// isStreamingVideo
			if(filter.video != undefined && filter.video != _users[index].isStreamingVideo()) {
				continue;
			}

			//getClientType
			if(filter.clientType != undefined && !filter.clientType.exists(_users[index].getClientType())) {
				continue;
			}

			// canSendAppContent
			if(filter.appContent != undefined && !_users[index].canSendAppContent(filter.appContent)) {
				continue;
			}

			if(filter.custom != undefined && typeof(filter.custom) == 'function' && !filter.custom.call(_users[index], [_users[index]])) {
				continue;
			}

			users.push(_users[index]);
		}
		return (randomOne) ? RandomOperations.getRandomObject(users) : users;
	};

	/*
		@docs	http://www.mychannel-apps.de/documentation/Channel_toString
	*/
	this.toString = function toString() {
		return '[KFramework Channel]';
	};
}());
<|endoftext|>


<commit_before>// window.Popcorn.version = 1.5.6
// http://popcornjs.org/code/dist/popcorn-complete.min.js
// window.SC._version = 2.0.0
// http://connect.soundcloud.com/sdk-2.0.0.js
//
(function(window, document, version, callback) { // http://stackoverflow.com/questions/2170439/how-to-embed-javascript-widget-that-depends-on-jquery-into-an-unknown-environmen
    var loaded_j = false;
    var loaded_p = false;
    var loaded_s = false;

    // document.head not standard before HTML5
    var insertionPoint = document.head || document.getElementsByTagName('head').item(0) || document.documentElement.childNodes[0];

    function cmp_vers(v1, v2) {
        var a1 = v1.split('.');
        var a2 = v2.split('.');
        for(var i = 0; i < Math.min(a1.length, a2.length); i++) {
            var n1 = parseInt(a1[i]);
            var n2 = parseInt(a2[i]);
            var d = n1 - n2;
            if(d) {
                return d;
            }
        }

        return(a1.length - a2.length);
    }

    function load_jquery(version, cb) {
        var js, d;
        if (!(js = window.jQuery) || cmp_vers(version, js.fn.jquery) > 0 || cb(js)) {
            var script = document.createElement("script");
            script.type = "text/javascript";
            script.src = "http://code.jquery.com/jquery-1.9.1.min.js";
            script.onload = script.onreadystatechange = function() {
                if(!loaded_j && (!(d = this.readyState) || d == "loaded" || d == "complete")) {
                    js = window.jQuery.noConflict(1);
                    cb(js, loaded_j = true);
                    js(script).remove();
                }
            };
            insertionPoint.appendChild(script);
        }
    }

    function load_popcorn(j, version, cb) {
        var js, d, new_js;
        if(!(js = window.Popcorn) || cmp_vers(version, js.version) > 0 || cb(js)) {
            var script = document.createElement("script");
            script.type = "text/javascript";
            script.src = "http://popcornjs.org/code/dist/popcorn-complete.min.js";
            script.onload = script.onreadystatechange = function() {
                if(!loaded_p && (!(d = this.readyState) || d == "loaded" || d == "complete")) {
                    new_js = window.Popcorn;
                    if(js) {
                        window.Popcorn = js;
                    }
                    cb(new_js, loaded_p = true);
                    j(script).remove();
                }
            };
            insertionPoint.appendChild(script);
        }
    }

    // Loading player api initializes incomplete version of window.SC
    function load_soundcloud(j, version, cb) {
        var js, d;
        if(!(js = window.SC) || !js.Dialog || cmp_vers(version, js._version) > 0 || cb(js)) {
            var script = document.createElement("script");
            script.type = "text/javascript";
            script.src = "http://connect.soundcloud.com/sdk-2.0.0.js";
            script.onload = script.onreadystatechange = function() {
                if(!loaded_s && (!(d = this.readyState) || d == "loaded" || d == "complete")) {
                    cb(window.SC, loaded_s = true);
                    j(script).remove();
                }
            };
            insertionPoint.appendChild(script);
        }
    }

    load_jquery(version, function(j) {
        load_popcorn(j, "1.5.6", function(p) {
            load_soundcloud(j, "2.0.0", function(s) {
               callback(j, p, s);
            });
        });
    });

})(window, document, "1.3", function($, $Popcorn, $SoundCloud) {
    $(document).ready(function () {
        var SOUNDCITE_CONFIG = {
            update_playing_element: function(el, percentage) {
                $(el).css({
                    'background' : '-webkit-linear-gradient(left, rgba(0,0,0,.15)' + percentage + '%, rgba(0,0,0,.05)' + (percentage + 1) + '%)',
                    'background' : 'linear-gradient(to right, rgba(0,0,0,.15)' + percentage + '%, rgba(0,0,0,.05)' + (percentage + 1) + '%)'
                });
            }
        }
        $.extend(SOUNDCITE_CONFIG, window.SOUNDCITE_CONFIG)
        // global vars
        window.soundcite = {};

        // check for mobile
        if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
            soundcite.mobile = true;
        } else {
            soundcite.mobile = false;
        }

        var clips = [];
        var $audio = $('

');

        $('body').append($audio);

        // initialize SoundCloud SDK
        $SoundCloud.initialize({
            client_id: "5ba7fd66044a60db41a97cb9d924996a",
        });

        // borrowing underscore.js bind function
        var bind = function(func, context) {
            var slice = Array.prototype.slice;
            var args = slice.call(arguments, 2);
            return function() {
              return func.apply(context, args.concat(slice.call(arguments)));
            };
        };

        // pause all playing clips. Optionally pass a clip as an argument which
        // should not be paused, for the case that this is triggered from a
        // click handler.
        function pause_all_clips(except_clip){
            for(var i = 0; i < clips.length; i++) {
                if(clips[i].playing) {
                    if (!except_clip || except_clip.el !== clips[i].el) {
                        clips[i].pause();
                    }
                }
            }
        }

// Clip
        function Clip(el) {
            this.el = el;
            this.$el = $(this.el);
            this.start = el.attributes['data-start'].value || 0;        // ms
            this.end = el.attributes['data-end'].value;                 // ms
            this.playing = false;
            this.sound = null;                          // implement in subclass

            clips.push(this);   // keep track of this
        }

        Clip.prototype.sound_loaded = function() {
            this.$el.click(bind(this.click_handler, this));
            this.$el.addClass('soundcite-loaded soundcite-play');
        }

        Clip.prototype.pause = function() {
            this.$el.removeClass('soundcite-pause');
            this.$el.addClass('soundcite-play');
            this.pause_sound();                         // implement in subclass
            this.playing = false;
        }

        Clip.prototype.stop = function() {
            this.$el.removeClass('soundcite-pause');
            this.$el.addClass('soundcite-play');
            this.stop_sound();                          // implement in subclass
            this.playing = false;
        }

        Clip.prototype.track_progress = function() {
            var totalTime = this.end - this.start;
            var position = this.sound_position();       // implement in subclass
            var relative_position = position - this.start;
            var percentage = (relative_position * 100) / totalTime;
            SOUNDCITE_CONFIG.update_playing_element(this.el, percentage);
        }

        Clip.prototype.click_handler = function() {
            pause_all_clips(this);

            if(this.playing) {
                this.pause();
            } else {
                this.play();                            // implement in subclass
            }
        }

        function SoundCloudClip(el) {
            Clip.apply(this, Array.prototype.slice.call(arguments));

            this.id = el.attributes['data-id'].value;

            $SoundCloud.stream(this.id, bind(function(sound) {
                this.sound = sound;

                this.sound._player.on("positionChange", bind(function(pos) {
                    this.track_progress();

                    if(pos > this.end) {
                        this.stop();
                    }
                }, this));

               this.sound_loaded();
            }, this));
        }
        SoundCloudClip.prototype = Object.create(Clip.prototype);

        SoundCloudClip.prototype.sound_position = function() {
            return this.sound.getCurrentPosition();
        }

        SoundCloudClip.prototype.pause_sound = function() {
            this.sound.pause();
        }

        SoundCloudClip.prototype.stop_sound = function() {
            this.sound.stop();
        }

        SoundCloudClip.prototype.play = function() {
            var pos = this.sound_position();

            if(pos < this.start || pos >= this.end) {
                this.sound.seek(this.start);
            }

            this.$el.removeClass('soundcite-play');
            this.$el.addClass('soundcite-pause');

            this.sound.play();
            this.playing = true;
        }

// Popcorn Clip
        function PopcornClip(el) {
            Clip.apply(this, Array.prototype.slice.call(arguments));

            this.id = 'soundcite-audio-'+clips.length;
            this.url = el.attributes['data-url'].value;

            // convert to ms to secs
            this.start = Math.floor(this.start / 1000);
            this.end = Math.floor(this.end / 1000);

            $audio.append('<audio id="'+this.id+'" src="'+this.url+'" preload="true"></audio>');
            this.sound = $Popcorn('#'+this.id, {'frameAnimation': true});

            // Safari iOS Audio streams cannot be loaded unless triggered by a
            // user event, so load in play_sound via click for mobile
            this.sound.on('loadeddata', bind(function() {
                if(!this.end) {
                    this.end = this.sound.duration();
                }
                this.sound.cue(this.end, bind(this.stop, this));

                if(!soundcite.mobile) {
                    this.sound_loaded();
                }
            }, this));

            if(soundcite.mobile) {
                this.sound_loaded();
            } else if(this.sound.readyState() > 1) {
                this.sound_loaded();
            }
        }
        PopcornClip.prototype = Object.create(Clip.prototype);

        PopcornClip.prototype.sound_position = function() {
            return this.sound.currentTime();
        }

        PopcornClip.prototype.pause_sound = function() {
            this.sound.pause();
            this.sound.off('timeupdate');
        }

        PopcornClip.prototype.stop_sound = function() {
            this.sound.pause();
            this.sound.off('timeupdate');
        }

        PopcornClip.prototype._play_sound = function() {
            this.$el.removeClass('soundcite-loading soundcite-play');
            this.$el.addClass('soundcite-pause');
            this.sound.play();
            this.playing = true;

            this.sound.on('timeupdate', bind(this.track_progress, this));
            this.sound.on('ended', bind(this.stop, this));
        }

        PopcornClip.prototype.play_sound = function() {
            var pos = this.sound.roundTime();

            if(pos < this.start || pos >= this.end) {
                this.sound.on('seeked', bind(function() {
                    this.sound.off('seeked');
                    this._play_sound();
                }, this));

                this.sound.currentTime(this.start);
            } else {
                this._play_sound();
            }
        }

        PopcornClip.prototype.play = function() {
            if(soundcite.mobile) {
                this.$el.removeClass('soundcite-play');
                this.$el.addClass('soundcite-loading');

                if(this.sound.readyState() > 1) {
                    this.play_sound();
                } else {
                    this.sound.on('canplaythrough',bind(function() {
                        this.play_sound();
                    }, this));

                    $('#'+this.id)[0].load();
                }
            } else {
                this.play_sound();
            }
        }

// set up clips array
        var soundcite_array = $('.soundcite');

        for(var i = 0; i < soundcite_array.length; i++) {
            var el = soundcite_array[i];
            if(el.hasAttribute('data-url')) {
                new PopcornClip(el);
            } else { //if(!soundcite.mobile) {
                new SoundCloudClip(el);
            }
        }

        soundcite.Clip = Clip;
        soundcite.SoundCloudClip = SoundCloudClip;
        soundcite.PopcornClip = PopcornClip;
        soundcite.clips = clips;    // keep track of clips
        soundcite.pause_all_clips = pause_all_clips;
    });
});
<commit_msg>Protocol-relative URL<commit_after>// window.Popcorn.version = 1.5.6
// http://popcornjs.org/code/dist/popcorn-complete.min.js
// window.SC._version = 2.0.0
// http://connect.soundcloud.com/sdk-2.0.0.js
//
(function(window, document, version, callback) { // http://stackoverflow.com/questions/2170439/how-to-embed-javascript-widget-that-depends-on-jquery-into-an-unknown-environmen
    var loaded_j = false;
    var loaded_p = false;
    var loaded_s = false;

    // document.head not standard before HTML5
    var insertionPoint = document.head || document.getElementsByTagName('head').item(0) || document.documentElement.childNodes[0];

    function cmp_vers(v1, v2) {
        var a1 = v1.split('.');
        var a2 = v2.split('.');
        for(var i = 0; i < Math.min(a1.length, a2.length); i++) {
            var n1 = parseInt(a1[i]);
            var n2 = parseInt(a2[i]);
            var d = n1 - n2;
            if(d) {
                return d;
            }
        }

        return(a1.length - a2.length);
    }

    function load_jquery(version, cb) {
        var js, d;
        if (!(js = window.jQuery) || cmp_vers(version, js.fn.jquery) > 0 || cb(js)) {
            var script = document.createElement("script");
            script.type = "text/javascript";
            script.src = "//code.jquery.com/jquery-1.9.1.min.js";
            script.onload = script.onreadystatechange = function() {
                if(!loaded_j && (!(d = this.readyState) || d == "loaded" || d == "complete")) {
                    js = window.jQuery.noConflict(1);
                    cb(js, loaded_j = true);
                    js(script).remove();
                }
            };
            insertionPoint.appendChild(script);
        }
    }

    function load_popcorn(j, version, cb) {
        var js, d, new_js;
        if(!(js = window.Popcorn) || cmp_vers(version, js.version) > 0 || cb(js)) {
            var script = document.createElement("script");
            script.type = "text/javascript";
            script.src = "http://popcornjs.org/code/dist/popcorn-complete.min.js"; // no SSL version of this, will self-host
            script.onload = script.onreadystatechange = function() {
                if(!loaded_p && (!(d = this.readyState) || d == "loaded" || d == "complete")) {
                    new_js = window.Popcorn;
                    if(js) {
                        window.Popcorn = js;
                    }
                    cb(new_js, loaded_p = true);
                    j(script).remove();
                }
            };
            insertionPoint.appendChild(script);
        }
    }

    // Loading player api initializes incomplete version of window.SC
    function load_soundcloud(j, version, cb) {
        var js, d;
        if(!(js = window.SC) || !js.Dialog || cmp_vers(version, js._version) > 0 || cb(js)) {
            var script = document.createElement("script");
            script.type = "text/javascript";
            script.src = "//connect.soundcloud.com/sdk-2.0.0.js";
            script.onload = script.onreadystatechange = function() {
                if(!loaded_s && (!(d = this.readyState) || d == "loaded" || d == "complete")) {
                    cb(window.SC, loaded_s = true);
                    j(script).remove();
                }
            };
            insertionPoint.appendChild(script);
        }
    }

    load_jquery(version, function(j) {
        load_popcorn(j, "1.5.6", function(p) {
            load_soundcloud(j, "2.0.0", function(s) {
               callback(j, p, s);
            });
        });
    });

})(window, document, "1.3", function($, $Popcorn, $SoundCloud) {
    $(document).ready(function () {
        var SOUNDCITE_CONFIG = {
            update_playing_element: function(el, percentage) {
                $(el).css({
                    'background' : '-webkit-linear-gradient(left, rgba(0,0,0,.15)' + percentage + '%, rgba(0,0,0,.05)' + (percentage + 1) + '%)',
                    'background' : 'linear-gradient(to right, rgba(0,0,0,.15)' + percentage + '%, rgba(0,0,0,.05)' + (percentage + 1) + '%)'
                });
            }
        }
        $.extend(SOUNDCITE_CONFIG, window.SOUNDCITE_CONFIG)
        // global vars
        window.soundcite = {};

        // check for mobile
        if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
            soundcite.mobile = true;
        } else {
            soundcite.mobile = false;
        }

        var clips = [];
        var $audio = $('

');

        $('body').append($audio);

        // initialize SoundCloud SDK
        $SoundCloud.initialize({
            client_id: "5ba7fd66044a60db41a97cb9d924996a",
        });

        // borrowing underscore.js bind function
        var bind = function(func, context) {
            var slice = Array.prototype.slice;
            var args = slice.call(arguments, 2);
            return function() {
              return func.apply(context, args.concat(slice.call(arguments)));
            };
        };

        // pause all playing clips. Optionally pass a clip as an argument which
        // should not be paused, for the case that this is triggered from a
        // click handler.
        function pause_all_clips(except_clip){
            for(var i = 0; i < clips.length; i++) {
                if(clips[i].playing) {
                    if (!except_clip || except_clip.el !== clips[i].el) {
                        clips[i].pause();
                    }
                }
            }
        }

// Clip
        function Clip(el) {
            this.el = el;
            this.$el = $(this.el);
            this.start = el.attributes['data-start'].value || 0;        // ms
            this.end = el.attributes['data-end'].value;                 // ms
            this.playing = false;
            this.sound = null;                          // implement in subclass

            clips.push(this);   // keep track of this
        }

        Clip.prototype.sound_loaded = function() {
            this.$el.click(bind(this.click_handler, this));
            this.$el.addClass('soundcite-loaded soundcite-play');
        }

        Clip.prototype.pause = function() {
            this.$el.removeClass('soundcite-pause');
            this.$el.addClass('soundcite-play');
            this.pause_sound();                         // implement in subclass
            this.playing = false;
        }

        Clip.prototype.stop = function() {
            this.$el.removeClass('soundcite-pause');
            this.$el.addClass('soundcite-play');
            this.stop_sound();                          // implement in subclass
            this.playing = false;
        }

        Clip.prototype.track_progress = function() {
            var totalTime = this.end - this.start;
            var position = this.sound_position();       // implement in subclass
            var relative_position = position - this.start;
            var percentage = (relative_position * 100) / totalTime;
            SOUNDCITE_CONFIG.update_playing_element(this.el, percentage);
        }

        Clip.prototype.click_handler = function() {
            pause_all_clips(this);

            if(this.playing) {
                this.pause();
            } else {
                this.play();                            // implement in subclass
            }
        }

        function SoundCloudClip(el) {
            Clip.apply(this, Array.prototype.slice.call(arguments));

            this.id = el.attributes['data-id'].value;

            $SoundCloud.stream(this.id, bind(function(sound) {
                this.sound = sound;

                this.sound._player.on("positionChange", bind(function(pos) {
                    this.track_progress();

                    if(pos > this.end) {
                        this.stop();
                    }
                }, this));

               this.sound_loaded();
            }, this));
        }
        SoundCloudClip.prototype = Object.create(Clip.prototype);

        SoundCloudClip.prototype.sound_position = function() {
            return this.sound.getCurrentPosition();
        }

        SoundCloudClip.prototype.pause_sound = function() {
            this.sound.pause();
        }

        SoundCloudClip.prototype.stop_sound = function() {
            this.sound.stop();
        }

        SoundCloudClip.prototype.play = function() {
            var pos = this.sound_position();

            if(pos < this.start || pos >= this.end) {
                this.sound.seek(this.start);
            }

            this.$el.removeClass('soundcite-play');
            this.$el.addClass('soundcite-pause');

            this.sound.play();
            this.playing = true;
        }

// Popcorn Clip
        function PopcornClip(el) {
            Clip.apply(this, Array.prototype.slice.call(arguments));

            this.id = 'soundcite-audio-'+clips.length;
            this.url = el.attributes['data-url'].value;

            // convert to ms to secs
            this.start = Math.floor(this.start / 1000);
            this.end = Math.floor(this.end / 1000);

            $audio.append('<audio id="'+this.id+'" src="'+this.url+'" preload="true"></audio>');
            this.sound = $Popcorn('#'+this.id, {'frameAnimation': true});

            // Safari iOS Audio streams cannot be loaded unless triggered by a
            // user event, so load in play_sound via click for mobile
            this.sound.on('loadeddata', bind(function() {
                if(!this.end) {
                    this.end = this.sound.duration();
                }
                this.sound.cue(this.end, bind(this.stop, this));

                if(!soundcite.mobile) {
                    this.sound_loaded();
                }
            }, this));

            if(soundcite.mobile) {
                this.sound_loaded();
            } else if(this.sound.readyState() > 1) {
                this.sound_loaded();
            }
        }
        PopcornClip.prototype = Object.create(Clip.prototype);

        PopcornClip.prototype.sound_position = function() {
            return this.sound.currentTime();
        }

        PopcornClip.prototype.pause_sound = function() {
            this.sound.pause();
            this.sound.off('timeupdate');
        }

        PopcornClip.prototype.stop_sound = function() {
            this.sound.pause();
            this.sound.off('timeupdate');
        }

        PopcornClip.prototype._play_sound = function() {
            this.$el.removeClass('soundcite-loading soundcite-play');
            this.$el.addClass('soundcite-pause');
            this.sound.play();
            this.playing = true;

            this.sound.on('timeupdate', bind(this.track_progress, this));
            this.sound.on('ended', bind(this.stop, this));
        }

        PopcornClip.prototype.play_sound = function() {
            var pos = this.sound.roundTime();

            if(pos < this.start || pos >= this.end) {
                this.sound.on('seeked', bind(function() {
                    this.sound.off('seeked');
                    this._play_sound();
                }, this));

                this.sound.currentTime(this.start);
            } else {
                this._play_sound();
            }
        }

        PopcornClip.prototype.play = function() {
            if(soundcite.mobile) {
                this.$el.removeClass('soundcite-play');
                this.$el.addClass('soundcite-loading');

                if(this.sound.readyState() > 1) {
                    this.play_sound();
                } else {
                    this.sound.on('canplaythrough',bind(function() {
                        this.play_sound();
                    }, this));

                    $('#'+this.id)[0].load();
                }
            } else {
                this.play_sound();
            }
        }

// set up clips array
        var soundcite_array = $('.soundcite');

        for(var i = 0; i < soundcite_array.length; i++) {
            var el = soundcite_array[i];
            if(el.hasAttribute('data-url')) {
                new PopcornClip(el);
            } else { //if(!soundcite.mobile) {
                new SoundCloudClip(el);
            }
        }

        soundcite.Clip = Clip;
        soundcite.SoundCloudClip = SoundCloudClip;
        soundcite.PopcornClip = PopcornClip;
        soundcite.clips = clips;    // keep track of clips
        soundcite.pause_all_clips = pause_all_clips;
    });
});
<|endoftext|>


<commit_before>"use strict";
var URL = require("url");
var Http2ServerResponse = require("http2").Http2ServerResponse;
var headersKeys = "Content-Type,Content-Length,User-Agent,Accept-Language,Accept-Encoding,Range,If-Range,Last-Modified".split(",");
var privateKeys = Object.create(null);
"Cookie,Connection,Referer,Host,Origin".split(",").forEach(k => privateKeys[k] = privateKeys[k.toLowerCase()] = true);
var options = {
    record_path: process.env.record_path
};

if (options.record_path) {
    let { record_path } = options.record_path;
    let parseKV = require("../basic/parseKV");
    if (/\=/.test(record_path)) {
        options.record_path = parseKV(record_path);
    }
}
-function () {
    var fs = require("fs");
    var path = require("path");
    var loadCertFile = function (keyname, reletivepath) {
        var fullpath = path.join(__dirname, "../../data/keystore", reletivepath);
        fs.readFile(fullpath, function (err, chunk) {
            if (err) console.error(err);
            else options[keyname] = chunk;
        });
    }
    loadCertFile("key", "cross-key.pem");
    loadCertFile("cert", "cross-cert.pem");
}();
function parseUrl(hostpath, real) {
    var { pathname, search, hostname, protocol, port } = URL.parse(hostpath);
    if (real === undefined && /^https?\:\/\//i.test(hostpath)) {
        var headers = {};
        var realpath = pathname.slice(1);
        hostpath = `${protocol}//${hostname}${port ? ':' + port : ''}/`;
    } else {

        var slice_end = pathname.indexOf("@");
        if (slice_end < 0) slice_end = pathname.length;
        var realpath = real ? real.slice(1) : pathname.slice(slice_end + 1) + (search || "");
        var jsonlike = pathname.slice(1, slice_end);
        var matchlike = /^(?:\{|%7b)(s?)(\/|%2f)\2(.*?)\2(.*?)(?:\}|%7d)$/i.exec(jsonlike);
        if (matchlike) {
            // {s//wx2.qq.com/k=v,k=v,k=v}
            var headers = {};
            let [, s, , host, header] = matchlike;
            var hostpath = `http${s}://${host}/`;
            header.split(/[,&]/).forEach(function (kv) {
                var [k, v] = kv.split("=");
                if (k && v) try {
                    headers[decodeURIComponent(k)] = decodeURIComponent(v);
                } catch (e) {
                    headers[unescape(k)] = unescape(v);
                }
            });
        } else {
            var { url: hostpath, token, headers = {} } = JSON.parse(decodeURIComponent(jsonlike));
            if (!token) throw new Error("验证身份失败！");
            hostpath = escape(hostpath);
        }
    }
    return { jsonlike, realpath, hostpath, headers };
}
// https://github.com/nodejs/node/blob/02a0c74861c3107e6a9a1752e91540f8d4c49a76/lib/_http_common.js :204
const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/
/**
 * Verifies that the given val is a valid HTTP token
 * per the rules defined in RFC 7230
 * See https://tools.ietf.org/html/rfc7230#section-3.2.6
 */
function checkIsHttpToken(val) {
    return tokenRegExp.test(val);
}
/**
 *
 * @param {*} req
 * @param {http.ServerResponse} res
 * @param {*} referer
 */
function cross(req, res, referer) {
    try {
        if (referer) {
            var { jsonlike, realpath, hostpath, headers } = parseUrl(referer, req.url);
            if (/^head|^get/i.test(req.method)) {
                var redirect = "/" + unescape(jsonlike) + "@" + realpath;
                res.writeHead(302, {
                    "Location": redirect
                });
                return res.end();
            }
            var $url = hostpath + realpath;
        } else {
            var { jsonlike, realpath, hostpath, headers } = parseUrl(req.url);
            var $url = hostpath + realpath;
        }
        // $data = $cross['data'],//不再接受数据参数，如果是get请直接写入$url，如果是post，请直接post
        var method = req.method;//$_SERVER['REQUEST_METHOD'];
        var _headers = req.headers;
        var is_proxy = false;
        if (/^https?\:\/\/[^\/]*\/(?:\{|%7b)/i.test(_headers.referer) && !headers.referer) {
            headers.referer = hostpath + parseUrl(_headers.referer, false).realpath;
            is_proxy = true;
        } else if (_headers.referer || _headers.origin === 'null') {
            headers.referer = hostpath;
        }
        for (let key in headers) {
            let k = key.toLowerCase();
            if (k !== key) {
                headers[k] = headers[key];
                delete headers[key];
            }
        }
        headersKeys.forEach(function (key) {
            key = key.toLowerCase();
            if (!headers[key] && _headers[key]) {
                headers[key] = _headers[key];
            }
        });
        for (var k in _headers) {
            if ({}.hasOwnProperty.call(privateKeys, k)) {
                continue;
            }
            if (!headers[k] && _headers[k] && checkIsHttpToken(k)) {
                headers[k] = _headers[k];
            }
        }
        var http;
        if (/^https\:/i.test(hostpath)) {
            http = require("https");
        } else {
            http = require("http");
        }
        var request = http.request(Object.assign({
            method: method,
            headers: headers,
            rejectUnauthorized: false// 放行证书不可用的网站
        }, URL.parse($url), options), function (response) {
            var headers = response.headers;
            var setCookie = headers["set-cookie"];
            if (setCookie && !is_proxy) headers["efront-cookie"] = setCookie, delete headers["set-cookie"];
            if (headers.location) {
                headers["efront-location"] = headers.location;
                delete headers.location;
            }
            headers["Access-Control-Expose-Headers"] = ["efront-location", "efront-cookie"].join();
            delete headers["access-control-allow-origin"];
            delete headers["access-control-allow-methods"];
            if (res instanceof Http2ServerResponse) {
                delete headers["transfer-encoding"];
                delete headers["connection"];
            }
            if (!closed) {
                res.writeHead(response.statusCode, headers);
                let { record_path } = options;
                try {
                    $url = decodeURI($url);
                } catch (e) {
                    $url = escape($url);
                }
                let { pathname, hostname } = URL.parse($url);
                if (record_path instanceof Object) {
                    record_path = record_path[hostname];
                    if (!record_path) {
                        console.warn("skiped", $url);
                    }
                }
                if (record_path && response.statusCode === 200) {
                    let fs = require("fs");
                    let path = require("path");
                    if (/[\/\\]$/.test(pathname)) {
                        pathname = path.join(pathname, 'index.html');
                    }
                    let fullpath = path.join(record_path, pathname);
                    response.pipe(res);
                    var buffers = [];
                    response.on("data", function (data) {
                        buffers.push(data);
                    });
                    response.on("end", function () {
                        fs.mkdir(path.dirname(fullpath), { recursive: true }, function (error) {
                            if (error) {
                                console.error("创建文件夹失败", error);
                            }
                            var stream = fs.createWriteStream(fullpath);
                            var data = Buffer.concat(buffers);
                            var write = function (error, data) {
                                if (error) {
                                    console.error(fullpath, error);
                                    return;
                                }
                                console.info('grap', fullpath);
                                stream.write(data);
                                stream.end();
                            };
                            switch (response.headers["content-encoding"]) {
                                case "gzip":
                                    require("zlib").gunzip(data, write);
                                    break;
                                case null:
                                case "":
                                case undefined:
                                    write(null, data);
                                    break;
                                default:
                                    console.warn(response.headers["content-encoding"], "not support!");
                                    write(null, data);
                            }
                            // console.log(data);
                        });
                    })
                } else {
                    response.pipe(res);
                }
            } else {
                response.destroy();
                res.end();
            }
        });
        var closed = false;
        req.on("close", function (e) {
            closed = true;
        });
        request.setTimeout(120000/*support for wechat long pull*/);
        request.on("error", function (e) {
            var code;
            switch (e.code) {
                case "ECONNREFUSED":
                    code = 502;
                    break;
                case "ETIMEDOUT":
                    code = 504;
                    break;
                default:
                    code = 500;
            }
            closed = true;
            res.writeHead(code, {});
            res.end(String(e));
        });
        req.pipe(request);
    } catch (e) {
        res.writeHead(500, {});
        res.end(String(e));
    }
}
module.exports = cross;<commit_msg>做为代理服务器使用时不再返回efront-cookie<commit_after>"use strict";
var URL = require("url");
var Http2ServerResponse = require("http2").Http2ServerResponse;
var headersKeys = "Content-Type,Content-Length,User-Agent,Accept-Language,Accept-Encoding,Range,If-Range,Last-Modified".split(",");
var privateKeys = Object.create(null);
"Cookie,Connection,Referer,Host,Origin".split(",").forEach(k => privateKeys[k] = privateKeys[k.toLowerCase()] = true);
var options = {
    record_path: process.env.record_path
};

if (options.record_path) {
    let { record_path } = options.record_path;
    let parseKV = require("../basic/parseKV");
    if (/\=/.test(record_path)) {
        options.record_path = parseKV(record_path);
    }
}
-function () {
    var fs = require("fs");
    var path = require("path");
    var loadCertFile = function (keyname, reletivepath) {
        var fullpath = path.join(__dirname, "../../data/keystore", reletivepath);
        fs.readFile(fullpath, function (err, chunk) {
            if (err) console.error(err);
            else options[keyname] = chunk;
        });
    }
    loadCertFile("key", "cross-key.pem");
    loadCertFile("cert", "cross-cert.pem");
}();
function parseUrl(hostpath, real) {
    var { pathname, search, hostname, protocol, port } = URL.parse(hostpath);
    if (real === undefined && /^https?\:\/\//i.test(hostpath)) {
        var headers = {};
        var realpath = pathname.slice(1);
        hostpath = `${protocol}//${hostname}${port ? ':' + port : ''}/`;
    } else {

        var slice_end = pathname.indexOf("@");
        if (slice_end < 0) slice_end = pathname.length;
        var realpath = real ? real.slice(1) : pathname.slice(slice_end + 1) + (search || "");
        var jsonlike = pathname.slice(1, slice_end);
        var matchlike = /^(?:\{|%7b)(s?)(\/|%2f)\2(.*?)\2(.*?)(?:\}|%7d)$/i.exec(jsonlike);
        if (matchlike) {
            // {s//wx2.qq.com/k=v,k=v,k=v}
            var headers = {};
            let [, s, , host, header] = matchlike;
            var hostpath = `http${s}://${host}/`;
            header.split(/[,&]/).forEach(function (kv) {
                var [k, v] = kv.split("=");
                if (k && v) try {
                    headers[decodeURIComponent(k)] = decodeURIComponent(v);
                } catch (e) {
                    headers[unescape(k)] = unescape(v);
                }
            });
        } else {
            var { url: hostpath, token, headers = {} } = JSON.parse(decodeURIComponent(jsonlike));
            if (!token) throw new Error("验证身份失败！");
            hostpath = escape(hostpath);
        }
    }
    return { jsonlike, realpath, hostpath, headers };
}
// https://github.com/nodejs/node/blob/02a0c74861c3107e6a9a1752e91540f8d4c49a76/lib/_http_common.js :204
const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/
/**
 * Verifies that the given val is a valid HTTP token
 * per the rules defined in RFC 7230
 * See https://tools.ietf.org/html/rfc7230#section-3.2.6
 */
function checkIsHttpToken(val) {
    return tokenRegExp.test(val);
}
/**
 *
 * @param {*} req
 * @param {http.ServerResponse} res
 * @param {*} referer
 */
function cross(req, res, referer) {
    try {
        if (referer) {
            var { jsonlike, realpath, hostpath, headers } = parseUrl(referer, req.url);
            if (/^head|^get/i.test(req.method)) {
                var redirect = "/" + unescape(jsonlike) + "@" + realpath;
                res.writeHead(302, {
                    "Location": redirect
                });
                return res.end();
            }
            var $url = hostpath + realpath;
        } else {
            var { jsonlike, realpath, hostpath, headers } = parseUrl(req.url);
            var $url = hostpath + realpath;
        }
        // $data = $cross['data'],//不再接受数据参数，如果是get请直接写入$url，如果是post，请直接post
        var method = req.method;//$_SERVER['REQUEST_METHOD'];
        var _headers = req.headers;
        var is_proxy = false;
        if (/^https?\:\/\/[^\/]*\/(?:\{|%7b)/i.test(_headers.referer) && !headers.referer) {
            headers.referer = hostpath + parseUrl(_headers.referer, false).realpath;
            is_proxy = true;
        } else if (_headers.referer || _headers.origin === 'null') {
            headers.referer = hostpath;
        }
        for (let key in headers) {
            let k = key.toLowerCase();
            if (k !== key) {
                headers[k] = headers[key];
                delete headers[key];
            }
        }
        headersKeys.forEach(function (key) {
            key = key.toLowerCase();
            if (!headers[key] && _headers[key]) {
                headers[key] = _headers[key];
            }
        });
        for (var k in _headers) {
            if ({}.hasOwnProperty.call(privateKeys, k)) {
                continue;
            }
            if (!headers[k] && _headers[k] && checkIsHttpToken(k)) {
                headers[k] = _headers[k];
            }
        }
        var http;
        if (/^https\:/i.test(hostpath)) {
            http = require("https");
        } else {
            http = require("http");
        }
        var request = http.request(Object.assign({
            method: method,
            headers: headers,
            rejectUnauthorized: false// 放行证书不可用的网站
        }, URL.parse($url), options), function (response) {
            var headers = response.headers;
            var setCookie = headers["set-cookie"];
            if (setCookie && !is_proxy) headers["efront-cookie"] = setCookie, delete headers["set-cookie"];
            if (headers.location && referer) {
                headers["efront-location"] = headers.location;
                delete headers.location;
            }
            headers["Access-Control-Expose-Headers"] = ["efront-location", "efront-cookie"].join();
            delete headers["access-control-allow-origin"];
            delete headers["access-control-allow-methods"];
            if (res instanceof Http2ServerResponse) {
                delete headers["transfer-encoding"];
                delete headers["connection"];
            }
            if (!closed) {
                res.writeHead(response.statusCode, headers);
                let { record_path } = options;
                try {
                    $url = decodeURI($url);
                } catch (e) {
                    $url = escape($url);
                }
                let { pathname, hostname } = URL.parse($url);
                if (record_path instanceof Object) {
                    record_path = record_path[hostname];
                    if (!record_path) {
                        console.warn("skiped", $url);
                    }
                }
                if (record_path && response.statusCode === 200) {
                    let fs = require("fs");
                    let path = require("path");
                    if (/[\/\\]$/.test(pathname)) {
                        pathname = path.join(pathname, 'index.html');
                    }
                    let fullpath = path.join(record_path, pathname);
                    response.pipe(res);
                    var buffers = [];
                    response.on("data", function (data) {
                        buffers.push(data);
                    });
                    response.on("end", function () {
                        fs.mkdir(path.dirname(fullpath), { recursive: true }, function (error) {
                            if (error) {
                                console.error("创建文件夹失败", error);
                            }
                            var stream = fs.createWriteStream(fullpath);
                            var data = Buffer.concat(buffers);
                            var write = function (error, data) {
                                if (error) {
                                    console.error(fullpath, error);
                                    return;
                                }
                                console.info('grap', fullpath);
                                stream.write(data);
                                stream.end();
                            };
                            switch (response.headers["content-encoding"]) {
                                case "gzip":
                                    require("zlib").gunzip(data, write);
                                    break;
                                case null:
                                case "":
                                case undefined:
                                    write(null, data);
                                    break;
                                default:
                                    console.warn(response.headers["content-encoding"], "not support!");
                                    write(null, data);
                            }
                            // console.log(data);
                        });
                    })
                } else {
                    response.pipe(res);
                }
            } else {
                response.destroy();
                res.end();
            }
        });
        var closed = false;
        req.on("close", function (e) {
            closed = true;
        });
        request.setTimeout(120000/*support for wechat long pull*/);
        request.on("error", function (e) {
            var code;
            switch (e.code) {
                case "ECONNRESET":
                case "ECONNREFUSED":
                    code = 502;
                    break;
                case "ETIMEDOUT":
                    code = 504;
                    break;
                default:
                    code = 500;
            }
            closed = true;
            res.writeHead(code, {});
            res.end(String(e));
        });
        req.pipe(request);
    } catch (e) {
        res.writeHead(500, {});
        res.end(String(e));
    }
}
module.exports = cross;<|endoftext|>


<commit_before>const DiscordBot = require('./bot');
const PluginManager = require ('./pluginmanager');
const CommandManager = require('./command');

const jsonfile = require('jsonfile');
const Logging = require('./logging')
const async = require('async');
class Disnode {
    constructor(config) {
        this.botConfigPath = config;
    }

    Start() {
      var self = this;
      async.waterfall([
        // Load Config and Init bot
        function(callback) {//Test
          //This is test
          Logging.DisnodeInfo("Disnode", "Start", "Loadeding Config");
          self.LoadBotConfig().then(function(){
            self.bot = new DiscordBot(self.botConfig.key);
            Logging.DisnodeSuccess("Disnode", "Start", "Loaded Config");
            callback();
          }).catch(callback);
        },
        // Connect to Discord
        function(callback) {
          Logging.DisnodeInfo("Disnode", "Start", "Connecting to Discord");
          self.bot.Connect().then(function(){
            Logging.DisnodeSuccess("Disnode", "Start", "Connected to Discord");
            callback();
          }).catch(callback);
        },
        // Load Functions
        function(callback) {
          Logging.DisnodeInfo("Disnode", "Start", "Loading Plugins");
          self.plugin = new PluginManager(self);
          self.plugin.Load("./plugins").then(function(){
            Logging.DisnodeSuccess("Disnode", "Start", "Plugins Loaded!");
            callback();
          }).catch(callback);
        },
        // Bind Events
        function(callback) {
          Logging.DisnodeInfo("Disnode", "Start", "Binding Events");
          self.bot.client.on("message",(msg)=>self.OnMessage(msg));
          callback();
        },
        // Create Command Handler
        function(callback) {
          Logging.DisnodeInfo("Disnode", "Start", "Loading Command Handler");
          self.command = new CommandManager(self);
          callback();
        },
        // Launch Static Plugins
        function(callback) {
          Logging.DisnodeInfo("Disnode", "Start", "Launching static plugins");
          self.plugin.LauchStatic().then(function(){
            Logging.DisnodeSuccess("Disnode", "Start", "Static Plugins Launched!");
            callback();
          }).catch(callback);
        },
      ], function (err, result) {
          if(err){
            Logging.DisnodeError("Disnode", "Start", err)
          }
      });
    }

    Stop() {
      var self = this;
      self.bot.Disconnect();
    }

    Restart() {
      var self = this;
      self.bot.Disconnect().then(function(){
        self.bot.Connect();
      }).catch(function(err){
        Logging.DisnodeError("Disnode", "Restart", err);

      });

    }

    LoadBotConfig() {
      var self = this;

      return new Promise(function(resolve, reject) {
        if (!self.botConfigPath) {
          //Logging.DisnodeWarning("Disnode", "LoadBotConfig", " No Bot Config Path Set!")

            reject(" No Bot Config Path Set");
        }
        //Logging.DisnodeInfo("Disnode", "LoadBotConfig", " Loading Config!")

        self.botConfig = {}; // Creates/Clears Object.

        jsonfile.readFile(self.botConfigPath, function(err, obj) {
            if(err){
              reject(err) // If Error Call Catch for Promise
            }
            self.botConfig = obj;
            resolve(); // If Loaded Call Resolve for promise
        });
      });
    }

    OnMessage (msg){
      if(this.command){

        this.command.RunMessage(msg);
      }else{
        Logging.DisnodeWarning("Disnode", "Message", "No Command Handler!");
      }
    }
}

module.exports = Disnode;
<commit_msg>Test 6<commit_after>const DiscordBot = require('./bot');
const PluginManager = require ('./pluginmanager');
const CommandManager = require('./command');

const jsonfile = require('jsonfile');
const Logging = require('./logging')
const async = require('async');
class Disnode {
    constructor(config) {
        this.botConfigPath = config;
    }

    Start() {
      var self = this;
      async.waterfall([
        // Load Config and Init bot
        function(callback) {//Test

          Logging.DisnodeInfo("Disnode", "Start", "Loadeding Config");
          self.LoadBotConfig().then(function(){
            self.bot = new DiscordBot(self.botConfig.key);
            Logging.DisnodeSuccess("Disnode", "Start", "Loaded Config");
            callback();
          }).catch(callback);
        },
        // Connect to Discord
        function(callback) {
          Logging.DisnodeInfo("Disnode", "Start", "Connecting to Discord");
          self.bot.Connect().then(function(){
            Logging.DisnodeSuccess("Disnode", "Start", "Connected to Discord");
            callback();
          }).catch(callback);
        },
        // Load Functions
        function(callback) {
          Logging.DisnodeInfo("Disnode", "Start", "Loading Plugins");
          self.plugin = new PluginManager(self);
          self.plugin.Load("./plugins").then(function(){
            Logging.DisnodeSuccess("Disnode", "Start", "Plugins Loaded!");
            callback();
          }).catch(callback);
        },
        // Bind Events
        function(callback) {
          Logging.DisnodeInfo("Disnode", "Start", "Binding Events");
          self.bot.client.on("message",(msg)=>self.OnMessage(msg));
          callback();
        },
        // Create Command Handler
        function(callback) {
          Logging.DisnodeInfo("Disnode", "Start", "Loading Command Handler");
          self.command = new CommandManager(self);
          callback();
        },
        // Launch Static Plugins
        function(callback) {
          Logging.DisnodeInfo("Disnode", "Start", "Launching static plugins");
          self.plugin.LauchStatic().then(function(){
            Logging.DisnodeSuccess("Disnode", "Start", "Static Plugins Launched!");
            callback();
          }).catch(callback);
        },
      ], function (err, result) {
          if(err){
            Logging.DisnodeError("Disnode", "Start", err)
          }
      });
    }

    Stop() {
      var self = this;
      self.bot.Disconnect();
    }

    Restart() {
      var self = this;
      self.bot.Disconnect().then(function(){
        self.bot.Connect();
      }).catch(function(err){
        Logging.DisnodeError("Disnode", "Restart", err);

      });

    }

    LoadBotConfig() {
      var self = this;

      return new Promise(function(resolve, reject) {
        if (!self.botConfigPath) {
          //Logging.DisnodeWarning("Disnode", "LoadBotConfig", " No Bot Config Path Set!")

            reject(" No Bot Config Path Set");
        }
        //Logging.DisnodeInfo("Disnode", "LoadBotConfig", " Loading Config!")

        self.botConfig = {}; // Creates/Clears Object.

        jsonfile.readFile(self.botConfigPath, function(err, obj) {
            if(err){
              reject(err) // If Error Call Catch for Promise
            }
            self.botConfig = obj;
            resolve(); // If Loaded Call Resolve for promise
        });
      });
    }

    OnMessage (msg){
      if(this.command){

        this.command.RunMessage(msg);
      }else{
        Logging.DisnodeWarning("Disnode", "Message", "No Command Handler!");
      }
    }
}

module.exports = Disnode;
<|endoftext|>