296 lines
8.3 KiB
JavaScript
296 lines
8.3 KiB
JavaScript
var util = require('../util'),
|
|
_ = util.lodash,
|
|
|
|
E = '',
|
|
SPC = ' ',
|
|
CRLF = '\r\n',
|
|
HEADER_KV_SEPARATOR = ':',
|
|
|
|
Property = require('./property').Property,
|
|
PropertyList = require('./property-list').PropertyList,
|
|
Header;
|
|
|
|
/**
|
|
* @typedef Header.definition
|
|
* @property {String} key The Header name (e.g: 'Content-Type')
|
|
* @property {String} value The value of the header.
|
|
*
|
|
* @example <caption>Create a header</caption>
|
|
* var Header = require('postman-collection').Header,
|
|
* header = new Header({
|
|
* key: 'Content-Type',
|
|
* value: 'application/xml'
|
|
* });
|
|
*
|
|
* console.log(header.toString()) // prints the string representation of the Header.
|
|
*/
|
|
_.inherit((
|
|
|
|
/**
|
|
* Represents an HTTP header, for requests or for responses.
|
|
*
|
|
* @constructor
|
|
* @extends {Property}
|
|
*
|
|
* @param {Header.definition|String} options - Pass the header definition as an object or the value of the header.
|
|
* If the value is passed as a string, it should either be in `name:value` format or the second "name" parameter
|
|
* should be used to pass the name as string
|
|
* @param {String} [name] - optional override the header name or use when the first parameter is the header value as
|
|
* string.
|
|
*
|
|
* @example <caption>Parse a string of headers into an array of Header objects</caption>
|
|
* var Header = require('postman-collection').Header,
|
|
* headerString = 'Content-Type: application/json\nUser-Agent: MyClientLibrary/2.0\n';
|
|
*
|
|
* var rawHeaders = Header.parse(headerString);
|
|
* console.log(rawHeaders); // [{ 'Content-Type': 'application/json', 'User-Agent': 'MyClientLibrary/2.0' }]
|
|
*
|
|
* var headers = rawHeaders.map(function (h) {
|
|
* return new Header(h);
|
|
* });
|
|
*
|
|
* function assert(condition, message) {
|
|
* if (!condition) {
|
|
* message = message || "Assertion failed";
|
|
* if (typeof Error !== "undefined") {
|
|
* throw new Error(message);
|
|
* }
|
|
* throw message; //fallback
|
|
* }
|
|
* else {
|
|
* console.log("Assertion passed");
|
|
* }
|
|
* }
|
|
*
|
|
* assert(headerString.trim() === Header.unparse(headers).trim());
|
|
*/
|
|
Header = function PostmanHeader (options, name) {
|
|
if (_.isString(options)) {
|
|
options = _.isString(name) ? { key: name, value: options } : Header.parseSingle(options);
|
|
}
|
|
|
|
// this constructor is intended to inherit and as such the super constructor is required to be executed
|
|
Header.super_.apply(this, arguments);
|
|
|
|
this.update(options);
|
|
}), Property);
|
|
|
|
_.assign(Header.prototype, /** @lends Header.prototype */ {
|
|
/**
|
|
* Converts the header to a single header string.
|
|
*
|
|
* @returns {String}
|
|
*/
|
|
toString () {
|
|
return this.key + ': ' + this.value;
|
|
},
|
|
|
|
/**
|
|
* Return the value of this header.
|
|
*
|
|
* @returns {String}
|
|
*/
|
|
valueOf () {
|
|
return this.value;
|
|
},
|
|
|
|
/**
|
|
* Assigns the given properties to the Header
|
|
*
|
|
* @param {Object} options -
|
|
* @todo check for allowed characters in header key-value or store encoded.
|
|
*/
|
|
update (options) {
|
|
/**
|
|
* The header Key
|
|
*
|
|
* @type {String}
|
|
* @todo avoid headers with falsy key.
|
|
*/
|
|
this.key = _.get(options, 'key') || E;
|
|
|
|
/**
|
|
* The header value
|
|
*
|
|
* @type {String}
|
|
*/
|
|
this.value = _.get(options, 'value', E);
|
|
|
|
/**
|
|
* Indicates whether the header was added by internal SDK operations, such as authorizing a request.
|
|
*
|
|
* @type {*|boolean}
|
|
*/
|
|
_.has(options, 'system') && (this.system = options.system);
|
|
|
|
/**
|
|
* Indicates whether the header should be .
|
|
*
|
|
* @type {*|boolean}
|
|
* @todo figure out whether this should be in property.js
|
|
*/
|
|
_.has(options, 'disabled') && (this.disabled = options.disabled);
|
|
}
|
|
});
|
|
|
|
_.assign(Header, /** @lends Header */ {
|
|
|
|
/**
|
|
* Defines the name of this property for internal use.
|
|
*
|
|
* @private
|
|
* @readOnly
|
|
* @type {String}
|
|
*/
|
|
_postman_propertyName: 'Header',
|
|
|
|
/**
|
|
* Specify the key to be used while indexing this object
|
|
*
|
|
* @private
|
|
* @readOnly
|
|
* @type {String}
|
|
*/
|
|
_postman_propertyIndexKey: 'key',
|
|
|
|
/**
|
|
* Specifies whether the index lookup of this property, when in a list is case insensitive or not
|
|
*
|
|
* @private
|
|
* @readOnly
|
|
* @type {boolean}
|
|
*/
|
|
_postman_propertyIndexCaseInsensitive: true,
|
|
|
|
/**
|
|
* Since each header may have multiple possible values, this is set to true.
|
|
*
|
|
* @private
|
|
* @readOnly
|
|
* @type {Boolean}
|
|
*/
|
|
_postman_propertyAllowsMultipleValues: true,
|
|
|
|
/**
|
|
* Parses a multi line header string into an array of {@link Header.definition}.
|
|
*
|
|
* @param {String} headerString -
|
|
* @returns {Array}
|
|
*/
|
|
parse: function (headerString) {
|
|
var headers = [],
|
|
regexes = {
|
|
header: /^(\S+):(.*)$/gm,
|
|
fold: /\r\n([ \t])/g,
|
|
trim: /^\s*(.*\S)?\s*$/ // eslint-disable-line security/detect-unsafe-regex
|
|
},
|
|
match = regexes.header.exec(headerString);
|
|
|
|
headerString = headerString.toString().replace(regexes.fold, '$1');
|
|
|
|
while (match) {
|
|
headers.push({
|
|
key: match[1],
|
|
value: match[2].replace(regexes.trim, '$1')
|
|
});
|
|
match = regexes.header.exec(headerString);
|
|
}
|
|
|
|
return headers;
|
|
},
|
|
|
|
/**
|
|
* Parses a single Header.
|
|
*
|
|
* @param {String} header -
|
|
* @returns {{key: String, value: String}}
|
|
*/
|
|
parseSingle: function (header) {
|
|
if (!_.isString(header)) { return { key: E, value: E }; }
|
|
|
|
var index = header.indexOf(HEADER_KV_SEPARATOR),
|
|
key,
|
|
value;
|
|
|
|
(index < 0) && (index = header.length);
|
|
|
|
key = header.substr(0, index);
|
|
value = header.substr(index + 1);
|
|
|
|
return {
|
|
key: _.trim(key),
|
|
value: _.trim(value)
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Stringifies an Array or {@link PropertyList} of Headers into a single string.
|
|
*
|
|
* @note Disabled headers are excluded.
|
|
*
|
|
* @param {Array|PropertyList<Header>} headers -
|
|
* @param {String=} [separator='\r\n'] - Specify a string for separating each header
|
|
* @returns {String}
|
|
*/
|
|
unparse: function (headers, separator = CRLF) {
|
|
if (!_.isArray(headers) && !PropertyList.isPropertyList(headers)) {
|
|
return E;
|
|
}
|
|
|
|
return headers.reduce(function (acc, header) {
|
|
if (header && !header.disabled) {
|
|
acc += Header.unparseSingle(header) + separator;
|
|
}
|
|
|
|
return acc;
|
|
}, E);
|
|
},
|
|
|
|
/**
|
|
* Unparses a single Header.
|
|
*
|
|
* @param {String} header -
|
|
* @returns {String}
|
|
*/
|
|
unparseSingle: function (header) {
|
|
if (!_.isObject(header)) { return E; }
|
|
|
|
return header.key + HEADER_KV_SEPARATOR + SPC + header.value;
|
|
},
|
|
|
|
/**
|
|
* Check whether an object is an instance of PostmanHeader.
|
|
*
|
|
* @param {*} obj -
|
|
* @returns {Boolean}
|
|
*/
|
|
isHeader: function (obj) {
|
|
return Boolean(obj) && ((obj instanceof Header) ||
|
|
_.inSuperChain(obj.constructor, '_postman_propertyName', Header._postman_propertyName));
|
|
},
|
|
|
|
/* eslint-disable jsdoc/check-param-names */
|
|
/**
|
|
* Create a new header instance
|
|
*
|
|
* @param {Header.definition|String} [value] - Pass the header definition as an object or the value of the header.
|
|
* If the value is passed as a string, it should either be in `name:value` format or the second "name" parameter
|
|
* should be used to pass the name as string
|
|
* @param {String} [name] - optional override the header name or use when the first parameter is the header value as
|
|
* string.
|
|
* @returns {Header}
|
|
*/
|
|
create: function () {
|
|
var args = Array.prototype.slice.call(arguments);
|
|
|
|
args.unshift(Header);
|
|
|
|
return new (Header.bind.apply(Header, args))(); // eslint-disable-line prefer-spread
|
|
}
|
|
/* eslint-enable jsdoc/check-param-names */
|
|
});
|
|
|
|
module.exports = {
|
|
Header
|
|
};
|