Short/Generic Version:
I'm working on an application that (unfortunately, for other reasons), sets document.domain
at the top of every page to a substring of the "true" domain: for subdomains like sub.app.local
, document.domain = "app.local"
. I'm also creating an iframe dynamically and adding it to the page. The iframe loads a file residing on the same server as the parent page. Later on, some Javascript needs to access the contentDocument
property of the iframe.
This is fine in modern browsers, but causes problems in IE9 due to this bug. (See the top answer for a good explanation of why this is.) AFAIK, every browser newer than IE9 automatically inherits document.domain
for programmatically-created iframes, so this is IE9-specific. Because of some of the unique requirements of my scenario (tldr: the iframe src needs to change), the answer in the above post didn't work for me.
Longer/Application-Specific Version:
I'm using FineUploader in an application running on IIS, uploading files to S3. Everything's working just fine in modern browsers, but IE9 support is giving me trouble, even after following the docs (Supporting IE9 and older) to configure the iframeSupport.localBlankPagePath
option. I'm a little stumped!
Location
key, and a value that points to my blank document. If I paste the entire URL into the address bar, the page loads fine and is blank as expected.X-Frame-Options SAMEORIGIN
to the server's response headers, as suggested here, but it didn't help.The error that I get in the console is:
[Fine Uploader 5.0.3] Error when attempting to access iframe during handling of upload response (Access is denied.
)
[Fine Uploader 5.0.3] Amazon likely rejected the upload request
UPDATE
I've determined that the reason it's not working out-of-the-box is because the application sets document.domain
on page load, and it's different than (a subset of) location.host
. FineUploader's 303 redirect mechanism to the blank page is working fine, but the document.domain
of the iframe differs from the parent (due to IE9 not inheriting the property) and so, access denied.
The actual S3 upload is working. It's just the final step of verifying the upload that fails.
Here's my client-side code:
FineUploader.js
var fu = namespace('App.FineUploader');
fu.DocId;
fu.ClientDeployId;
fu.viewModel;
fu.defaultAttachmentEndpoint = "https://s3.amazonaws.com/App.UploadBucket";
fu.FineUploaderController = "FineUploaderDocAttachment";
fu.delete = function (documentAttatchmentID, attachmentID) {
var data = documentAttatchmentID;
$.ajax({
type: "POST",
url: App.BaseUrl + "/api/" + fu.FineUploaderController + "/delete",
data: JSON.stringify(data),
success: function () {
$('#fineUploader' + attachmentID).fineUploader('reset');
$('#fineUploader' + attachmentID).show();
$('#aDownloadfineUploader' + attachmentID).html('');
$('#aDownloadfineUploader' + attachmentID).hide();
$('#aDeletefineUploader' + attachmentID).hide();
},
dataType: 'json',
contentType: 'application/json'
})
}
fu.lockAll = function () {
$('.fineUploader').hide();
$('a[id^="aDeletefineUploader"]').hide();
}
fu.init = function (sID) {
$('#' + sID).fineUploaderS3({
request: {
endpoint: fu.defaultAttachmentEndpoint,
accessKey: "[key]",
params: {
documentid: $('#' + sID).attr('documentid'),
attachmentid: $('#' + sID).attr('attachmentid')
}
},
signature: {
endpoint: App.BaseUrl + "/api/" + fu.FineUploaderController + "/signtureHandler"
},
uploadSuccess: {
endpoint: App.BaseUrl + "/api/" + fu.FineUploaderController + "/success"
},
iframeSupport: {
localBlankPagePath: App.BaseUrl + "/Scripts/FineUploader/4.0.3/html/blank.html"
},
objectProperties: {
key: function (fileId) {
var keyRetrieval = new qq.Promise(),
filename = $('#' + sID).fineUploader("getName", fileId);
var documentid = $('#' + sID).attr('documentid');
var attachmentid = $('#' + sID).attr('attachmentid');
var data = { name: filename, documentId: documentid, attachmentId: attachmentid }
$.ajax({
type: "POST",
url: App.BaseUrl + "/api/" + fu.FineUploaderController + "/preUpload",
data: JSON.stringify(data),
success: null,
dataType: 'json',
contentType: 'application/json'
}).done(function (data) {
keyRetrieval.success(data.key);
}).fail(function () {
keyRetrieval.failure();
});
return keyRetrieval;
}
},
validation: {
itemLimit: 1
},
chunking: {
enabled: true
}
}).on('error', function (event, id, name, errorReason, xhrOrXdr) {
alert(qq.format("Error on file number {} - {}. Reason: {}", id, name, errorReason));
}).on('complete', function (event, id, name, response) {
if (fu.FineUploaderController === "FineUploaderDocLibraryAttachment") {
$('#' + sID).fineUploader('reset');
App.Contracts.Create.ReloadImageLibraryList(true);
App.Contracts.Create.HideLoader();
} else {
$('#aDownload' + sID).attr('href', response.url);
$('#aDownload' + sID).html(response.name);
$('#aDownload' + sID).show();
$('#aDelete' + sID).show();
$('#aDelete' + sID).attr('onclick', 'App.FineUploader.delete(' + response.daId + ',' + sID.replace('fineUploader', '') + ');');
$('#' + sID).hide();
}
}).on('submitted', function () {
if (fu.FineUploaderController === "FineUploaderDocLibraryAttachment") {
App.Contracts.Create.ShowLoader();
}
});
}
(If anyone stumbles across this answer outside of the context of FineUploader, this idea is what I based my solution on.)
To implement this, I made FineUploader's blank.html slightly non-blank:
<head>
<script type="text/javascript">
// Provide a mechanism to override document.domain
// inside the iframe via this url syntax: blank.html?[args]#domain.com
if (location.hash.substring(1).length > 0)
document.domain = location.hash.substring(1);
</script>
</head><body></body>
This gives me a way to feed the correct document.domain
value from the parent page when the iframe is generated. Slight modification to the FineUploader configuration object:
$.fineUploaderS3({
[snip]
iframeSupport: {
localBlankPagePath: App.BaseUrl + "/Scripts/FineUploader/4.0.3/html/blank.html#" + document.domain
},
[/snip]
}
This doesn't seem to interfere with the arguments that are prepended by AWS. We're still using FineUploader 4.0.3 in this application, but this should work with latest as well.
tl,dr; It works! Tested in IE11 Document mode and also native IE9.
The error suggests that the page served by the iframe is indeed not the same domain as the page hosting the uploader. Either that, or you have some plug-in/extension causing trouble. According to the error, Fine Uploader is simply not able to access any content in the iframe, which happens when the domain of the iframe doesn't match the domain of the frame/page hosting the uploader.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With