Uploading and downloading files via http
In this article, I would show how you can upload and download files from InterSystems products via http.
The questions about working with files over http arise fairly often on community and I'm usually linking to my FileServer project which demonstrates file upload/download but I'd like to talk a bit more on how we can serve and receive files from InterSystems products.
Downloading a file
If you have a file in on a file system and you know the path you can serve it from REST or CSP context by calling this method:
ClassMethod serve(name As %String) As %Status
{
#dim sc As %Status = $$$OK
#dim %response As %CSP.Response
kill %request.Data
set %request.Data("STREAMOID",1)= ##class(%CSP.StreamServer).Encrypt(##class(%CSP.StreamServer).GetOidForFile(name))
if ##class(%CSP.StreamServer).OnPreHTTP() {
set %response.Headers("Content-Disposition")="attachment; filename*=UTF-8''" _ ##class(%CSP.Page).EscapeURL(##class(%File).GetFilename(name), "UTF8")
set sc = ##class(%CSP.StreamServer).OnPage()
}
quit sc
}
If you have a stream instead of a file name you can replace
##class(%CSP.StreamServer).GetOidForFile(name)
with
stream.%Oid()
That's it!
User in a browser would see download dialog.
Uploading a file
On a client side (I assume JS/HTML) create a file input:
<input id="myFile" type="file">
and write some JavaScript code that sends POST requests to a server (depends on a framework):
function FileLoad(){ var formData = new FormData(); formData.append("file", document.getElementById("myFile").files[0]); var xhr = new XMLHttpRequest(); // Upload data to server xhr.open("POST", "/rest/path", true); xhr.send(formData); xhr.onload = function(e) { if (this.status == 200) { // everything is OK } else { alert(this.status + ' ' + this.statusText); } }; }
On a server side, you can get the stream as easy as
#dim %request As %CSP.Request #dim stream As %CSP.BinaryStream set stream = %request.GetMimeData("file")
After that, you can write this stream to a file, to a database or just process it without saving.
Links
- FileServer
- MIME Form data
- WebDAV implementation for InterSystems
Please make very sure when you implement it that way, to sanitize your inputs. Otherwise you very easily create a way for attackers to download all files your instance has access to.
Right you are!
I usually store files external from database and write a simple persistent class Document { GUID, DisplayName, FileStream }. User requests files by GUID, and it's served to him with Displayname in header.
Additionally files are never named on filesystem by Displayname, or any kind of user input but rather by hash or a simple incremental counter.
Storing more than 1k (10k) files per directory is not recommended, if possible add more directories (by date, etc.)