mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-26 10:08:06 +02:00
Makes PDF data reading Streams API friendly.
This commit is contained in:
parent
8cdb69634f
commit
0d591719d9
8 changed files with 1153 additions and 178 deletions
|
@ -295,13 +295,347 @@ var NetworkManager = (function NetworkManagerClosure() {
|
|||
//#if !(FIREFOX || MOZCENTRAL)
|
||||
(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define('pdfjs/core/network', ['exports'], factory);
|
||||
define('pdfjs/core/network', ['exports', 'pdfjs/shared/util',
|
||||
'pdfjs/core/worker'], factory);
|
||||
} else if (typeof exports !== 'undefined') {
|
||||
factory(exports);
|
||||
factory(exports, require('../shared/util.js'), require('./worker.js'));
|
||||
} else {
|
||||
factory((root.pdfjsCoreNetwork = {}));
|
||||
factory((root.pdfjsCoreNetwork = {}), root.pdfjsSharedUtil,
|
||||
root.pdfjsCoreWorker);
|
||||
}
|
||||
}(this, function (exports) {
|
||||
}(this, function (exports, sharedUtil, coreWorker) {
|
||||
|
||||
var assert = sharedUtil.assert;
|
||||
var createPromiseCapability = sharedUtil.createPromiseCapability;
|
||||
var isInt = sharedUtil.isInt;
|
||||
var MissingPDFException = sharedUtil.MissingPDFException;
|
||||
var UnexpectedResponseException = sharedUtil.UnexpectedResponseException;
|
||||
|
||||
/** @implements {IPDFStream} */
|
||||
function PDFNetworkStream(options) {
|
||||
this._options = options;
|
||||
var source = options.source;
|
||||
this._manager = new NetworkManager(source.url, {
|
||||
httpHeaders: source.httpHeaders,
|
||||
withCredentials: source.withCredentials
|
||||
});
|
||||
this._rangeChunkSize = source.rangeChunkSize;
|
||||
this._fullRequestReader = null;
|
||||
this._rangeRequestReaders = [];
|
||||
}
|
||||
|
||||
PDFNetworkStream.prototype = {
|
||||
_onRangeRequestReaderClosed:
|
||||
function PDFNetworkStream_onRangeRequestReaderClosed(reader) {
|
||||
var i = this._rangeRequestReaders.indexOf(reader);
|
||||
if (i >= 0) {
|
||||
this._rangeRequestReaders.splice(i, 1);
|
||||
}
|
||||
},
|
||||
|
||||
getFullReader: function PDFNetworkStream_getFullReader() {
|
||||
assert(!this._fullRequestReader);
|
||||
this._fullRequestReader =
|
||||
new PDFNetworkStreamFullRequestReader(this._manager, this._options);
|
||||
return this._fullRequestReader;
|
||||
},
|
||||
|
||||
getRangeReader: function PDFNetworkStream_getRangeReader(begin, end) {
|
||||
var reader = new PDFNetworkStreamRangeRequestReader(this._manager,
|
||||
begin, end);
|
||||
reader.onClosed = this._onRangeRequestReaderClosed.bind(this);
|
||||
this._rangeRequestReaders.push(reader);
|
||||
return reader;
|
||||
},
|
||||
|
||||
cancelAllRequests: function PDFNetworkStream_cancelAllRequests(reason) {
|
||||
if (this._fullRequestReader) {
|
||||
this._fullRequestReader.cancel(reason);
|
||||
}
|
||||
var readers = this._rangeRequestReaders.slice(0);
|
||||
readers.forEach(function (reader) {
|
||||
reader.cancel(reason);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/** @implements {IPDFStreamReader} */
|
||||
function PDFNetworkStreamFullRequestReader(manager, options) {
|
||||
this._manager = manager;
|
||||
|
||||
var source = options.source;
|
||||
var args = {
|
||||
onHeadersReceived: this._onHeadersReceived.bind(this),
|
||||
onProgressiveData: source.disableStream ? null :
|
||||
this._onProgressiveData.bind(this),
|
||||
onDone: this._onDone.bind(this),
|
||||
onError: this._onError.bind(this),
|
||||
onProgress: this._onProgress.bind(this)
|
||||
};
|
||||
this._url = source.url;
|
||||
this._fullRequestId = manager.requestFull(args);
|
||||
this._headersReceivedCapability = createPromiseCapability();
|
||||
this._disableRange = options.disableRange || false;
|
||||
this._contentLength = source.length; // optional
|
||||
this._rangeChunkSize = source.rangeChunkSize;
|
||||
if (!this._rangeChunkSize && !this._disableRange) {
|
||||
this._disableRange = true;
|
||||
}
|
||||
|
||||
this._isStreamingSupported = false;
|
||||
this._isRangeSupported = false;
|
||||
|
||||
this._cachedChunks = [];
|
||||
this._requests = [];
|
||||
this._done = false;
|
||||
this._storedError = undefined;
|
||||
|
||||
this.onProgress = null;
|
||||
}
|
||||
|
||||
PDFNetworkStreamFullRequestReader.prototype = {
|
||||
_validateRangeRequestCapabilities: function
|
||||
PDFNetworkStreamFullRequestReader_validateRangeRequestCapabilities() {
|
||||
|
||||
if (this._disableRange) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var networkManager = this._manager;
|
||||
var fullRequestXhrId = this._fullRequestId;
|
||||
var fullRequestXhr = networkManager.getRequestXhr(fullRequestXhrId);
|
||||
if (fullRequestXhr.getResponseHeader('Accept-Ranges') !== 'bytes') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var contentEncoding =
|
||||
fullRequestXhr.getResponseHeader('Content-Encoding') || 'identity';
|
||||
if (contentEncoding !== 'identity') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var length = fullRequestXhr.getResponseHeader('Content-Length');
|
||||
length = parseInt(length, 10);
|
||||
if (!isInt(length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._contentLength = length; // setting right content length
|
||||
|
||||
if (length <= 2 * this._rangeChunkSize) {
|
||||
// The file size is smaller than the size of two chunks, so it does
|
||||
// not make any sense to abort the request and retry with a range
|
||||
// request.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_onHeadersReceived:
|
||||
function PDFNetworkStreamFullRequestReader_onHeadersReceived() {
|
||||
|
||||
if (this._validateRangeRequestCapabilities()) {
|
||||
this._isRangeSupported = true;
|
||||
}
|
||||
|
||||
var networkManager = this._manager;
|
||||
var fullRequestXhrId = this._fullRequestId;
|
||||
if (networkManager.isStreamingRequest(fullRequestXhrId)) {
|
||||
// We can continue fetching when progressive loading is enabled,
|
||||
// and we don't need the autoFetch feature.
|
||||
this._isStreamingSupported = true;
|
||||
} else if (this._isRangeSupported) {
|
||||
// NOTE: by cancelling the full request, and then issuing range
|
||||
// requests, there will be an issue for sites where you can only
|
||||
// request the pdf once. However, if this is the case, then the
|
||||
// server should not be returning that it can support range
|
||||
// requests.
|
||||
networkManager.abortRequest(fullRequestXhrId);
|
||||
}
|
||||
|
||||
this._headersReceivedCapability.resolve();
|
||||
},
|
||||
|
||||
_onProgressiveData:
|
||||
function PDFNetworkStreamFullRequestReader_onProgressiveData(chunk) {
|
||||
if (this._requests.length > 0) {
|
||||
var requestCapability = this._requests.shift();
|
||||
requestCapability.resolve({value: chunk, done: false});
|
||||
} else {
|
||||
this._cachedChunks.push(chunk);
|
||||
}
|
||||
},
|
||||
|
||||
_onDone: function PDFNetworkStreamFullRequestReader_onDone(args) {
|
||||
if (args) {
|
||||
this._onProgressiveData(args.chunk);
|
||||
}
|
||||
this._done = true;
|
||||
if (this._cachedChunks.length > 0) {
|
||||
return;
|
||||
}
|
||||
this._requests.forEach(function (requestCapability) {
|
||||
requestCapability.resolve({value: undefined, done: true});
|
||||
});
|
||||
this._requests = [];
|
||||
},
|
||||
|
||||
_onError: function PDFNetworkStreamFullRequestReader_onError(status) {
|
||||
var url = this._url;
|
||||
var exception;
|
||||
if (status === 404 || status === 0 && /^file:/.test(url)) {
|
||||
exception = new MissingPDFException('Missing PDF "' + url + '".');
|
||||
} else {
|
||||
exception = new UnexpectedResponseException(
|
||||
'Unexpected server response (' + status +
|
||||
') while retrieving PDF "' + url + '".', status);
|
||||
}
|
||||
this._storedError = exception;
|
||||
this._headersReceivedCapability.reject(exception);
|
||||
this._requests.forEach(function (requestCapability) {
|
||||
requestCapability.reject(exception);
|
||||
});
|
||||
this._requests = [];
|
||||
this._cachedChunks = [];
|
||||
},
|
||||
|
||||
_onProgress: function PDFNetworkStreamFullRequestReader_onProgress(data) {
|
||||
if (this.onProgress) {
|
||||
this.onProgress({
|
||||
loaded: data.loaded,
|
||||
total: data.lengthComputable ? data.total : this._contentLength
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
get isRangeSupported() {
|
||||
return this._isRangeSupported;
|
||||
},
|
||||
|
||||
get isStreamingSupported() {
|
||||
return this._isStreamingSupported;
|
||||
},
|
||||
|
||||
get contentLength() {
|
||||
return this._contentLength;
|
||||
},
|
||||
|
||||
get headersReady() {
|
||||
return this._headersReceivedCapability.promise;
|
||||
},
|
||||
|
||||
read: function PDFNetworkStreamFullRequestReader_read() {
|
||||
if (this._storedError) {
|
||||
return Promise.reject(this._storedError);
|
||||
}
|
||||
if (this._cachedChunks.length > 0) {
|
||||
var chunk = this._cachedChunks.shift();
|
||||
return Promise.resolve(chunk);
|
||||
}
|
||||
if (this._done) {
|
||||
return Promise.resolve({value: undefined, done: true});
|
||||
}
|
||||
var requestCapability = createPromiseCapability();
|
||||
this._requests.push(requestCapability);
|
||||
return requestCapability.promise;
|
||||
},
|
||||
|
||||
cancel: function PDFNetworkStreamFullRequestReader_cancel(reason) {
|
||||
this._done = true;
|
||||
this._headersReceivedCapability.reject(reason);
|
||||
this._requests.forEach(function (requestCapability) {
|
||||
requestCapability.resolve({value: undefined, done: true});
|
||||
});
|
||||
this._requests = [];
|
||||
if (this._manager.isPendingRequest(this._fullRequestId)) {
|
||||
this._manager.abortRequest(this._fullRequestId);
|
||||
}
|
||||
this._fullRequestReader = null;
|
||||
}
|
||||
};
|
||||
|
||||
/** @implements {IPDFStreamRangeReader} */
|
||||
function PDFNetworkStreamRangeRequestReader(manager, begin, end) {
|
||||
this._manager = manager;
|
||||
var args = {
|
||||
onDone: this._onDone.bind(this),
|
||||
onProgress: this._onProgress.bind(this)
|
||||
};
|
||||
this._requestId = manager.requestRange(begin, end, args);
|
||||
this._requests = [];
|
||||
this._queuedChunk = null;
|
||||
this._done = false;
|
||||
|
||||
this.onProgress = null;
|
||||
this.onClosed = null;
|
||||
}
|
||||
|
||||
PDFNetworkStreamRangeRequestReader.prototype = {
|
||||
_close: function PDFNetworkStreamRangeRequestReader_close() {
|
||||
if (this.onClosed) {
|
||||
this.onClosed(this);
|
||||
}
|
||||
},
|
||||
|
||||
_onDone: function PDFNetworkStreamRangeRequestReader_onDone(data) {
|
||||
var chunk = data.chunk;
|
||||
if (this._requests.length > 0) {
|
||||
var requestCapability = this._requests.shift();
|
||||
requestCapability.resolve({value: chunk, done: false});
|
||||
} else {
|
||||
this._queuedChunk = chunk;
|
||||
}
|
||||
this._done = true;
|
||||
this._requests.forEach(function (requestCapability) {
|
||||
requestCapability.resolve({value: undefined, done: true});
|
||||
});
|
||||
this._requests = [];
|
||||
this._close();
|
||||
},
|
||||
|
||||
_onProgress: function PDFNetworkStreamRangeRequestReader_onProgress(evt) {
|
||||
if (!this.isStreamingSupported && this.onProgress) {
|
||||
this.onProgress({
|
||||
loaded: evt.loaded
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
get isStreamingSupported() {
|
||||
return false; // TODO allow progressive range bytes loading
|
||||
},
|
||||
|
||||
read: function PDFNetworkStreamRangeRequestReader_read() {
|
||||
if (this._queuedChunk !== null) {
|
||||
var chunk = this._queuedChunk;
|
||||
this._queuedChunk = null;
|
||||
return Promise.resolve({value: chunk, done: false});
|
||||
}
|
||||
if (this._done) {
|
||||
return Promise.resolve({value: undefined, done: true});
|
||||
}
|
||||
var requestCapability = createPromiseCapability();
|
||||
this._requests.push(requestCapability);
|
||||
return requestCapability.promise;
|
||||
},
|
||||
|
||||
cancel: function PDFNetworkStreamRangeRequestReader_cancel(reason) {
|
||||
this._done = true;
|
||||
this._requests.forEach(function (requestCapability) {
|
||||
requestCapability.resolve({value: undefined, done: true});
|
||||
});
|
||||
this._requests = [];
|
||||
if (this._manager.isPendingRequest(this._requestId)) {
|
||||
this._manager.abortRequest(this._requestId);
|
||||
}
|
||||
this._close();
|
||||
}
|
||||
};
|
||||
|
||||
coreWorker.setPDFNetworkStreamClass(PDFNetworkStream);
|
||||
|
||||
exports.PDFNetworkStream = PDFNetworkStream;
|
||||
exports.NetworkManager = NetworkManager;
|
||||
}));
|
||||
//#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue