UNPKG

core

Version:

Core Libs

849 lines (731 loc) 17.7 kB
/** * @overview Request * @copyright Dreamlab Onet.pl sp. z. o o 2012 */ var http = require('http'); var urlParser = require('uriparser'); var Types = require('../common/Types.js').Types; var Message = require('./Message.js').Message; var BinaryData = require('../data/BinaryData.js').BinaryData; var FormData = require('../data/FormData.js').FormData; /** * Http Request * @class Request * @classdesc Object that represents http request * @extends Message * @throw Request.Exception.REQUEST_CANNOT_BE_A_BUFFER * @param {Object|String|Request|Buffer|http.IncomingMessage} params * @return {Request} */ var Request = function (params) { Message.call(this, params); this._url = null; this._search = null; this._method = 'GET'; this._host = null; this._port = null; this._defaultPortChanged = false; this._path = '/'; this._proto = 'http:'; this._authUser = null; this._authPassword = null; this._querySuffixes = {}; this._querySeparator = '&'; this._query = {}; this._clientAddress = null; this._clientPort = null; this._timeStart = null; if (Buffer.isBuffer(params)) { throw Request.Exception.REQUEST_CANNOT_BE_A_BUFFER; } else if (Types.isString(params)) { this.setUrl(params); } else if (Types.isInstanceOf(params, Request)) { this.setUrl(params.getUrl()); this.setMethod(params.getMethod()); this.setHeaders(params.getHeaders()); this.setBody(params.getBody()); this.setHttpVersion(params.getHttpVersion()); //connection host this.setConnectionHost(params.getConnectionHost()); } else if (Types.isInstanceOf(params, http.IncomingMessage)) { // 1831 - 1886 // 1500 - 1618 this.setMethod(params.method); // 1483 - 1572 this.setHeaders(params.headers); // 1416 - 1552 var httpVer = params.httpVersion; // 1381 - 1483 this.setHttpVersion(httpVer); // 1381 - 1483 // 1362 - 1488 (bez return this) 1388 - 1492 this.setBody(params.data); // 1340 - 1453 this.setUrl(params.url); this._clientAddress = params.client.remoteAddress; this._clientPort = params.client.remotePort; this._timeStart = (params.__timeStart || Date.now()); } else { this.init(params); } }; Request.prototype = Object.create(Message.prototype); Request.prototype._cookieRegExpCache = {}; Request.prototype._preCookieRegexp = '((?:^|;)\\s?)'; Request.prototype._postCookieRegExp = '=([^;]+)(;\\s?|$)'; /** * Checks if given string is already encoded * @method * @private * @param {String} str * @return {Boolean} */ Request.prototype._isEncoded = function (str) { return (str.indexOf("%") != -1 || str.indexOf("+") != -1); }; /** * Set cookie * @method * @param {String} cookie * @return {Request} */ Request.prototype.setCookie = function (cookie) { var cookies = this.headers.getHeader("cookie"); if (!cookies) { cookies = ''; } if (cookies.length) { cookies += '; ' + cookie; } else { cookies = cookie; } this.headers.setHeader("cookie", cookies, true); return this; }; /** * Get cookie * @method * @param {String} cookieName * @return {String|null} */ Request.prototype.getCookie = function (cookieName) { var cookies = this.headers.getHeader('cookie'); if (!cookies) { return null; } var result = cookies.match(this._getCookieRegexp(cookieName)); if (result && result[2]) { return result[2]; } return null; }; /** * Remove cookie * @method * @param {String} cookieName * @return {null|Boolean} */ Request.prototype.removeCookie = function (cookieName) { var cookies = this.headers.getHeader('cookie'); if (!cookies) { return null; } cookies = cookies.replace(this._getCookieRegexp(cookieName), '$1').replace(/[; ]+$/, ''); this.headers.setHeader('cookie', cookies, true); return true; }; /** * Returns cookie cached regexp * * @param {string} cookieName * @return {RegExp} - regexp pattern for cookie */ Request.prototype._getCookieRegexp = function (cookieName) { if (!this._cookieRegExpCache[cookieName]) { this._cookieRegExpCache[cookieName] = new RegExp(this._preCookieRegexp + cookieName + this._postCookieRegExp); } return this._cookieRegExpCache[cookieName]; }; /** * Sets url of a service endpoint * @method * @param {String} url * @returns {UrlRequest} */ Request.prototype.setUrl = function (url) { this._url = url; var matches = urlParser.parse(url); if (matches.hasOwnProperty('auth')) { this.setAuth(matches.auth); } else { this.setAuth(''); } if (matches.hasOwnProperty('host')) { this.setConnectionHost(matches.host); } else { this.setConnectionHost(this.getHost()); } if (matches.hasOwnProperty('port')) { this._defaultPortChanged = true; this.setPort(parseInt(matches.port, 10)); } else { this._defaultPortChanged = false; this.setPort(80); } if (matches.hasOwnProperty('protocol')) { this.setProto(matches.protocol); } else { this.setProto('http:'); } if (matches.hasOwnProperty('path')) { var path = matches.path; if (path[0] != '/') { path = '/' + path; } this.setPath(path); } if (matches.hasOwnProperty('query')) { this.setQuery(matches.query); if (matches.hasOwnProperty('queryArraySuffix')) { this._querySuffixes = matches.queryArraySuffix; } } else { this.setQuery({}); } if (matches.hasOwnProperty('querySeparator')) { this._querySeparator = matches.querySeparator || '&'; } if (matches.hasOwnProperty('search')) { this._search = matches.search; } return this; }; /** * Returns url of a service endpoint * @method * @returns {String} */ Request.prototype.getUrl = function () { if (this._url) { return this._url; } var url = ''; var proto = this.getProto(); if (proto) { url += proto + '//'; } var auth = this.getAuth(); if (auth) { url += auth + '@'; } var host = this.getConnectionHost(), port = this.getPort(); if (this.getHost()) { host = this.getHost(); if (host.lastIndexOf(':') > 0) { port = null; } } //jak mamy port i nie mamy pary http:80 i https:443 to doklejamy do hosta port //dla http/https jesli port jest default to go nie zwracamy if (port && !((proto === 'http:' && port == 80) || (proto === 'https:' && port == 443))) { url += host + ':' + port; } else { url += host; } var path = this.getPath(); if (path) { url += path; } else { url += '/'; } url += this.getQueryString(); this._url = url; return url; }; /** * Returns query string component of an url * @method * @returns {String} */ Request.prototype.getQueryString = function () { var url = ''; var query = this.getQuery(); if (this._search) { return this._search; } if (query) { url += '?'; var tmp = ''; // to nie zadziala dla case test ącki for (var key in query) { if (query.hasOwnProperty(key)) { if (Array.isArray(query[key])) { for (var i = 0, max = query[key].length; i < max; i++) { var value = query[key][i]; tmp += key; tmp += this._querySuffixes[key] || ''; tmp += '=' + value; tmp += this._querySeparator; } } else { tmp += key; if (query[key]) { tmp += '=' + query[key]; } else if (query[key] === '') { tmp += '='; } tmp += this._querySeparator; } } } url += tmp.substring(0, tmp.length - 1); } if (url == '?') { url = ''; } return url; }; /** * Sets method of communicating with a service * @method * @param {String} method * @returns {Request} */ Request.prototype.setMethod = function (method) { this._method = method; return this; }; /** * Returns method of communicating with a service * @method * @returns {String} */ Request.prototype.getMethod = function () { return this._method; }; /** * Sets connection host * @method * @param {String} host * @returns {Request} */ Request.prototype.setConnectionHost = function (host) { this._url = null; if (host) { this._host = host.toLowerCase(); } else { this._host = host; } return this; }; /** * Returns connection host * @method * @returns {String} */ Request.prototype.getConnectionHost = function () { if (this._host) { return this._host.toLowerCase(); } else { return this._host; } }; /** * Sets Host http header * @method * @param {String} host * @returns {Request} */ Request.prototype.setHost = function (host) { this._url = null; if (host) { this.headers.setHeader('host', host.toLowerCase(), true); } else { this.headers.setHeader('host', host, true); } return this; }; /** * Returns Host http header * @method * @returns {String|null} */ Request.prototype.getHost = function () { var host = this.headers.getHeader('host'); if (host) { return host.toLowerCase(); } else { return host; } }; /** * Sets connection port * @method * @param {Number} port * @returns {Request} */ Request.prototype.setPort = function (port) { this._url = null; this._port = port; return this; }; /** * Returns connection port * @method * @returns {Number|null} */ Request.prototype.getPort = function () { return this._port; }; /** * Sets url path * @method * @param {String} path * @returns {Request} */ Request.prototype.setPath = function (path) { this._url = null; this._path = path; return this; }; /** * Returns url path * @method * @returns {String|null} */ Request.prototype.getPath = function () { return this._path; }; /** * Sets protocol * @method * @param {String} proto * @returns {Request} */ Request.prototype.setProto = function (proto) { this._url = null; this._proto = proto; if (!this._defaultPortChanged) { if (proto === 'https:') { this.setPort(443); } else if (proto === 'http:') { this.setPort(80); } } return this; }; /** * Returns protocol * @method * @returns {String|null} */ Request.prototype.getProto = function () { return this._proto; }; /** * Sets http simple auth digest in format: user:pass * @method * @param {String} auth * @returns {Request} */ Request.prototype.setAuth = function (auth) { this._url = null; var data; if (Types.isString(auth)) { var tmp = auth.split(':'); data = { user: tmp[0], password: tmp[1] }; } else { data = auth; } this.setAuthUser(data.user); this.setAuthPassword(data.password); return this; }; /** * Returns http simple auth digest in format: user:pass * @method * @returns {String|null} */ Request.prototype.getAuth = function () { var user = this.getAuthUser(), password = this.getAuthPassword(); if (user && password) { return user + ':' + password; } return null; }; /** * Sets username for http simple auth digest * @method * @param {String} user * @returns {Request} */ Request.prototype.setAuthUser = function (user) { this._url = null; this._authUser = user; return this; }; /** * Returns username for http simple auth digest * @method * @returns {String|null} */ Request.prototype.getAuthUser = function () { return this._authUser; }; /** * Sets password for http simple auth digest * @method * @param {String} password * @returns {Request} */ Request.prototype.setAuthPassword = function (password) { this._url = null; this._authPassword = password; return this; }; /** * Returns password for http simple auth digest * @method * @returns {String|null} */ Request.prototype.getAuthPassword = function () { return this._authPassword; }; /** * Sets url query string * @method * @param {String} query * @returns {Request} */ Request.prototype.setQuery = function (query) { this._url = null; this._search = null; this._query = query; return this; }; /** * Returns url query string * @method * @returns {String|null} */ Request.prototype.getQuery = function () { return this._query; }; /** * Sets url query component * @param {String} name * @param {String} value * @returns {Request} * @method */ Request.prototype.setQueryParam = function (name, value) { this._url = null; this._search = null; if (!this._query) { this._query = {}; } this._query[name] = value; if (Types.isArray(value)) { this._querySuffixes[name] = '[]'; } return this; }; Request.prototype.hasQueryParam = function (name) { if (!this._query) { return false; } return this._query.hasOwnProperty(name); }; /** * Returns url query component * @method * @param {String} name * @returns {String|null} */ Request.prototype.getQueryParam = function (name) { if (!this._query) { return null; } if (this._query.hasOwnProperty(name)) { // FIXME remove in next majaor if (this._query[name] === null) { return ''; } /// END return this._query[name]; } return null; }; /** * Returns client ip address * @method * @returns {String|null} */ Request.prototype.getClientAddress = function () { return (this._clientAddress || null); }; /** * Returns client port number * @method * @returns {Number|null} */ Request.prototype.getClientPort = function () { return (this._clientPort || null); }; /** * Returns request processing time * @method * @returns {Number} */ Request.prototype.getProcessingTime = function () { return this._timeStart ? (Date.now() - this._timeStart) : 0; }; /** * Sets request body (post data) * @method * @param {BinaryData|String|null|undefined} body * @returns {Request} */ Request.prototype.setBody = function (body) { if (Types.isInstanceOf(body, FormData)) { this.setHeader('content-length', body.length(), true); var boundary = body.getBoundary(); if (boundary) { this.setHeader('content-type', 'multipart/form-data; boundary=' + boundary, true); } Message.prototype.setBody.call(this, body); } else if (Types.isInstanceOf(body, BinaryData)) { Message.prototype.setBody.call(this, body); } else { Message.prototype.setBody.call(this, new BinaryData(body ? body : '', BinaryData.Encoding.TEXT, BinaryData.CharacterEncoding.UTF8)); } return this; }; /** * Determines if caching is disabled * @method * @returns {Boolean} */ Request.prototype.isCachingDisabled = function () { if (this.getMethod() == Request.POST) { return true; } return false; }; /** * Determines if request is conditional (can return 304 response) * @method * @returns {Boolean} */ Request.prototype.isConditional = function () { return this.getHeader('if-modified-since'); }; /** * Determines if request client allow receiving compressed data * @method * @returns {Boolean} */ Request.prototype.isCompressedContentAccepted = function () { var ae = this.getHeader('accept-encoding'); if (ae) { return ae.indexOf('gzip') > -1; } return false; }; /** * Determines if client requests for regenerate content * @method * @returns {Boolean} */ Request.prototype.isGenerating = function () { return this.getHeader('x-onet-regenerate'); }; /** * Returns JSON representation of a request * @method * @returns {Object} */ Request.prototype.toJson = function () { var body = this.getBody(); return { "url": this.getUrl(), "method": this._method, "headers": this.headers.getHeaders(), "body": body ? body.toString() : body, "httpVersion": this._httpVersion }; }; /** * @constant * @type {String} * @default */ Request.OPTIONS = "OPTIONS"; /** * @constant * @type {String} * @default */ Request.GET = "GET"; /** * @constant * @type {String} * @default */ Request.HEAD = "HEAD"; /** * @constant * @type {String} * @default */ Request.POST = "POST"; /** * @constant * @type {String} * @default */ Request.PUT = "PUT"; /** * @constant * @type {String} * @default */ Request.DELETE = "DELETE"; /** * @constant * @type {String} * @default */ Request.TRACE = "TRACE"; /** * @constant * @type {String} * @default */ Request.CONNECT = "CONNECT"; /** * @static * @constant * @namespace */ Request.Exception = {}; /** * @static * @constant * @type {String} * @default */ Request.Exception.WRONG_BODY = "Body has to be a instance of BinaryData"; /** * @static * @constant * @type {String} * @default */ Request.Exception.REQUEST_CANNOT_BE_A_BUFFER = "Request cannot be a Buffer"; exports.Request = Request;