[api-minor] Ensure that PDFDocumentProxy.hasJSActions won't fail if MissingDataExceptions are thrown during the associated worker-thread parsing
				
					
				
			With the current implementation of `PDFDocument.hasJSActions`, in the worker-thread, we're not actually handling not-yet-loaded data correctly. This can thus fail in *two* different ways: - The `PDFDocument.fieldObjects` getter (and its helper method), while it may *return* a Promise, still fetches all of its data synchronously and it can thus throw a `MissingDataException` during parsing. - The `Catalog.jsActions` getter, which is completely synchronous, can obviously throw a `MissingDataException` during parsing. If either of these cases occur currently, the `PDFDocumentProxy.hasJSActions` method in the API can either return a *rejected* Promise (which it never should) or possibly "hang" and never resolve. *Please note:* While I've not *yet* seen this error in an actual PDF document, it can happen during loading if you're unlucky enough with e.g. the structure of the PDF document and/or the download speed offered by the server. This patch is thus based on code-inspection *and* on manually throwing a `MissingDataException` on the first access of `Catalog.jsActions` to simulate this situation. Finally, this patch adds a couple of *API* unit-tests for this (since none existed).
This commit is contained in:
		
							parent
							
								
									4aa27cc645
								
							
						
					
					
						commit
						2b2234fd5a
					
				@ -1182,20 +1182,29 @@ class PDFDocument {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get hasJSActions() {
 | 
					  get hasJSActions() {
 | 
				
			||||||
    return shadow(
 | 
					    const promise = this.pdfManager.ensure(this, "_parseHasJSActions");
 | 
				
			||||||
      this,
 | 
					    return shadow(this, "hasJSActions", promise);
 | 
				
			||||||
      "hasJSActions",
 | 
					  }
 | 
				
			||||||
      this.fieldObjects.then(fieldObjects => {
 | 
					
 | 
				
			||||||
        return (
 | 
					  /**
 | 
				
			||||||
          (fieldObjects !== null &&
 | 
					   * @private
 | 
				
			||||||
            Object.values(fieldObjects).some(fieldObject =>
 | 
					   */
 | 
				
			||||||
 | 
					  async _parseHasJSActions() {
 | 
				
			||||||
 | 
					    const [catalogJsActions, fieldObjects] = await Promise.all([
 | 
				
			||||||
 | 
					      this.pdfManager.ensureCatalog("jsActions"),
 | 
				
			||||||
 | 
					      this.pdfManager.ensure(this, "fieldObjects"),
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (catalogJsActions) {
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (fieldObjects) {
 | 
				
			||||||
 | 
					      return Object.values(fieldObjects).some(fieldObject =>
 | 
				
			||||||
        fieldObject.some(object => object.actions !== null)
 | 
					        fieldObject.some(object => object.actions !== null)
 | 
				
			||||||
            )) ||
 | 
					 | 
				
			||||||
          !!this.catalog.jsActions
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get calculationOrderIds() {
 | 
					  get calculationOrderIds() {
 | 
				
			||||||
    const acroForm = this.catalog.acroForm;
 | 
					    const acroForm = this.catalog.acroForm;
 | 
				
			||||||
 | 
				
			|||||||
@ -1014,6 +1014,23 @@ describe("api", function () {
 | 
				
			|||||||
        .catch(done.fail);
 | 
					        .catch(done.fail);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it("gets hasJSActions, in document without javaScript", async function () {
 | 
				
			||||||
 | 
					      const hasJSActions = await pdfDocument.hasJSActions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(hasJSActions).toEqual(false);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it("gets hasJSActions, in document with javaScript", async function () {
 | 
				
			||||||
 | 
					      const loadingTask = getDocument(
 | 
				
			||||||
 | 
					        buildGetDocumentParams("doc_actions.pdf")
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      const pdfDoc = await loadingTask.promise;
 | 
				
			||||||
 | 
					      const hasJSActions = await pdfDoc.hasJSActions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(hasJSActions).toEqual(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await loadingTask.destroy();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it("gets JSActions (none)", function (done) {
 | 
					    it("gets JSActions (none)", function (done) {
 | 
				
			||||||
      const promise = pdfDocument.getJSActions();
 | 
					      const promise = pdfDocument.getJSActions();
 | 
				
			||||||
      promise
 | 
					      promise
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user