node-fetch/src/headers.js

235 lines
4.5 KiB
JavaScript
Raw Normal View History

2016-04-05 10:43:12 -07:00
2015-01-27 05:11:26 -08:00
/**
* headers.js
*
* Headers class offers convenient helpers
*/
import getIterator from 'babel-runtime/core-js/get-iterator';
2016-10-10 15:32:56 -07:00
import { _checkIsHttpToken, _checkInvalidHeaderChar } from './common.js';
function sanitizeName(name) {
name += '';
if (!_checkIsHttpToken(name)) {
throw new TypeError(`${name} is not a legal HTTP header name`);
}
return name.toLowerCase();
}
function sanitizeValue(value) {
value += '';
if (_checkInvalidHeaderChar(value)) {
throw new TypeError(`${value} is not a legal HTTP header value`);
}
return value;
}
2016-10-10 15:32:56 -07:00
export const MAP = Symbol('map');
2016-10-10 18:31:53 -07:00
const FOLLOW_SPEC = Symbol('followSpec');
export default class Headers {
/**
* Headers class
*
* @param Object headers Response headers
* @return Void
*/
constructor(headers) {
this[MAP] = Object.create(null);
2016-10-10 18:31:53 -07:00
this[FOLLOW_SPEC] = Headers.FOLLOW_SPEC;
// Headers
if (headers instanceof Headers) {
let init = headers.raw();
for (let name of Object.keys(init)) {
for (let value of init[name]) {
this.append(name, value);
}
}
} else if (Array.isArray(headers)) {
// array of tuples
for (let el of headers) {
if (!Array.isArray(el) || el.length !== 2) {
throw new TypeError('Header pairs must contain exactly two items');
}
this.append(el[0], el[1]);
}
} else if (typeof headers === 'object') {
// plain object
for (const prop of Object.keys(headers)) {
// We don't worry about converting prop to ByteString here as append()
// will handle it.
this.append(prop, headers[prop]);
}
}
}
2015-01-27 05:11:26 -08:00
/**
* Return first header value given name
*
* @param String name Header name
* @return Mixed
*/
get(name) {
2016-10-10 15:32:56 -07:00
const list = this[MAP][sanitizeName(name)];
2016-10-10 18:31:53 -07:00
if (!list) {
return null;
}
return this[FOLLOW_SPEC] ? list.join(',') : list[0];
2015-04-22 08:36:11 -07:00
}
/**
* Return all header values given name
*
* @param String name Header name
* @return Array
*/
getAll(name) {
if (!this.has(name)) {
return [];
}
2016-10-10 15:32:56 -07:00
return this[MAP][sanitizeName(name)];
}
/**
* Iterate over all headers
*
* @param Function callback Executed for each item with parameters (value, name, thisArg)
* @param Boolean thisArg `this` context for callback function
* @return Void
*/
forEach(callback, thisArg) {
for (let name in this[MAP]) {
this[MAP][name].forEach(value => {
callback.call(thisArg, value, name, this);
});
}
}
/**
* Overwrite header values given name
*
* @param String name Header name
* @param String value Header value
* @return Void
*/
set(name, value) {
2016-10-10 15:32:56 -07:00
this[MAP][sanitizeName(name)] = [sanitizeValue(value)];
}
/**
* Append a value onto existing header
*
* @param String name Header name
* @param String value Header value
* @return Void
*/
append(name, value) {
if (!this.has(name)) {
this.set(name, value);
return;
2015-01-27 05:11:26 -08:00
}
2016-10-10 15:32:56 -07:00
this[MAP][sanitizeName(name)].push(sanitizeValue(value));
2015-01-27 05:11:26 -08:00
}
/**
* Check for header name existence
*
* @param String name Header name
* @return Boolean
*/
has(name) {
return !!this[MAP][sanitizeName(name)];
}
2015-01-27 05:11:26 -08:00
/**
* Delete all header values given name
*
* @param String name Header name
* @return Void
*/
delete(name) {
2016-10-10 15:32:56 -07:00
delete this[MAP][sanitizeName(name)];
};
/**
* Return raw headers (non-spec api)
*
* @return Object
*/
raw() {
return this[MAP];
}
2015-01-27 05:11:26 -08:00
/**
* Get an iterator on keys.
*
* @return Iterator
*/
keys() {
2016-10-10 18:31:53 -07:00
let keys = [];
if (this[FOLLOW_SPEC]) {
keys = Object.keys(this[MAP]).sort();
} else {
this.forEach((_, name) => keys.push(name));
};
return getIterator(keys);
2015-01-27 05:11:26 -08:00
}
/**
* Get an iterator on values.
*
* @return Iterator
*/
2016-10-10 18:31:53 -07:00
*values() {
if (this[FOLLOW_SPEC]) {
for (const name of this.keys()) {
yield this.get(name);
}
} else {
const values = [];
this.forEach(value => values.push(value));
yield* getIterator(values);
2016-10-10 18:31:53 -07:00
}
}
2015-01-27 05:11:26 -08:00
/**
* Get an iterator on entries.
*
* @return Iterator
*/
2016-10-10 18:31:53 -07:00
*entries() {
if (this[FOLLOW_SPEC]) {
for (const name of this.keys()) {
yield [name, this.get(name)];
}
} else {
const entries = [];
this.forEach((value, name) => entries.push([name, value]));
yield* getIterator(entries);
2016-10-10 18:31:53 -07:00
}
}
2015-10-26 22:13:02 -07:00
/**
* Get an iterator on entries.
*
* This is the default iterator of the Headers object.
*
* @return Iterator
*/
[Symbol.iterator]() {
return this.entries();
}
2015-01-27 05:11:26 -08:00
/**
* Tag used by `Object.prototype.toString()`.
*/
get [Symbol.toStringTag]() {
return 'Headers';
2015-01-27 05:11:26 -08:00
}
}
2015-01-27 05:11:26 -08:00
2016-10-10 18:31:53 -07:00
Headers.FOLLOW_SPEC = false;