@@ -14,7 +14,7 @@ sap.ui.define([
1414 "sap/ui/thirdparty/jquery" ,
1515 "./PDFViewerRenderer"
1616] ,
17- function (
17+ function (
1818 library ,
1919 Control ,
2020 Device ,
@@ -61,47 +61,55 @@ sap.ui.define([
6161 * Defines the height of the PDF viewer control, respective to the height of
6262 * the parent container. Can be set to a percent, pixel, or em value.
6363 */
64- height : { type : "sap.ui.core.CSSSize" , group : "Dimension" , defaultValue : "100%" } ,
64+ height : { type : "sap.ui.core.CSSSize" , group : "Dimension" , defaultValue : "100%" } ,
6565 /**
6666 * Defines the width of the PDF viewer control, respective to the width of the
6767 * parent container. Can be set to a percent, pixel, or em value.
6868 */
69- width : { type : "sap.ui.core.CSSSize" , group : "Dimension" , defaultValue : "100%" } ,
69+ width : { type : "sap.ui.core.CSSSize" , group : "Dimension" , defaultValue : "100%" } ,
7070 /**
7171 * Specifies the path to the PDF file to display. Can be set to a relative or
7272 * an absolute path.<br>
7373 * Optionally, this property can also be set to a data URI path or a blob URL
7474 * in all major web browsers except Internet Explorer and Microsoft Edge, provided
7575 * that this data URI or blob URL is allowed in advance. For more information about
7676 * URL filtering, see {@link topic:91f3768f6f4d1014b6dd926db0e91070 URLList Validator Filtering}.
77+ *
78+ * <h3>Source Validation</h3>
79+ * When the source is set, the PDFViewer automatically validates the resource using a GET request
80+ * to ensure it exists and is accessible. This validation:
81+ * <ul>
82+ * <li>Prevents loading invalid or non-existent PDF files</li>
83+ * <li>If validation fails, error content is displayed instead of attempting PDF load</li>
84+ * </ul>
7785 */
78- source : { type : "sap.ui.core.URI" , group : "Misc" , defaultValue : null } ,
86+ source : { type : "sap.ui.core.URI" , group : "Misc" , defaultValue : null } ,
7987 /**
8088 * A custom error message that is displayed when the PDF file cannot be loaded.
8189 * @deprecated As of version 1.50.0, replaced by {@link sap.m.PDFViewer#getErrorPlaceholderMessage}.
8290 */
83- errorMessage : { type : "string" , group : "Misc" , defaultValue : null , deprecated : true } ,
91+ errorMessage : { type : "string" , group : "Misc" , defaultValue : null , deprecated : true } ,
8492 /**
8593 * A custom text that is displayed instead of the PDF file content when the PDF
8694 * file cannot be loaded.
8795 */
88- errorPlaceholderMessage : { type : "string" , group : "Misc" , defaultValue : null } ,
96+ errorPlaceholderMessage : { type : "string" , group : "Misc" , defaultValue : null } ,
8997 /**
9098 * A custom title for the PDF viewer popup dialog. Works only if the PDF viewer
9199 * is set to open in a popup dialog.
92100 * @deprecated As of version 1.50.0, replaced by {@link sap.m.PDFViewer#getTitle}.
93101 */
94- popupHeaderTitle : { type : "string" , group : "Misc" , defaultValue : null , deprecated : true } ,
102+ popupHeaderTitle : { type : "string" , group : "Misc" , defaultValue : null , deprecated : true } ,
95103
96104 /**
97105 * A custom title for the PDF viewer.
98106 */
99- title : { type : "string" , group : "Misc" , defaultValue : null } ,
107+ title : { type : "string" , group : "Misc" , defaultValue : null } ,
100108
101109 /**
102110 * Shows or hides the download button.
103111 */
104- showDownloadButton : { type : "boolean" , group : "Misc" , defaultValue : true } ,
112+ showDownloadButton : { type : "boolean" , group : "Misc" , defaultValue : true } ,
105113
106114 /**
107115 * Defines how the PDF viewer should be displayed.
@@ -123,25 +131,25 @@ sap.ui.define([
123131 * </li>
124132 * </ul>
125133 */
126- displayType : { type : "sap.m.PDFViewerDisplayType" , group : "Misc" , defaultValue : PDFViewerDisplayType . Auto } ,
134+ displayType : { type : "sap.m.PDFViewerDisplayType" , group : "Misc" , defaultValue : PDFViewerDisplayType . Auto } ,
127135 /**
128136 * Parameter to determine if the given PDF is from a trusted source. If the source is valid this property can be set to true.
129137 * If isTrustedSource is set to true, the PDFViewer opens with the displayType set to "Embedded" on desktop devices. This means that the PDF content is directly shown within the PDFViewer. Set this property to true only when the PDF is generated by the application or the PDF is scanned for viruses.
130138 * If isTrustedSource is set to false, the PDFViewer opens with the displayType set to "Link" on desktop devices. This means that any configuration that has been provided by the application for the property displayType is overridden. In this case, the user would need to download the PDF to view its content.
131139 */
132- isTrustedSource : { type : "boolean" , group : "Misc" , defaultValue : false }
140+ isTrustedSource : { type : "boolean" , group : "Misc" , defaultValue : false }
133141 } ,
134142 aggregations : {
135143 /**
136144 * A custom control that can be used instead of the error message specified by the
137145 * errorPlaceholderMessage property.
138146 */
139- errorPlaceholder : { type : "sap.ui.core.Control" , multiple : false } ,
147+ errorPlaceholder : { type : "sap.ui.core.Control" , multiple : false } ,
140148 /**
141149 * A multiple aggregation for buttons that can be added to the footer of the popup
142150 * dialog. Works only if the PDF viewer is set to open in a popup dialog.
143151 */
144- popupButtons : { type : "sap.m.Button" , multiple : true , singularName : "popupButton" } ,
152+ popupButtons : { type : "sap.m.Button" , multiple : true , singularName : "popupButton" } ,
145153 /**
146154 * A message page is displayed when the property isTrustedSource = false
147155 * @private
@@ -159,7 +167,7 @@ sap.ui.define([
159167 * This event is fired when there is an error loading the PDF file.
160168 */
161169 error : {
162- parameters : {
170+ parameters : {
163171 /**
164172 * The iframe element.
165173 */
@@ -322,38 +330,42 @@ sap.ui.define([
322330 * @private
323331 * Handles the iframe load event for PDFViewer.
324332 * - Checks if PDF plugin is enabled, fires error if not.
325- * - Tries to access children of the iframe document body.
326- * - If children exist, checks for embed tag to validate PDF rendering.
327- * - Fires loaded event if valid, error event otherwise.
333+ * - Validates the PDF source using a GET request to ensure accessibility.
334+ * - Fires loaded event if validation succeeds, error event otherwise.
328335 * - Catches and logs any unexpected errors, fires error event in such cases.
329336 */
330- PDFViewer . prototype . _onLoadListener = function ( oEvent ) {
337+ PDFViewer . prototype . _onLoadListener = function ( oEvent ) {
331338 try {
332339 // Check if PDF plugin is enabled
333340 if ( PDFViewerRenderer . _isPdfPluginEnabled ( ) ) {
334- var bContinue = true ;
335- var oTarget = jQuery ( oEvent . target ) ;
336- try {
337- // Try to access children of the iframe document body
338- var oContentWindow = oTarget [ 0 ] && oTarget [ 0 ] . contentWindow ;
339- var oDocumentBody = oContentWindow && oContentWindow . document && oContentWindow . document . body ;
340- var aTargetChildren = oDocumentBody && oDocumentBody . children ;
341- } catch ( error ) {
342- // If access fails, log warning and treat as no children
343- aTargetChildren = [ ] ;
344- Log . warning ( "Error in fetching children entity for given source of PDFViewer." ) ;
345- }
346- // If children exist, check for embed tag
347- if ( aTargetChildren && aTargetChildren . length ) {
348- var oContentWindow = oTarget [ 0 ] && oTarget [ 0 ] . contentWindow ;
349- var oDocument = oContentWindow && oContentWindow . document ;
350- var aEmbeds = oDocument && oDocument . embeds ;
351- bContinue = ! ! aEmbeds && aEmbeds . length === 1 ;
352- }
353- // If valid PDF rendering, fire loaded event; else, fire error event
354- if ( bContinue ) {
355- this . _fireLoadedEvent ( ) ;
341+ // Validate source using GET request when iframe loads
342+ var sSource = this . getSource ( ) ;
343+ if ( sSource ) {
344+ // Skip validation for data URIs and blob URLs as they may not work with fetch
345+ // or would waste bandwidth by re-downloading embedded data
346+ if ( this . _isDataUriOrBlob ( sSource ) ) {
347+ // For data URIs and blob URLs, assume valid and fire loaded event
348+ this . _fireLoadedEvent ( ) ;
349+ } else {
350+ try {
351+ // Source validation using GET request to check resource existence
352+ // Simple and universally compatible approach without Range headers
353+ window . fetch ( sSource , { method : "GET" } )
354+ . then ( function ( response ) {
355+ if ( response . ok ) {
356+ this . _fireLoadedEvent ( ) ;
357+ } else {
358+ this . _fireErrorEvent ( oEvent . target ) ;
359+ }
360+ } . bind ( this ) ) . catch ( function ( ) {
361+ this . _fireErrorEvent ( oEvent . target ) ;
362+ } . bind ( this ) ) ;
363+ } catch ( error ) {
364+ this . _fireErrorEvent ( oEvent . target ) ;
365+ }
366+ }
356367 } else {
368+ // No valid source, fire error event
357369 this . _fireErrorEvent ( oEvent . target ) ;
358370 }
359371 } else {
@@ -368,6 +380,21 @@ sap.ui.define([
368380 }
369381 } ;
370382
383+ /**
384+ * Checks if the source is a data URI or blob URL
385+ * @param {string } sSource The source URL to check
386+ * @returns {boolean } true if source is data URI or blob URL
387+ * @private
388+ */
389+ PDFViewer . prototype . _isDataUriOrBlob = function ( sSource ) {
390+ if ( ! sSource || typeof sSource !== "string" ) {
391+ return false ;
392+ }
393+
394+ var sLowerSource = sSource . toLowerCase ( ) ;
395+ return sLowerSource . startsWith ( "data:" ) || sLowerSource . startsWith ( "blob:" ) ;
396+ } ;
397+
371398 /**
372399 * @private
373400 */
0 commit comments