fine-uploader
fine-uploader copied to clipboard
Allow endpoints to support promises rather than urls
Struggling to implement CSRF on calls from the uploader in S3 mode. Even using a customHeader function for the signature and uploadSuccess endpoints, I see occasionally failures that I haven't been able to trace down that I think happen when our server rejects signature requests due to CSRF mismatches.
Add support for these endpoints to be functions that return promises (similar to how objectProperties.key currently functions). This would let us handle communication between the client and our server rather than delegating it to fineuploader.
I'm a bit unclear on your requirements. What, specifically, are you doing now that isn't working consistently? Illustration w/ code would be best.
I have figured out what was causing the CSRF mismatches - the cookie library I was using was urldecoding the CSRF cookie on the client. All appears to be working as expected in your library.
So my reason for needing this feature is kaput. However, I still think it would be a good improvement to the library. It would be nice to be in full control of all interactions with the server.
Here is a snippet of my current implementation:
$element.find('.uploader').fineUploaderS3({
uploaderType: 'basic',
request: {
endpoint: $attrs.endpoint,
accessKey: $attrs.accesskey
},
signature: {
endpoint: $attrs.signature ? $attrs.signature : '/upload/signature',
customHeaders: function () {
return {
RootCSRF: $.cookie('RootCSRF')
};
}
},
uploadSuccess: {
endpoint: $attrs.success ? $attrs.success : '/upload/UploadS3',
customHeaders: function () {
return {
RootCSRF: $.cookie('RootCSRF')
};
}
},
iframeSupport: {
localBlankPagePath: $attrs.blankPagePath ? $attrs.blankPagePath : '/upload/blank'
},
objectProperties: {
key: function (fileId) {
var p = new qq.Promise();
$scope.$apply(function () {
adminAPI.GetKey()
.then(function (result) {
p.success(result.Result);
}, function (err) {
p.failure();
});
});
return p;
}
},
validation: {
allowedExtensions: $attrs.extension ? $attrs.extension : [],
acceptFiles: $attrs.accept ? $attrs.accept : [],
itemLimit: $attrs.itemLimit ? ParseInt($attrs.itemLimit) : 1
},
retry: {
},
chucking: {
enabled: typeof $attrs.chunk === undefined ? true : $attrs.chunk,
concurrent: {
enabled: true
}
},
resume: {
enabled: typeof $attrs.resume === undefined ? true : $attrs.resume
},
camera: {
ios: typeof $attrs.camera === undefined ? true : $attrs.camera
},
//template: qq.supportedFeatures.fileDrop ? 'qq-template-with-drop' : 'qq-template',
extraButtons: extraButtons
});
and what I would like to be able to do in the future
$element.find('.uploader').fineUploaderS3({
uploaderType: 'basic',
request: {
endpoint: $attrs.endpoint,
accessKey: $attrs.accesskey
},
signature: {
endpoint: function (tosign, asheader) {
//return thenable object
return adminAPI.Signature(tosign, asheader || false);
}
},
uploadSuccess: {
endpoint: function (key, uuid, name, bucket) {
//return thenable object
return adminAPI.UploadSuccess(key, uuid, name, bucket);
}
},
iframeSupport: {
localBlankPagePath: $attrs.blankPagePath ? $attrs.blankPagePath : '/upload/blank'
},
objectProperties: {
key: function (fileId) {
var p = new qq.Promise();
$scope.$apply(function () {
adminAPI.GetKey()
.then(function (result) {
p.success(result.Result);
}, function (err) {
p.failure();
});
});
return p;
}
},
validation: {
allowedExtensions: $attrs.extension ? $attrs.extension : [],
acceptFiles: $attrs.accept ? $attrs.accept : [],
itemLimit: $attrs.itemLimit ? ParseInt($attrs.itemLimit) : 1
},
retry: {
},
chucking: {
enabled: typeof $attrs.chunk === undefined ? true : $attrs.chunk,
concurrent: {
enabled: true
}
},
resume: {
enabled: typeof $attrs.resume === undefined ? true : $attrs.resume
},
camera: {
ios: typeof $attrs.camera === undefined ? true : $attrs.camera
},
//template: qq.supportedFeatures.fileDrop ? 'qq-template-with-drop' : 'qq-template',
extraButtons: extraButtons
});
Looks like you've declared a chucking
configuration option. If this is an exact copy of your production setup, you'll want to correct that to be chunking
instead.
I can see other benefits to allowing for an endpoint to be determined on-demand asynchronously as you have illustrated. So, I'll keep this open for future consideration.
Hah. Thanks for catching that. Pre production :)
Ray - just bumping this to see if you guys are still considering making the endpoint properties accept functions that return promises rather than just strings (so we can implement our own xhr, etc rather than having fineuploader do it internally).
I would expect the promise to return a URL to the endpoint. Is this what you are suggesting?
No. The promise would resolve to the data that you'd expect to currently be returned from the endpoint. This is a somewhat contrived example, but something along these lines should work:
uploadSuccess: {
endpoint: function (key, uuid, name, bucket) {
var p = new qq.Promise();
setTimeout(function() {
p.success({});
}, 1000);
return p;
}
}
This has the advantage of allowing us to have a bit more flexibility into how our API is structured - for instance (and again contrived), if we wanted to use a Websocket in the above example rather than xhr we could do it.
I'm not talking about endpoints that talk to services outside our control (like the S3 endpoints - obviously you have to manage that internal to the uploader). I'm talking about the endpoints you specify that are integration points with our application (uploadSuccess, getKey, signature, etc.). Promises would give us more flexibility in implementation.
Ah I see. I think I misunderstood the intent of this case, looking back at my earlier comments.
I can see implementing this for everything other than upload requests (for all endpoint types, not just S3). There would need to be some agreement as to what the resolved promise would "return". Should it return an XMLHttpRequest
object, or some other object with conventional properties? The former seems to be the simplest choice, but I suppose this makes the solution less flexible for integrators.
This seems interesting, but it probably isn't going to happen any time soon. There are several non-trivial higher-priority enhancements ahead of this in the queue, such as support for S3 v4 signatures (#1336), and substantial updates to the documentation. I'd also want to hear a few other users express support for this.
I'll start the lobbying process :). Not urgent for us, either - just something I thought might be a good idea.
+1
+1
I don't see this making it into 5.5, as that is currently intended to be a small, focused release. 6.0 is also quite full at the moment (overfull even). Still I can see that it is a desired feature, and I'll keep it in my periphery when planning releases.
+1
In my scenario I'd like to control how the success request is made, rather than conforming to what fileUploader wants to do.