node_stream.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2017 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * Javascript code in this page
  21. */
  22. 'use strict';
  23. Object.defineProperty(exports, "__esModule", {
  24. value: true
  25. });
  26. exports.PDFNodeStream = undefined;
  27. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  28. var _util = require('../shared/util');
  29. var _network_utils = require('./network_utils');
  30. function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
  31. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
  32. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  33. var fs = require('fs');
  34. var http = require('http');
  35. var https = require('https');
  36. var url = require('url');
  37. var fileUriRegex = /^file:\/\/\/[a-zA-Z]:\//;
  38. var PDFNodeStream = function () {
  39. function PDFNodeStream(source) {
  40. _classCallCheck(this, PDFNodeStream);
  41. this.source = source;
  42. this.url = url.parse(source.url);
  43. this.isHttp = this.url.protocol === 'http:' || this.url.protocol === 'https:';
  44. this.isFsUrl = this.url.protocol === 'file:' || !this.url.host;
  45. this.httpHeaders = this.isHttp && source.httpHeaders || {};
  46. this._fullRequest = null;
  47. this._rangeRequestReaders = [];
  48. }
  49. _createClass(PDFNodeStream, [{
  50. key: 'getFullReader',
  51. value: function getFullReader() {
  52. (0, _util.assert)(!this._fullRequest);
  53. this._fullRequest = this.isFsUrl ? new PDFNodeStreamFsFullReader(this) : new PDFNodeStreamFullReader(this);
  54. return this._fullRequest;
  55. }
  56. }, {
  57. key: 'getRangeReader',
  58. value: function getRangeReader(start, end) {
  59. var rangeReader = this.isFsUrl ? new PDFNodeStreamFsRangeReader(this, start, end) : new PDFNodeStreamRangeReader(this, start, end);
  60. this._rangeRequestReaders.push(rangeReader);
  61. return rangeReader;
  62. }
  63. }, {
  64. key: 'cancelAllRequests',
  65. value: function cancelAllRequests(reason) {
  66. if (this._fullRequest) {
  67. this._fullRequest.cancel(reason);
  68. }
  69. var readers = this._rangeRequestReaders.slice(0);
  70. readers.forEach(function (reader) {
  71. reader.cancel(reason);
  72. });
  73. }
  74. }]);
  75. return PDFNodeStream;
  76. }();
  77. var BaseFullReader = function () {
  78. function BaseFullReader(stream) {
  79. _classCallCheck(this, BaseFullReader);
  80. this._url = stream.url;
  81. this._done = false;
  82. this._errored = false;
  83. this._reason = null;
  84. this.onProgress = null;
  85. var source = stream.source;
  86. this._contentLength = source.length;
  87. this._loaded = 0;
  88. this._filename = null;
  89. this._disableRange = source.disableRange || false;
  90. this._rangeChunkSize = source.rangeChunkSize;
  91. if (!this._rangeChunkSize && !this._disableRange) {
  92. this._disableRange = true;
  93. }
  94. this._isStreamingSupported = !source.disableStream;
  95. this._isRangeSupported = !source.disableRange;
  96. this._readableStream = null;
  97. this._readCapability = (0, _util.createPromiseCapability)();
  98. this._headersCapability = (0, _util.createPromiseCapability)();
  99. }
  100. _createClass(BaseFullReader, [{
  101. key: 'read',
  102. value: function read() {
  103. var _this = this;
  104. return this._readCapability.promise.then(function () {
  105. if (_this._done) {
  106. return Promise.resolve({
  107. value: undefined,
  108. done: true
  109. });
  110. }
  111. if (_this._errored) {
  112. return Promise.reject(_this._reason);
  113. }
  114. var chunk = _this._readableStream.read();
  115. if (chunk === null) {
  116. _this._readCapability = (0, _util.createPromiseCapability)();
  117. return _this.read();
  118. }
  119. _this._loaded += chunk.length;
  120. if (_this.onProgress) {
  121. _this.onProgress({
  122. loaded: _this._loaded,
  123. total: _this._contentLength
  124. });
  125. }
  126. var buffer = new Uint8Array(chunk).buffer;
  127. return Promise.resolve({
  128. value: buffer,
  129. done: false
  130. });
  131. });
  132. }
  133. }, {
  134. key: 'cancel',
  135. value: function cancel(reason) {
  136. if (!this._readableStream) {
  137. this._error(reason);
  138. return;
  139. }
  140. this._readableStream.destroy(reason);
  141. }
  142. }, {
  143. key: '_error',
  144. value: function _error(reason) {
  145. this._errored = true;
  146. this._reason = reason;
  147. this._readCapability.resolve();
  148. }
  149. }, {
  150. key: '_setReadableStream',
  151. value: function _setReadableStream(readableStream) {
  152. var _this2 = this;
  153. this._readableStream = readableStream;
  154. readableStream.on('readable', function () {
  155. _this2._readCapability.resolve();
  156. });
  157. readableStream.on('end', function () {
  158. readableStream.destroy();
  159. _this2._done = true;
  160. _this2._readCapability.resolve();
  161. });
  162. readableStream.on('error', function (reason) {
  163. _this2._error(reason);
  164. });
  165. if (!this._isStreamingSupported && this._isRangeSupported) {
  166. this._error(new _util.AbortException('streaming is disabled'));
  167. }
  168. if (this._errored) {
  169. this._readableStream.destroy(this._reason);
  170. }
  171. }
  172. }, {
  173. key: 'headersReady',
  174. get: function get() {
  175. return this._headersCapability.promise;
  176. }
  177. }, {
  178. key: 'filename',
  179. get: function get() {
  180. return this._filename;
  181. }
  182. }, {
  183. key: 'contentLength',
  184. get: function get() {
  185. return this._contentLength;
  186. }
  187. }, {
  188. key: 'isRangeSupported',
  189. get: function get() {
  190. return this._isRangeSupported;
  191. }
  192. }, {
  193. key: 'isStreamingSupported',
  194. get: function get() {
  195. return this._isStreamingSupported;
  196. }
  197. }]);
  198. return BaseFullReader;
  199. }();
  200. var BaseRangeReader = function () {
  201. function BaseRangeReader(stream) {
  202. _classCallCheck(this, BaseRangeReader);
  203. this._url = stream.url;
  204. this._done = false;
  205. this._errored = false;
  206. this._reason = null;
  207. this.onProgress = null;
  208. this._loaded = 0;
  209. this._readableStream = null;
  210. this._readCapability = (0, _util.createPromiseCapability)();
  211. var source = stream.source;
  212. this._isStreamingSupported = !source.disableStream;
  213. }
  214. _createClass(BaseRangeReader, [{
  215. key: 'read',
  216. value: function read() {
  217. var _this3 = this;
  218. return this._readCapability.promise.then(function () {
  219. if (_this3._done) {
  220. return Promise.resolve({
  221. value: undefined,
  222. done: true
  223. });
  224. }
  225. if (_this3._errored) {
  226. return Promise.reject(_this3._reason);
  227. }
  228. var chunk = _this3._readableStream.read();
  229. if (chunk === null) {
  230. _this3._readCapability = (0, _util.createPromiseCapability)();
  231. return _this3.read();
  232. }
  233. _this3._loaded += chunk.length;
  234. if (_this3.onProgress) {
  235. _this3.onProgress({ loaded: _this3._loaded });
  236. }
  237. var buffer = new Uint8Array(chunk).buffer;
  238. return Promise.resolve({
  239. value: buffer,
  240. done: false
  241. });
  242. });
  243. }
  244. }, {
  245. key: 'cancel',
  246. value: function cancel(reason) {
  247. if (!this._readableStream) {
  248. this._error(reason);
  249. return;
  250. }
  251. this._readableStream.destroy(reason);
  252. }
  253. }, {
  254. key: '_error',
  255. value: function _error(reason) {
  256. this._errored = true;
  257. this._reason = reason;
  258. this._readCapability.resolve();
  259. }
  260. }, {
  261. key: '_setReadableStream',
  262. value: function _setReadableStream(readableStream) {
  263. var _this4 = this;
  264. this._readableStream = readableStream;
  265. readableStream.on('readable', function () {
  266. _this4._readCapability.resolve();
  267. });
  268. readableStream.on('end', function () {
  269. readableStream.destroy();
  270. _this4._done = true;
  271. _this4._readCapability.resolve();
  272. });
  273. readableStream.on('error', function (reason) {
  274. _this4._error(reason);
  275. });
  276. if (this._errored) {
  277. this._readableStream.destroy(this._reason);
  278. }
  279. }
  280. }, {
  281. key: 'isStreamingSupported',
  282. get: function get() {
  283. return this._isStreamingSupported;
  284. }
  285. }]);
  286. return BaseRangeReader;
  287. }();
  288. function createRequestOptions(url, headers) {
  289. return {
  290. protocol: url.protocol,
  291. auth: url.auth,
  292. host: url.hostname,
  293. port: url.port,
  294. path: url.path,
  295. method: 'GET',
  296. headers: headers
  297. };
  298. }
  299. var PDFNodeStreamFullReader = function (_BaseFullReader) {
  300. _inherits(PDFNodeStreamFullReader, _BaseFullReader);
  301. function PDFNodeStreamFullReader(stream) {
  302. _classCallCheck(this, PDFNodeStreamFullReader);
  303. var _this5 = _possibleConstructorReturn(this, (PDFNodeStreamFullReader.__proto__ || Object.getPrototypeOf(PDFNodeStreamFullReader)).call(this, stream));
  304. var handleResponse = function handleResponse(response) {
  305. _this5._headersCapability.resolve();
  306. _this5._setReadableStream(response);
  307. var getResponseHeader = function getResponseHeader(name) {
  308. return _this5._readableStream.headers[name.toLowerCase()];
  309. };
  310. var _validateRangeRequest = (0, _network_utils.validateRangeRequestCapabilities)({
  311. getResponseHeader: getResponseHeader,
  312. isHttp: stream.isHttp,
  313. rangeChunkSize: _this5._rangeChunkSize,
  314. disableRange: _this5._disableRange
  315. }),
  316. allowRangeRequests = _validateRangeRequest.allowRangeRequests,
  317. suggestedLength = _validateRangeRequest.suggestedLength;
  318. if (allowRangeRequests) {
  319. _this5._isRangeSupported = true;
  320. }
  321. _this5._contentLength = suggestedLength;
  322. _this5._filename = (0, _network_utils.extractFilenameFromHeader)(getResponseHeader);
  323. };
  324. _this5._request = null;
  325. if (_this5._url.protocol === 'http:') {
  326. _this5._request = http.request(createRequestOptions(_this5._url, stream.httpHeaders), handleResponse);
  327. } else {
  328. _this5._request = https.request(createRequestOptions(_this5._url, stream.httpHeaders), handleResponse);
  329. }
  330. _this5._request.on('error', function (reason) {
  331. _this5._errored = true;
  332. _this5._reason = reason;
  333. _this5._headersCapability.reject(reason);
  334. });
  335. _this5._request.end();
  336. return _this5;
  337. }
  338. return PDFNodeStreamFullReader;
  339. }(BaseFullReader);
  340. var PDFNodeStreamRangeReader = function (_BaseRangeReader) {
  341. _inherits(PDFNodeStreamRangeReader, _BaseRangeReader);
  342. function PDFNodeStreamRangeReader(stream, start, end) {
  343. _classCallCheck(this, PDFNodeStreamRangeReader);
  344. var _this6 = _possibleConstructorReturn(this, (PDFNodeStreamRangeReader.__proto__ || Object.getPrototypeOf(PDFNodeStreamRangeReader)).call(this, stream));
  345. _this6._httpHeaders = {};
  346. for (var property in stream.httpHeaders) {
  347. var value = stream.httpHeaders[property];
  348. if (typeof value === 'undefined') {
  349. continue;
  350. }
  351. _this6._httpHeaders[property] = value;
  352. }
  353. _this6._httpHeaders['Range'] = 'bytes=' + start + '-' + (end - 1);
  354. _this6._request = null;
  355. if (_this6._url.protocol === 'http:') {
  356. _this6._request = http.request(createRequestOptions(_this6._url, _this6._httpHeaders), function (response) {
  357. _this6._setReadableStream(response);
  358. });
  359. } else {
  360. _this6._request = https.request(createRequestOptions(_this6._url, _this6._httpHeaders), function (response) {
  361. _this6._setReadableStream(response);
  362. });
  363. }
  364. _this6._request.on('error', function (reason) {
  365. _this6._errored = true;
  366. _this6._reason = reason;
  367. });
  368. _this6._request.end();
  369. return _this6;
  370. }
  371. return PDFNodeStreamRangeReader;
  372. }(BaseRangeReader);
  373. var PDFNodeStreamFsFullReader = function (_BaseFullReader2) {
  374. _inherits(PDFNodeStreamFsFullReader, _BaseFullReader2);
  375. function PDFNodeStreamFsFullReader(stream) {
  376. _classCallCheck(this, PDFNodeStreamFsFullReader);
  377. var _this7 = _possibleConstructorReturn(this, (PDFNodeStreamFsFullReader.__proto__ || Object.getPrototypeOf(PDFNodeStreamFsFullReader)).call(this, stream));
  378. var path = decodeURIComponent(_this7._url.path);
  379. if (fileUriRegex.test(_this7._url.href)) {
  380. path = path.replace(/^\//, '');
  381. }
  382. fs.lstat(path, function (error, stat) {
  383. if (error) {
  384. _this7._errored = true;
  385. _this7._reason = error;
  386. _this7._headersCapability.reject(error);
  387. return;
  388. }
  389. _this7._contentLength = stat.size;
  390. _this7._setReadableStream(fs.createReadStream(path));
  391. _this7._headersCapability.resolve();
  392. });
  393. return _this7;
  394. }
  395. return PDFNodeStreamFsFullReader;
  396. }(BaseFullReader);
  397. var PDFNodeStreamFsRangeReader = function (_BaseRangeReader2) {
  398. _inherits(PDFNodeStreamFsRangeReader, _BaseRangeReader2);
  399. function PDFNodeStreamFsRangeReader(stream, start, end) {
  400. _classCallCheck(this, PDFNodeStreamFsRangeReader);
  401. var _this8 = _possibleConstructorReturn(this, (PDFNodeStreamFsRangeReader.__proto__ || Object.getPrototypeOf(PDFNodeStreamFsRangeReader)).call(this, stream));
  402. var path = decodeURIComponent(_this8._url.path);
  403. if (fileUriRegex.test(_this8._url.href)) {
  404. path = path.replace(/^\//, '');
  405. }
  406. _this8._setReadableStream(fs.createReadStream(path, {
  407. start: start,
  408. end: end - 1
  409. }));
  410. return _this8;
  411. }
  412. return PDFNodeStreamFsRangeReader;
  413. }(BaseRangeReader);
  414. exports.PDFNodeStream = PDFNodeStream;