node_stream.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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._disableRange = source.disableRange || false;
  89. this._rangeChunkSize = source.rangeChunkSize;
  90. if (!this._rangeChunkSize && !this._disableRange) {
  91. this._disableRange = true;
  92. }
  93. this._isStreamingSupported = !source.disableStream;
  94. this._isRangeSupported = !source.disableRange;
  95. this._readableStream = null;
  96. this._readCapability = (0, _util.createPromiseCapability)();
  97. this._headersCapability = (0, _util.createPromiseCapability)();
  98. }
  99. _createClass(BaseFullReader, [{
  100. key: 'read',
  101. value: function read() {
  102. var _this = this;
  103. return this._readCapability.promise.then(function () {
  104. if (_this._done) {
  105. return Promise.resolve({
  106. value: undefined,
  107. done: true
  108. });
  109. }
  110. if (_this._errored) {
  111. return Promise.reject(_this._reason);
  112. }
  113. var chunk = _this._readableStream.read();
  114. if (chunk === null) {
  115. _this._readCapability = (0, _util.createPromiseCapability)();
  116. return _this.read();
  117. }
  118. _this._loaded += chunk.length;
  119. if (_this.onProgress) {
  120. _this.onProgress({
  121. loaded: _this._loaded,
  122. total: _this._contentLength
  123. });
  124. }
  125. var buffer = new Uint8Array(chunk).buffer;
  126. return Promise.resolve({
  127. value: buffer,
  128. done: false
  129. });
  130. });
  131. }
  132. }, {
  133. key: 'cancel',
  134. value: function cancel(reason) {
  135. if (!this._readableStream) {
  136. this._error(reason);
  137. return;
  138. }
  139. this._readableStream.destroy(reason);
  140. }
  141. }, {
  142. key: '_error',
  143. value: function _error(reason) {
  144. this._errored = true;
  145. this._reason = reason;
  146. this._readCapability.resolve();
  147. }
  148. }, {
  149. key: '_setReadableStream',
  150. value: function _setReadableStream(readableStream) {
  151. var _this2 = this;
  152. this._readableStream = readableStream;
  153. readableStream.on('readable', function () {
  154. _this2._readCapability.resolve();
  155. });
  156. readableStream.on('end', function () {
  157. readableStream.destroy();
  158. _this2._done = true;
  159. _this2._readCapability.resolve();
  160. });
  161. readableStream.on('error', function (reason) {
  162. _this2._error(reason);
  163. });
  164. if (!this._isStreamingSupported && this._isRangeSupported) {
  165. this._error(new _util.AbortException('streaming is disabled'));
  166. }
  167. if (this._errored) {
  168. this._readableStream.destroy(this._reason);
  169. }
  170. }
  171. }, {
  172. key: 'headersReady',
  173. get: function get() {
  174. return this._headersCapability.promise;
  175. }
  176. }, {
  177. key: 'contentLength',
  178. get: function get() {
  179. return this._contentLength;
  180. }
  181. }, {
  182. key: 'isRangeSupported',
  183. get: function get() {
  184. return this._isRangeSupported;
  185. }
  186. }, {
  187. key: 'isStreamingSupported',
  188. get: function get() {
  189. return this._isStreamingSupported;
  190. }
  191. }]);
  192. return BaseFullReader;
  193. }();
  194. var BaseRangeReader = function () {
  195. function BaseRangeReader(stream) {
  196. _classCallCheck(this, BaseRangeReader);
  197. this._url = stream.url;
  198. this._done = false;
  199. this._errored = false;
  200. this._reason = null;
  201. this.onProgress = null;
  202. this._loaded = 0;
  203. this._readableStream = null;
  204. this._readCapability = (0, _util.createPromiseCapability)();
  205. var source = stream.source;
  206. this._isStreamingSupported = !source.disableStream;
  207. }
  208. _createClass(BaseRangeReader, [{
  209. key: 'read',
  210. value: function read() {
  211. var _this3 = this;
  212. return this._readCapability.promise.then(function () {
  213. if (_this3._done) {
  214. return Promise.resolve({
  215. value: undefined,
  216. done: true
  217. });
  218. }
  219. if (_this3._errored) {
  220. return Promise.reject(_this3._reason);
  221. }
  222. var chunk = _this3._readableStream.read();
  223. if (chunk === null) {
  224. _this3._readCapability = (0, _util.createPromiseCapability)();
  225. return _this3.read();
  226. }
  227. _this3._loaded += chunk.length;
  228. if (_this3.onProgress) {
  229. _this3.onProgress({ loaded: _this3._loaded });
  230. }
  231. var buffer = new Uint8Array(chunk).buffer;
  232. return Promise.resolve({
  233. value: buffer,
  234. done: false
  235. });
  236. });
  237. }
  238. }, {
  239. key: 'cancel',
  240. value: function cancel(reason) {
  241. if (!this._readableStream) {
  242. this._error(reason);
  243. return;
  244. }
  245. this._readableStream.destroy(reason);
  246. }
  247. }, {
  248. key: '_error',
  249. value: function _error(reason) {
  250. this._errored = true;
  251. this._reason = reason;
  252. this._readCapability.resolve();
  253. }
  254. }, {
  255. key: '_setReadableStream',
  256. value: function _setReadableStream(readableStream) {
  257. var _this4 = this;
  258. this._readableStream = readableStream;
  259. readableStream.on('readable', function () {
  260. _this4._readCapability.resolve();
  261. });
  262. readableStream.on('end', function () {
  263. readableStream.destroy();
  264. _this4._done = true;
  265. _this4._readCapability.resolve();
  266. });
  267. readableStream.on('error', function (reason) {
  268. _this4._error(reason);
  269. });
  270. if (this._errored) {
  271. this._readableStream.destroy(this._reason);
  272. }
  273. }
  274. }, {
  275. key: 'isStreamingSupported',
  276. get: function get() {
  277. return this._isStreamingSupported;
  278. }
  279. }]);
  280. return BaseRangeReader;
  281. }();
  282. function createRequestOptions(url, headers) {
  283. return {
  284. protocol: url.protocol,
  285. auth: url.auth,
  286. host: url.hostname,
  287. port: url.port,
  288. path: url.path,
  289. method: 'GET',
  290. headers: headers
  291. };
  292. }
  293. var PDFNodeStreamFullReader = function (_BaseFullReader) {
  294. _inherits(PDFNodeStreamFullReader, _BaseFullReader);
  295. function PDFNodeStreamFullReader(stream) {
  296. _classCallCheck(this, PDFNodeStreamFullReader);
  297. var _this5 = _possibleConstructorReturn(this, (PDFNodeStreamFullReader.__proto__ || Object.getPrototypeOf(PDFNodeStreamFullReader)).call(this, stream));
  298. var handleResponse = function handleResponse(response) {
  299. _this5._headersCapability.resolve();
  300. _this5._setReadableStream(response);
  301. var _validateRangeRequest = (0, _network_utils.validateRangeRequestCapabilities)({
  302. getResponseHeader: function getResponseHeader(name) {
  303. return _this5._readableStream.headers[name.toLowerCase()];
  304. },
  305. isHttp: stream.isHttp,
  306. rangeChunkSize: _this5._rangeChunkSize,
  307. disableRange: _this5._disableRange
  308. }),
  309. allowRangeRequests = _validateRangeRequest.allowRangeRequests,
  310. suggestedLength = _validateRangeRequest.suggestedLength;
  311. if (allowRangeRequests) {
  312. _this5._isRangeSupported = true;
  313. }
  314. _this5._contentLength = suggestedLength;
  315. };
  316. _this5._request = null;
  317. if (_this5._url.protocol === 'http:') {
  318. _this5._request = http.request(createRequestOptions(_this5._url, stream.httpHeaders), handleResponse);
  319. } else {
  320. _this5._request = https.request(createRequestOptions(_this5._url, stream.httpHeaders), handleResponse);
  321. }
  322. _this5._request.on('error', function (reason) {
  323. _this5._errored = true;
  324. _this5._reason = reason;
  325. _this5._headersCapability.reject(reason);
  326. });
  327. _this5._request.end();
  328. return _this5;
  329. }
  330. return PDFNodeStreamFullReader;
  331. }(BaseFullReader);
  332. var PDFNodeStreamRangeReader = function (_BaseRangeReader) {
  333. _inherits(PDFNodeStreamRangeReader, _BaseRangeReader);
  334. function PDFNodeStreamRangeReader(stream, start, end) {
  335. _classCallCheck(this, PDFNodeStreamRangeReader);
  336. var _this6 = _possibleConstructorReturn(this, (PDFNodeStreamRangeReader.__proto__ || Object.getPrototypeOf(PDFNodeStreamRangeReader)).call(this, stream));
  337. _this6._httpHeaders = {};
  338. for (var property in stream.httpHeaders) {
  339. var value = stream.httpHeaders[property];
  340. if (typeof value === 'undefined') {
  341. continue;
  342. }
  343. _this6._httpHeaders[property] = value;
  344. }
  345. _this6._httpHeaders['Range'] = 'bytes=' + start + '-' + (end - 1);
  346. _this6._request = null;
  347. if (_this6._url.protocol === 'http:') {
  348. _this6._request = http.request(createRequestOptions(_this6._url, _this6._httpHeaders), function (response) {
  349. _this6._setReadableStream(response);
  350. });
  351. } else {
  352. _this6._request = https.request(createRequestOptions(_this6._url, _this6._httpHeaders), function (response) {
  353. _this6._setReadableStream(response);
  354. });
  355. }
  356. _this6._request.on('error', function (reason) {
  357. _this6._errored = true;
  358. _this6._reason = reason;
  359. });
  360. _this6._request.end();
  361. return _this6;
  362. }
  363. return PDFNodeStreamRangeReader;
  364. }(BaseRangeReader);
  365. var PDFNodeStreamFsFullReader = function (_BaseFullReader2) {
  366. _inherits(PDFNodeStreamFsFullReader, _BaseFullReader2);
  367. function PDFNodeStreamFsFullReader(stream) {
  368. _classCallCheck(this, PDFNodeStreamFsFullReader);
  369. var _this7 = _possibleConstructorReturn(this, (PDFNodeStreamFsFullReader.__proto__ || Object.getPrototypeOf(PDFNodeStreamFsFullReader)).call(this, stream));
  370. var path = decodeURIComponent(_this7._url.path);
  371. if (fileUriRegex.test(_this7._url.href)) {
  372. path = path.replace(/^\//, '');
  373. }
  374. fs.lstat(path, function (error, stat) {
  375. if (error) {
  376. _this7._errored = true;
  377. _this7._reason = error;
  378. _this7._headersCapability.reject(error);
  379. return;
  380. }
  381. _this7._contentLength = stat.size;
  382. _this7._setReadableStream(fs.createReadStream(path));
  383. _this7._headersCapability.resolve();
  384. });
  385. return _this7;
  386. }
  387. return PDFNodeStreamFsFullReader;
  388. }(BaseFullReader);
  389. var PDFNodeStreamFsRangeReader = function (_BaseRangeReader2) {
  390. _inherits(PDFNodeStreamFsRangeReader, _BaseRangeReader2);
  391. function PDFNodeStreamFsRangeReader(stream, start, end) {
  392. _classCallCheck(this, PDFNodeStreamFsRangeReader);
  393. var _this8 = _possibleConstructorReturn(this, (PDFNodeStreamFsRangeReader.__proto__ || Object.getPrototypeOf(PDFNodeStreamFsRangeReader)).call(this, stream));
  394. var path = decodeURIComponent(_this8._url.path);
  395. if (fileUriRegex.test(_this8._url.href)) {
  396. path = path.replace(/^\//, '');
  397. }
  398. _this8._setReadableStream(fs.createReadStream(path, {
  399. start: start,
  400. end: end - 1
  401. }));
  402. return _this8;
  403. }
  404. return PDFNodeStreamFsRangeReader;
  405. }(BaseRangeReader);
  406. exports.PDFNodeStream = PDFNodeStream;