index.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. // Based on https://github.com/tmpvar/jsdom/blob/aa85b2abf07766ff7bf5c1f6daafb3726f2f2db5/lib/jsdom/living/blob.js
  4. // (MIT licensed)
  5. const BUFFER = Symbol('buffer');
  6. const TYPE = Symbol('type');
  7. const CLOSED = Symbol('closed');
  8. class Blob {
  9. constructor() {
  10. Object.defineProperty(this, Symbol.toStringTag, {
  11. value: 'Blob',
  12. writable: false,
  13. enumerable: false,
  14. configurable: true
  15. });
  16. this[CLOSED] = false;
  17. this[TYPE] = '';
  18. const blobParts = arguments[0];
  19. const options = arguments[1];
  20. const buffers = [];
  21. if (blobParts) {
  22. const a = blobParts;
  23. const length = Number(a.length);
  24. for (let i = 0; i < length; i++) {
  25. const element = a[i];
  26. let buffer;
  27. if (element instanceof Buffer) {
  28. buffer = element;
  29. } else if (ArrayBuffer.isView(element)) {
  30. buffer = Buffer.from(element.buffer, element.byteOffset, element.byteLength);
  31. } else if (element instanceof ArrayBuffer) {
  32. buffer = Buffer.from(element);
  33. } else if (element instanceof Blob) {
  34. buffer = element[BUFFER];
  35. } else {
  36. buffer = Buffer.from(typeof element === 'string' ? element : String(element));
  37. }
  38. buffers.push(buffer);
  39. }
  40. }
  41. this[BUFFER] = Buffer.concat(buffers);
  42. let type = options && options.type !== undefined && String(options.type).toLowerCase();
  43. if (type && !/[^\u0020-\u007E]/.test(type)) {
  44. this[TYPE] = type;
  45. }
  46. }
  47. get size() {
  48. return this[CLOSED] ? 0 : this[BUFFER].length;
  49. }
  50. get type() {
  51. return this[TYPE];
  52. }
  53. get isClosed() {
  54. return this[CLOSED];
  55. }
  56. slice() {
  57. const size = this.size;
  58. const start = arguments[0];
  59. const end = arguments[1];
  60. let relativeStart, relativeEnd;
  61. if (start === undefined) {
  62. relativeStart = 0;
  63. } else if (start < 0) {
  64. relativeStart = Math.max(size + start, 0);
  65. } else {
  66. relativeStart = Math.min(start, size);
  67. }
  68. if (end === undefined) {
  69. relativeEnd = size;
  70. } else if (end < 0) {
  71. relativeEnd = Math.max(size + end, 0);
  72. } else {
  73. relativeEnd = Math.min(end, size);
  74. }
  75. const span = Math.max(relativeEnd - relativeStart, 0);
  76. const buffer = this[BUFFER];
  77. const slicedBuffer = buffer.slice(relativeStart, relativeStart + span);
  78. const blob = new Blob([], { type: arguments[2] });
  79. blob[BUFFER] = slicedBuffer;
  80. blob[CLOSED] = this[CLOSED];
  81. return blob;
  82. }
  83. close() {
  84. this[CLOSED] = true;
  85. }
  86. }
  87. Object.defineProperty(Blob.prototype, Symbol.toStringTag, {
  88. value: 'BlobPrototype',
  89. writable: false,
  90. enumerable: false,
  91. configurable: true
  92. });
  93. /**
  94. * fetch-error.js
  95. *
  96. * FetchError interface for operational errors
  97. */
  98. /**
  99. * Create FetchError instance
  100. *
  101. * @param String message Error message for human
  102. * @param String type Error type for machine
  103. * @param String systemError For Node.js system error
  104. * @return FetchError
  105. */
  106. function FetchError(message, type, systemError) {
  107. Error.call(this, message);
  108. this.message = message;
  109. this.type = type;
  110. // when err.type is `system`, err.code contains system error code
  111. if (systemError) {
  112. this.code = this.errno = systemError.code;
  113. }
  114. // hide custom error implementation details from end-users
  115. Error.captureStackTrace(this, this.constructor);
  116. }
  117. FetchError.prototype = Object.create(Error.prototype);
  118. FetchError.prototype.constructor = FetchError;
  119. FetchError.prototype.name = 'FetchError';
  120. /**
  121. * body.js
  122. *
  123. * Body interface provides common methods for Request and Response
  124. */
  125. const Stream = require('stream');
  126. var _require$1 = require('stream');
  127. const PassThrough$1 = _require$1.PassThrough;
  128. const DISTURBED = Symbol('disturbed');
  129. let convert;
  130. try {
  131. convert = require('encoding').convert;
  132. } catch (e) {}
  133. /**
  134. * Body class
  135. *
  136. * Cannot use ES6 class because Body must be called with .call().
  137. *
  138. * @param Stream body Readable stream
  139. * @param Object opts Response options
  140. * @return Void
  141. */
  142. function Body(body) {
  143. var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
  144. _ref$size = _ref.size;
  145. let size = _ref$size === undefined ? 0 : _ref$size;
  146. var _ref$timeout = _ref.timeout;
  147. let timeout = _ref$timeout === undefined ? 0 : _ref$timeout;
  148. if (body == null) {
  149. // body is undefined or null
  150. body = null;
  151. } else if (typeof body === 'string') {
  152. // body is string
  153. } else if (isURLSearchParams(body)) {
  154. // body is a URLSearchParams
  155. } else if (body instanceof Blob) {
  156. // body is blob
  157. } else if (Buffer.isBuffer(body)) {
  158. // body is buffer
  159. } else if (body instanceof Stream) {
  160. // body is stream
  161. } else {
  162. // none of the above
  163. // coerce to string
  164. body = String(body);
  165. }
  166. this.body = body;
  167. this[DISTURBED] = false;
  168. this.size = size;
  169. this.timeout = timeout;
  170. }
  171. Body.prototype = {
  172. get bodyUsed() {
  173. return this[DISTURBED];
  174. },
  175. /**
  176. * Decode response as ArrayBuffer
  177. *
  178. * @return Promise
  179. */
  180. arrayBuffer() {
  181. return consumeBody.call(this).then(function (buf) {
  182. return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
  183. });
  184. },
  185. /**
  186. * Return raw response as Blob
  187. *
  188. * @return Promise
  189. */
  190. blob() {
  191. let ct = this.headers && this.headers.get('content-type') || '';
  192. return consumeBody.call(this).then(function (buf) {
  193. return Object.assign(
  194. // Prevent copying
  195. new Blob([], {
  196. type: ct.toLowerCase()
  197. }), {
  198. [BUFFER]: buf
  199. });
  200. });
  201. },
  202. /**
  203. * Decode response as json
  204. *
  205. * @return Promise
  206. */
  207. json() {
  208. var _this = this;
  209. return consumeBody.call(this).then(function (buffer) {
  210. try {
  211. return JSON.parse(buffer.toString());
  212. } catch (err) {
  213. return Body.Promise.reject(new FetchError(`invalid json response body at ${_this.url} reason: ${err.message}`, 'invalid-json'));
  214. }
  215. });
  216. },
  217. /**
  218. * Decode response as text
  219. *
  220. * @return Promise
  221. */
  222. text() {
  223. return consumeBody.call(this).then(function (buffer) {
  224. return buffer.toString();
  225. });
  226. },
  227. /**
  228. * Decode response as buffer (non-spec api)
  229. *
  230. * @return Promise
  231. */
  232. buffer() {
  233. return consumeBody.call(this);
  234. },
  235. /**
  236. * Decode response as text, while automatically detecting the encoding and
  237. * trying to decode to UTF-8 (non-spec api)
  238. *
  239. * @return Promise
  240. */
  241. textConverted() {
  242. var _this2 = this;
  243. return consumeBody.call(this).then(function (buffer) {
  244. return convertBody(buffer, _this2.headers);
  245. });
  246. }
  247. };
  248. Body.mixIn = function (proto) {
  249. for (const name of Object.getOwnPropertyNames(Body.prototype)) {
  250. // istanbul ignore else: future proof
  251. if (!(name in proto)) {
  252. const desc = Object.getOwnPropertyDescriptor(Body.prototype, name);
  253. Object.defineProperty(proto, name, desc);
  254. }
  255. }
  256. };
  257. /**
  258. * Decode buffers into utf-8 string
  259. *
  260. * @return Promise
  261. */
  262. function consumeBody(body) {
  263. var _this3 = this;
  264. if (this[DISTURBED]) {
  265. return Body.Promise.reject(new Error(`body used already for: ${this.url}`));
  266. }
  267. this[DISTURBED] = true;
  268. // body is null
  269. if (this.body === null) {
  270. return Body.Promise.resolve(Buffer.alloc(0));
  271. }
  272. // body is string
  273. if (typeof this.body === 'string') {
  274. return Body.Promise.resolve(Buffer.from(this.body));
  275. }
  276. // body is blob
  277. if (this.body instanceof Blob) {
  278. return Body.Promise.resolve(this.body[BUFFER]);
  279. }
  280. // body is buffer
  281. if (Buffer.isBuffer(this.body)) {
  282. return Body.Promise.resolve(this.body);
  283. }
  284. // istanbul ignore if: should never happen
  285. if (!(this.body instanceof Stream)) {
  286. return Body.Promise.resolve(Buffer.alloc(0));
  287. }
  288. // body is stream
  289. // get ready to actually consume the body
  290. let accum = [];
  291. let accumBytes = 0;
  292. let abort = false;
  293. return new Body.Promise(function (resolve, reject) {
  294. let resTimeout;
  295. // allow timeout on slow response body
  296. if (_this3.timeout) {
  297. resTimeout = setTimeout(function () {
  298. abort = true;
  299. reject(new FetchError(`Response timeout while trying to fetch ${_this3.url} (over ${_this3.timeout}ms)`, 'body-timeout'));
  300. }, _this3.timeout);
  301. }
  302. // handle stream error, such as incorrect content-encoding
  303. _this3.body.on('error', function (err) {
  304. reject(new FetchError(`Invalid response body while trying to fetch ${_this3.url}: ${err.message}`, 'system', err));
  305. });
  306. _this3.body.on('data', function (chunk) {
  307. if (abort || chunk === null) {
  308. return;
  309. }
  310. if (_this3.size && accumBytes + chunk.length > _this3.size) {
  311. abort = true;
  312. reject(new FetchError(`content size at ${_this3.url} over limit: ${_this3.size}`, 'max-size'));
  313. return;
  314. }
  315. accumBytes += chunk.length;
  316. accum.push(chunk);
  317. });
  318. _this3.body.on('end', function () {
  319. if (abort) {
  320. return;
  321. }
  322. clearTimeout(resTimeout);
  323. resolve(Buffer.concat(accum));
  324. });
  325. });
  326. }
  327. /**
  328. * Detect buffer encoding and convert to target encoding
  329. * ref: http://www.w3.org/TR/2011/WD-html5-20110113/parsing.html#determining-the-character-encoding
  330. *
  331. * @param Buffer buffer Incoming buffer
  332. * @param String encoding Target encoding
  333. * @return String
  334. */
  335. function convertBody(buffer, headers) {
  336. if (typeof convert !== 'function') {
  337. throw new Error('The package `encoding` must be installed to use the textConverted() function');
  338. }
  339. const ct = headers.get('content-type');
  340. let charset = 'utf-8';
  341. let res, str;
  342. // header
  343. if (ct) {
  344. res = /charset=([^;]*)/i.exec(ct);
  345. }
  346. // no charset in content type, peek at response body for at most 1024 bytes
  347. str = buffer.slice(0, 1024).toString();
  348. // html5
  349. if (!res && str) {
  350. res = /<meta.+?charset=(['"])(.+?)\1/i.exec(str);
  351. }
  352. // html4
  353. if (!res && str) {
  354. res = /<meta[\s]+?http-equiv=(['"])content-type\1[\s]+?content=(['"])(.+?)\2/i.exec(str);
  355. if (res) {
  356. res = /charset=(.*)/i.exec(res.pop());
  357. }
  358. }
  359. // xml
  360. if (!res && str) {
  361. res = /<\?xml.+?encoding=(['"])(.+?)\1/i.exec(str);
  362. }
  363. // found charset
  364. if (res) {
  365. charset = res.pop();
  366. // prevent decode issues when sites use incorrect encoding
  367. // ref: https://hsivonen.fi/encoding-menu/
  368. if (charset === 'gb2312' || charset === 'gbk') {
  369. charset = 'gb18030';
  370. }
  371. }
  372. // turn raw buffers into a single utf-8 buffer
  373. return convert(buffer, 'UTF-8', charset).toString();
  374. }
  375. /**
  376. * Detect a URLSearchParams object
  377. * ref: https://github.com/bitinn/node-fetch/issues/296#issuecomment-307598143
  378. *
  379. * @param Object obj Object to detect by type or brand
  380. * @return String
  381. */
  382. function isURLSearchParams(obj) {
  383. // Duck-typing as a necessary condition.
  384. if (typeof obj !== 'object' || typeof obj.append !== 'function' || typeof obj.delete !== 'function' || typeof obj.get !== 'function' || typeof obj.getAll !== 'function' || typeof obj.has !== 'function' || typeof obj.set !== 'function') {
  385. return false;
  386. }
  387. // Brand-checking and more duck-typing as optional condition.
  388. return obj.constructor.name === 'URLSearchParams' || Object.prototype.toString.call(obj) === '[object URLSearchParams]' || typeof obj.sort === 'function';
  389. }
  390. /**
  391. * Clone body given Res/Req instance
  392. *
  393. * @param Mixed instance Response or Request instance
  394. * @return Mixed
  395. */
  396. function clone(instance) {
  397. let p1, p2;
  398. let body = instance.body;
  399. // don't allow cloning a used body
  400. if (instance.bodyUsed) {
  401. throw new Error('cannot clone body after it is used');
  402. }
  403. // check that body is a stream and not form-data object
  404. // note: we can't clone the form-data object without having it as a dependency
  405. if (body instanceof Stream && typeof body.getBoundary !== 'function') {
  406. // tee instance body
  407. p1 = new PassThrough$1();
  408. p2 = new PassThrough$1();
  409. body.pipe(p1);
  410. body.pipe(p2);
  411. // set instance body to teed body and return the other teed body
  412. instance.body = p1;
  413. body = p2;
  414. }
  415. return body;
  416. }
  417. /**
  418. * Performs the operation "extract a `Content-Type` value from |object|" as
  419. * specified in the specification:
  420. * https://fetch.spec.whatwg.org/#concept-bodyinit-extract
  421. *
  422. * This function assumes that instance.body is present and non-null.
  423. *
  424. * @param Mixed instance Response or Request instance
  425. */
  426. function extractContentType(instance) {
  427. const body = instance.body;
  428. // istanbul ignore if: Currently, because of a guard in Request, body
  429. // can never be null. Included here for completeness.
  430. if (body === null) {
  431. // body is null
  432. return null;
  433. } else if (typeof body === 'string') {
  434. // body is string
  435. return 'text/plain;charset=UTF-8';
  436. } else if (isURLSearchParams(body)) {
  437. // body is a URLSearchParams
  438. return 'application/x-www-form-urlencoded;charset=UTF-8';
  439. } else if (body instanceof Blob) {
  440. // body is blob
  441. return body.type || null;
  442. } else if (Buffer.isBuffer(body)) {
  443. // body is buffer
  444. return null;
  445. } else if (typeof body.getBoundary === 'function') {
  446. // detect form data input from form-data module
  447. return `multipart/form-data;boundary=${body.getBoundary()}`;
  448. } else {
  449. // body is stream
  450. // can't really do much about this
  451. return null;
  452. }
  453. }
  454. function getTotalBytes(instance) {
  455. const body = instance.body;
  456. // istanbul ignore if: included for completion
  457. if (body === null) {
  458. // body is null
  459. return 0;
  460. } else if (typeof body === 'string') {
  461. // body is string
  462. return Buffer.byteLength(body);
  463. } else if (isURLSearchParams(body)) {
  464. // body is URLSearchParams
  465. return Buffer.byteLength(String(body));
  466. } else if (body instanceof Blob) {
  467. // body is blob
  468. return body.size;
  469. } else if (Buffer.isBuffer(body)) {
  470. // body is buffer
  471. return body.length;
  472. } else if (body && typeof body.getLengthSync === 'function') {
  473. // detect form data input from form-data module
  474. if (body._lengthRetrievers && body._lengthRetrievers.length == 0 || // 1.x
  475. body.hasKnownLength && body.hasKnownLength()) {
  476. // 2.x
  477. return body.getLengthSync();
  478. }
  479. return null;
  480. } else {
  481. // body is stream
  482. // can't really do much about this
  483. return null;
  484. }
  485. }
  486. function writeToStream(dest, instance) {
  487. const body = instance.body;
  488. if (body === null) {
  489. // body is null
  490. dest.end();
  491. } else if (typeof body === 'string') {
  492. // body is string
  493. dest.write(body);
  494. dest.end();
  495. } else if (isURLSearchParams(body)) {
  496. // body is URLSearchParams
  497. dest.write(Buffer.from(String(body)));
  498. dest.end();
  499. } else if (body instanceof Blob) {
  500. // body is blob
  501. dest.write(body[BUFFER]);
  502. dest.end();
  503. } else if (Buffer.isBuffer(body)) {
  504. // body is buffer
  505. dest.write(body);
  506. dest.end();
  507. } else {
  508. // body is stream
  509. body.pipe(dest);
  510. }
  511. }
  512. // expose Promise
  513. Body.Promise = global.Promise;
  514. /**
  515. * A set of utilities borrowed from Node.js' _http_common.js
  516. */
  517. /**
  518. * Verifies that the given val is a valid HTTP token
  519. * per the rules defined in RFC 7230
  520. * See https://tools.ietf.org/html/rfc7230#section-3.2.6
  521. *
  522. * Allowed characters in an HTTP token:
  523. * ^_`a-z 94-122
  524. * A-Z 65-90
  525. * - 45
  526. * 0-9 48-57
  527. * ! 33
  528. * #$%&' 35-39
  529. * *+ 42-43
  530. * . 46
  531. * | 124
  532. * ~ 126
  533. *
  534. * This implementation of checkIsHttpToken() loops over the string instead of
  535. * using a regular expression since the former is up to 180% faster with v8 4.9
  536. * depending on the string length (the shorter the string, the larger the
  537. * performance difference)
  538. *
  539. * Additionally, checkIsHttpToken() is currently designed to be inlinable by v8,
  540. * so take care when making changes to the implementation so that the source
  541. * code size does not exceed v8's default max_inlined_source_size setting.
  542. **/
  543. /* istanbul ignore next */
  544. function isValidTokenChar(ch) {
  545. if (ch >= 94 && ch <= 122) return true;
  546. if (ch >= 65 && ch <= 90) return true;
  547. if (ch === 45) return true;
  548. if (ch >= 48 && ch <= 57) return true;
  549. if (ch === 34 || ch === 40 || ch === 41 || ch === 44) return false;
  550. if (ch >= 33 && ch <= 46) return true;
  551. if (ch === 124 || ch === 126) return true;
  552. return false;
  553. }
  554. /* istanbul ignore next */
  555. function checkIsHttpToken(val) {
  556. if (typeof val !== 'string' || val.length === 0) return false;
  557. if (!isValidTokenChar(val.charCodeAt(0))) return false;
  558. const len = val.length;
  559. if (len > 1) {
  560. if (!isValidTokenChar(val.charCodeAt(1))) return false;
  561. if (len > 2) {
  562. if (!isValidTokenChar(val.charCodeAt(2))) return false;
  563. if (len > 3) {
  564. if (!isValidTokenChar(val.charCodeAt(3))) return false;
  565. for (var i = 4; i < len; i++) {
  566. if (!isValidTokenChar(val.charCodeAt(i))) return false;
  567. }
  568. }
  569. }
  570. }
  571. return true;
  572. }
  573. /**
  574. * True if val contains an invalid field-vchar
  575. * field-value = *( field-content / obs-fold )
  576. * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
  577. * field-vchar = VCHAR / obs-text
  578. *
  579. * checkInvalidHeaderChar() is currently designed to be inlinable by v8,
  580. * so take care when making changes to the implementation so that the source
  581. * code size does not exceed v8's default max_inlined_source_size setting.
  582. **/
  583. /* istanbul ignore next */
  584. function checkInvalidHeaderChar(val) {
  585. val += '';
  586. if (val.length < 1) return false;
  587. var c = val.charCodeAt(0);
  588. if (c <= 31 && c !== 9 || c > 255 || c === 127) return true;
  589. if (val.length < 2) return false;
  590. c = val.charCodeAt(1);
  591. if (c <= 31 && c !== 9 || c > 255 || c === 127) return true;
  592. if (val.length < 3) return false;
  593. c = val.charCodeAt(2);
  594. if (c <= 31 && c !== 9 || c > 255 || c === 127) return true;
  595. for (var i = 3; i < val.length; ++i) {
  596. c = val.charCodeAt(i);
  597. if (c <= 31 && c !== 9 || c > 255 || c === 127) return true;
  598. }
  599. return false;
  600. }
  601. /**
  602. * headers.js
  603. *
  604. * Headers class offers convenient helpers
  605. */
  606. function sanitizeName(name) {
  607. name += '';
  608. if (!checkIsHttpToken(name)) {
  609. throw new TypeError(`${name} is not a legal HTTP header name`);
  610. }
  611. return name.toLowerCase();
  612. }
  613. function sanitizeValue(value) {
  614. value += '';
  615. if (checkInvalidHeaderChar(value)) {
  616. throw new TypeError(`${value} is not a legal HTTP header value`);
  617. }
  618. return value;
  619. }
  620. const MAP = Symbol('map');
  621. class Headers {
  622. /**
  623. * Headers class
  624. *
  625. * @param Object headers Response headers
  626. * @return Void
  627. */
  628. constructor() {
  629. let init = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;
  630. this[MAP] = Object.create(null);
  631. if (init instanceof Headers) {
  632. const rawHeaders = init.raw();
  633. const headerNames = Object.keys(rawHeaders);
  634. for (const headerName of headerNames) {
  635. for (const value of rawHeaders[headerName]) {
  636. this.append(headerName, value);
  637. }
  638. }
  639. return;
  640. }
  641. // We don't worry about converting prop to ByteString here as append()
  642. // will handle it.
  643. if (init == null) {
  644. // no op
  645. } else if (typeof init === 'object') {
  646. const method = init[Symbol.iterator];
  647. if (method != null) {
  648. if (typeof method !== 'function') {
  649. throw new TypeError('Header pairs must be iterable');
  650. }
  651. // sequence<sequence<ByteString>>
  652. // Note: per spec we have to first exhaust the lists then process them
  653. const pairs = [];
  654. for (const pair of init) {
  655. if (typeof pair !== 'object' || typeof pair[Symbol.iterator] !== 'function') {
  656. throw new TypeError('Each header pair must be iterable');
  657. }
  658. pairs.push(Array.from(pair));
  659. }
  660. for (const pair of pairs) {
  661. if (pair.length !== 2) {
  662. throw new TypeError('Each header pair must be a name/value tuple');
  663. }
  664. this.append(pair[0], pair[1]);
  665. }
  666. } else {
  667. // record<ByteString, ByteString>
  668. for (const key of Object.keys(init)) {
  669. const value = init[key];
  670. this.append(key, value);
  671. }
  672. }
  673. } else {
  674. throw new TypeError('Provided initializer must be an object');
  675. }
  676. Object.defineProperty(this, Symbol.toStringTag, {
  677. value: 'Headers',
  678. writable: false,
  679. enumerable: false,
  680. configurable: true
  681. });
  682. }
  683. /**
  684. * Return first header value given name
  685. *
  686. * @param String name Header name
  687. * @return Mixed
  688. */
  689. get(name) {
  690. const list = this[MAP][sanitizeName(name)];
  691. if (!list) {
  692. return null;
  693. }
  694. return list.join(', ');
  695. }
  696. /**
  697. * Iterate over all headers
  698. *
  699. * @param Function callback Executed for each item with parameters (value, name, thisArg)
  700. * @param Boolean thisArg `this` context for callback function
  701. * @return Void
  702. */
  703. forEach(callback) {
  704. let thisArg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
  705. let pairs = getHeaderPairs(this);
  706. let i = 0;
  707. while (i < pairs.length) {
  708. var _pairs$i = pairs[i];
  709. const name = _pairs$i[0],
  710. value = _pairs$i[1];
  711. callback.call(thisArg, value, name, this);
  712. pairs = getHeaderPairs(this);
  713. i++;
  714. }
  715. }
  716. /**
  717. * Overwrite header values given name
  718. *
  719. * @param String name Header name
  720. * @param String value Header value
  721. * @return Void
  722. */
  723. set(name, value) {
  724. this[MAP][sanitizeName(name)] = [sanitizeValue(value)];
  725. }
  726. /**
  727. * Append a value onto existing header
  728. *
  729. * @param String name Header name
  730. * @param String value Header value
  731. * @return Void
  732. */
  733. append(name, value) {
  734. if (!this.has(name)) {
  735. this.set(name, value);
  736. return;
  737. }
  738. this[MAP][sanitizeName(name)].push(sanitizeValue(value));
  739. }
  740. /**
  741. * Check for header name existence
  742. *
  743. * @param String name Header name
  744. * @return Boolean
  745. */
  746. has(name) {
  747. return !!this[MAP][sanitizeName(name)];
  748. }
  749. /**
  750. * Delete all header values given name
  751. *
  752. * @param String name Header name
  753. * @return Void
  754. */
  755. delete(name) {
  756. delete this[MAP][sanitizeName(name)];
  757. }
  758. /**
  759. * Return raw headers (non-spec api)
  760. *
  761. * @return Object
  762. */
  763. raw() {
  764. return this[MAP];
  765. }
  766. /**
  767. * Get an iterator on keys.
  768. *
  769. * @return Iterator
  770. */
  771. keys() {
  772. return createHeadersIterator(this, 'key');
  773. }
  774. /**
  775. * Get an iterator on values.
  776. *
  777. * @return Iterator
  778. */
  779. values() {
  780. return createHeadersIterator(this, 'value');
  781. }
  782. /**
  783. * Get an iterator on entries.
  784. *
  785. * This is the default iterator of the Headers object.
  786. *
  787. * @return Iterator
  788. */
  789. [Symbol.iterator]() {
  790. return createHeadersIterator(this, 'key+value');
  791. }
  792. }
  793. Headers.prototype.entries = Headers.prototype[Symbol.iterator];
  794. Object.defineProperty(Headers.prototype, Symbol.toStringTag, {
  795. value: 'HeadersPrototype',
  796. writable: false,
  797. enumerable: false,
  798. configurable: true
  799. });
  800. function getHeaderPairs(headers, kind) {
  801. const keys = Object.keys(headers[MAP]).sort();
  802. return keys.map(kind === 'key' ? function (k) {
  803. return [k];
  804. } : function (k) {
  805. return [k, headers.get(k)];
  806. });
  807. }
  808. const INTERNAL = Symbol('internal');
  809. function createHeadersIterator(target, kind) {
  810. const iterator = Object.create(HeadersIteratorPrototype);
  811. iterator[INTERNAL] = {
  812. target,
  813. kind,
  814. index: 0
  815. };
  816. return iterator;
  817. }
  818. const HeadersIteratorPrototype = Object.setPrototypeOf({
  819. next() {
  820. // istanbul ignore if
  821. if (!this || Object.getPrototypeOf(this) !== HeadersIteratorPrototype) {
  822. throw new TypeError('Value of `this` is not a HeadersIterator');
  823. }
  824. var _INTERNAL = this[INTERNAL];
  825. const target = _INTERNAL.target,
  826. kind = _INTERNAL.kind,
  827. index = _INTERNAL.index;
  828. const values = getHeaderPairs(target, kind);
  829. const len = values.length;
  830. if (index >= len) {
  831. return {
  832. value: undefined,
  833. done: true
  834. };
  835. }
  836. const pair = values[index];
  837. this[INTERNAL].index = index + 1;
  838. let result;
  839. if (kind === 'key') {
  840. result = pair[0];
  841. } else if (kind === 'value') {
  842. result = pair[1];
  843. } else {
  844. result = pair;
  845. }
  846. return {
  847. value: result,
  848. done: false
  849. };
  850. }
  851. }, Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())));
  852. Object.defineProperty(HeadersIteratorPrototype, Symbol.toStringTag, {
  853. value: 'HeadersIterator',
  854. writable: false,
  855. enumerable: false,
  856. configurable: true
  857. });
  858. /**
  859. * response.js
  860. *
  861. * Response class provides content decoding
  862. */
  863. var _require$2 = require('http');
  864. const STATUS_CODES = _require$2.STATUS_CODES;
  865. /**
  866. * Response class
  867. *
  868. * @param Stream body Readable stream
  869. * @param Object opts Response options
  870. * @return Void
  871. */
  872. class Response {
  873. constructor() {
  874. let body = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
  875. let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  876. Body.call(this, body, opts);
  877. this.url = opts.url;
  878. this.status = opts.status || 200;
  879. this.statusText = opts.statusText || STATUS_CODES[this.status];
  880. this.headers = new Headers(opts.headers);
  881. Object.defineProperty(this, Symbol.toStringTag, {
  882. value: 'Response',
  883. writable: false,
  884. enumerable: false,
  885. configurable: true
  886. });
  887. }
  888. /**
  889. * Convenience property representing if the request ended normally
  890. */
  891. get ok() {
  892. return this.status >= 200 && this.status < 300;
  893. }
  894. /**
  895. * Clone this response
  896. *
  897. * @return Response
  898. */
  899. clone() {
  900. return new Response(clone(this), {
  901. url: this.url,
  902. status: this.status,
  903. statusText: this.statusText,
  904. headers: this.headers,
  905. ok: this.ok
  906. });
  907. }
  908. }
  909. Body.mixIn(Response.prototype);
  910. Object.defineProperty(Response.prototype, Symbol.toStringTag, {
  911. value: 'ResponsePrototype',
  912. writable: false,
  913. enumerable: false,
  914. configurable: true
  915. });
  916. /**
  917. * request.js
  918. *
  919. * Request class contains server only options
  920. */
  921. var _require$3 = require('url');
  922. const format_url = _require$3.format;
  923. const parse_url = _require$3.parse;
  924. const PARSED_URL = Symbol('url');
  925. /**
  926. * Request class
  927. *
  928. * @param Mixed input Url or Request instance
  929. * @param Object init Custom options
  930. * @return Void
  931. */
  932. class Request {
  933. constructor(input) {
  934. let init = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  935. let parsedURL;
  936. // normalize input
  937. if (!(input instanceof Request)) {
  938. if (input && input.href) {
  939. // in order to support Node.js' Url objects; though WHATWG's URL objects
  940. // will fall into this branch also (since their `toString()` will return
  941. // `href` property anyway)
  942. parsedURL = parse_url(input.href);
  943. } else {
  944. // coerce input to a string before attempting to parse
  945. parsedURL = parse_url(`${input}`);
  946. }
  947. input = {};
  948. } else {
  949. parsedURL = parse_url(input.url);
  950. }
  951. let method = init.method || input.method || 'GET';
  952. if ((init.body != null || input instanceof Request && input.body !== null) && (method === 'GET' || method === 'HEAD')) {
  953. throw new TypeError('Request with GET/HEAD method cannot have body');
  954. }
  955. let inputBody = init.body != null ? init.body : input instanceof Request && input.body !== null ? clone(input) : null;
  956. Body.call(this, inputBody, {
  957. timeout: init.timeout || input.timeout || 0,
  958. size: init.size || input.size || 0
  959. });
  960. // fetch spec options
  961. this.method = method.toUpperCase();
  962. this.redirect = init.redirect || input.redirect || 'follow';
  963. this.headers = new Headers(init.headers || input.headers || {});
  964. if (init.body != null) {
  965. const contentType = extractContentType(this);
  966. if (contentType !== null && !this.headers.has('Content-Type')) {
  967. this.headers.append('Content-Type', contentType);
  968. }
  969. }
  970. // server only options
  971. this.follow = init.follow !== undefined ? init.follow : input.follow !== undefined ? input.follow : 20;
  972. this.compress = init.compress !== undefined ? init.compress : input.compress !== undefined ? input.compress : true;
  973. this.counter = init.counter || input.counter || 0;
  974. this.agent = init.agent || input.agent;
  975. this[PARSED_URL] = parsedURL;
  976. Object.defineProperty(this, Symbol.toStringTag, {
  977. value: 'Request',
  978. writable: false,
  979. enumerable: false,
  980. configurable: true
  981. });
  982. }
  983. get url() {
  984. return format_url(this[PARSED_URL]);
  985. }
  986. /**
  987. * Clone this request
  988. *
  989. * @return Request
  990. */
  991. clone() {
  992. return new Request(this);
  993. }
  994. }
  995. Body.mixIn(Request.prototype);
  996. Object.defineProperty(Request.prototype, Symbol.toStringTag, {
  997. value: 'RequestPrototype',
  998. writable: false,
  999. enumerable: false,
  1000. configurable: true
  1001. });
  1002. function getNodeRequestOptions(request) {
  1003. const parsedURL = request[PARSED_URL];
  1004. const headers = new Headers(request.headers);
  1005. // fetch step 3
  1006. if (!headers.has('Accept')) {
  1007. headers.set('Accept', '*/*');
  1008. }
  1009. // Basic fetch
  1010. if (!parsedURL.protocol || !parsedURL.hostname) {
  1011. throw new TypeError('Only absolute URLs are supported');
  1012. }
  1013. if (!/^https?:$/.test(parsedURL.protocol)) {
  1014. throw new TypeError('Only HTTP(S) protocols are supported');
  1015. }
  1016. // HTTP-network-or-cache fetch steps 5-9
  1017. let contentLengthValue = null;
  1018. if (request.body == null && /^(POST|PUT)$/i.test(request.method)) {
  1019. contentLengthValue = '0';
  1020. }
  1021. if (request.body != null) {
  1022. const totalBytes = getTotalBytes(request);
  1023. if (typeof totalBytes === 'number') {
  1024. contentLengthValue = String(totalBytes);
  1025. }
  1026. }
  1027. if (contentLengthValue) {
  1028. headers.set('Content-Length', contentLengthValue);
  1029. }
  1030. // HTTP-network-or-cache fetch step 12
  1031. if (!headers.has('User-Agent')) {
  1032. headers.set('User-Agent', 'node-fetch/1.0 (+https://github.com/bitinn/node-fetch)');
  1033. }
  1034. // HTTP-network-or-cache fetch step 16
  1035. if (request.compress) {
  1036. headers.set('Accept-Encoding', 'gzip,deflate');
  1037. }
  1038. if (!headers.has('Connection') && !request.agent) {
  1039. headers.set('Connection', 'close');
  1040. }
  1041. // HTTP-network fetch step 4
  1042. // chunked encoding is handled by Node.js
  1043. return Object.assign({}, parsedURL, {
  1044. method: request.method,
  1045. headers: headers.raw(),
  1046. agent: request.agent
  1047. });
  1048. }
  1049. /**
  1050. * index.js
  1051. *
  1052. * a request API compatible with window.fetch
  1053. */
  1054. const http = require('http');
  1055. const https = require('https');
  1056. var _require = require('stream');
  1057. const PassThrough = _require.PassThrough;
  1058. var _require2 = require('url');
  1059. const resolve_url = _require2.resolve;
  1060. const zlib = require('zlib');
  1061. /**
  1062. * Fetch function
  1063. *
  1064. * @param Mixed url Absolute url or Request instance
  1065. * @param Object opts Fetch options
  1066. * @return Promise
  1067. */
  1068. function fetch(url, opts) {
  1069. // allow custom promise
  1070. if (!fetch.Promise) {
  1071. throw new Error('native promise missing, set fetch.Promise to your favorite alternative');
  1072. }
  1073. Body.Promise = fetch.Promise;
  1074. // wrap http.request into fetch
  1075. return new fetch.Promise(function (resolve, reject) {
  1076. // build request object
  1077. const request = new Request(url, opts);
  1078. const options = getNodeRequestOptions(request);
  1079. const send = (options.protocol === 'https:' ? https : http).request;
  1080. // http.request only support string as host header, this hack make custom host header possible
  1081. if (options.headers.host) {
  1082. options.headers.host = options.headers.host[0];
  1083. }
  1084. // send request
  1085. const req = send(options);
  1086. let reqTimeout;
  1087. if (request.timeout) {
  1088. req.once('socket', function (socket) {
  1089. reqTimeout = setTimeout(function () {
  1090. req.abort();
  1091. reject(new FetchError(`network timeout at: ${request.url}`, 'request-timeout'));
  1092. }, request.timeout);
  1093. });
  1094. }
  1095. req.on('error', function (err) {
  1096. clearTimeout(reqTimeout);
  1097. reject(new FetchError(`request to ${request.url} failed, reason: ${err.message}`, 'system', err));
  1098. });
  1099. req.on('response', function (res) {
  1100. clearTimeout(reqTimeout);
  1101. // handle redirect
  1102. if (fetch.isRedirect(res.statusCode) && request.redirect !== 'manual') {
  1103. if (request.redirect === 'error') {
  1104. reject(new FetchError(`redirect mode is set to error: ${request.url}`, 'no-redirect'));
  1105. return;
  1106. }
  1107. if (request.counter >= request.follow) {
  1108. reject(new FetchError(`maximum redirect reached at: ${request.url}`, 'max-redirect'));
  1109. return;
  1110. }
  1111. if (!res.headers.location) {
  1112. reject(new FetchError(`redirect location header missing at: ${request.url}`, 'invalid-redirect'));
  1113. return;
  1114. }
  1115. // per fetch spec, for POST request with 301/302 response, or any request with 303 response, use GET when following redirect
  1116. if (res.statusCode === 303 || (res.statusCode === 301 || res.statusCode === 302) && request.method === 'POST') {
  1117. request.method = 'GET';
  1118. request.body = null;
  1119. request.headers.delete('content-length');
  1120. }
  1121. request.counter++;
  1122. resolve(fetch(resolve_url(request.url, res.headers.location), request));
  1123. return;
  1124. }
  1125. // normalize location header for manual redirect mode
  1126. const headers = new Headers();
  1127. for (const name of Object.keys(res.headers)) {
  1128. if (Array.isArray(res.headers[name])) {
  1129. for (const val of res.headers[name]) {
  1130. headers.append(name, val);
  1131. }
  1132. } else {
  1133. headers.append(name, res.headers[name]);
  1134. }
  1135. }
  1136. if (request.redirect === 'manual' && headers.has('location')) {
  1137. headers.set('location', resolve_url(request.url, headers.get('location')));
  1138. }
  1139. // prepare response
  1140. let body = res.pipe(new PassThrough());
  1141. const response_options = {
  1142. url: request.url,
  1143. status: res.statusCode,
  1144. statusText: res.statusMessage,
  1145. headers: headers,
  1146. size: request.size,
  1147. timeout: request.timeout
  1148. };
  1149. // HTTP-network fetch step 16.1.2
  1150. const codings = headers.get('Content-Encoding');
  1151. // HTTP-network fetch step 16.1.3: handle content codings
  1152. // in following scenarios we ignore compression support
  1153. // 1. compression support is disabled
  1154. // 2. HEAD request
  1155. // 3. no Content-Encoding header
  1156. // 4. no content response (204)
  1157. // 5. content not modified response (304)
  1158. if (!request.compress || request.method === 'HEAD' || codings === null || res.statusCode === 204 || res.statusCode === 304) {
  1159. resolve(new Response(body, response_options));
  1160. return;
  1161. }
  1162. // For Node v6+
  1163. // Be less strict when decoding compressed responses, since sometimes
  1164. // servers send slightly invalid responses that are still accepted
  1165. // by common browsers.
  1166. // Always using Z_SYNC_FLUSH is what cURL does.
  1167. const zlibOptions = {
  1168. flush: zlib.Z_SYNC_FLUSH,
  1169. finishFlush: zlib.Z_SYNC_FLUSH
  1170. };
  1171. // for gzip
  1172. if (codings == 'gzip' || codings == 'x-gzip') {
  1173. body = body.pipe(zlib.createGunzip(zlibOptions));
  1174. resolve(new Response(body, response_options));
  1175. return;
  1176. }
  1177. // for deflate
  1178. if (codings == 'deflate' || codings == 'x-deflate') {
  1179. // handle the infamous raw deflate response from old servers
  1180. // a hack for old IIS and Apache servers
  1181. const raw = res.pipe(new PassThrough());
  1182. raw.once('data', function (chunk) {
  1183. // see http://stackoverflow.com/questions/37519828
  1184. if ((chunk[0] & 0x0F) === 0x08) {
  1185. body = body.pipe(zlib.createInflate());
  1186. } else {
  1187. body = body.pipe(zlib.createInflateRaw());
  1188. }
  1189. resolve(new Response(body, response_options));
  1190. });
  1191. return;
  1192. }
  1193. // otherwise, use response as-is
  1194. resolve(new Response(body, response_options));
  1195. });
  1196. writeToStream(req, request);
  1197. });
  1198. }
  1199. /**
  1200. * Redirect code matching
  1201. *
  1202. * @param Number code Status code
  1203. * @return Boolean
  1204. */
  1205. fetch.isRedirect = function (code) {
  1206. return code === 301 || code === 302 || code === 303 || code === 307 || code === 308;
  1207. };
  1208. // expose Promise
  1209. fetch.Promise = global.Promise;
  1210. module.exports = exports = fetch;
  1211. exports.Headers = Headers;
  1212. exports.Request = Request;
  1213. exports.Response = Response;
  1214. exports.FetchError = FetchError;