1

I've a DataSnap server method

function TServerMethods.GetFile(filename): TStream

returning a file. In my test case the file is a simple .PDF.

I'm sure this function works fine, as I'm able to open files on ObjectiveC client side app's where I've used my own http call to the DataSnap method (no Delphi proxy). The stream is read from ASIHttpRequest object and saved as local file, then loaded and regulary shown in standard pdf reader. I do not kown how exactly ASIHttpRequest manages the returned data.

But on JavaScript client side where I use standard

stream = ServerMethods().GetFile('test.pdf')

JavaScript function, as provided from DataSnap proxy itself, I do not figure out how to show the .pdf data to the user.

Using

window.open().document.write(stream);

a new browser window opens with textual raw data ( %PDF-1.5 %âãÏÓ 1 0 obj << /Type /Catalog /Pages 2 0 R …..)

With

window.open("data:application/pdf;base64," +stream);

I get an empty new browser page.

With

window.open("data:application/pdf," +stream);

or

document.location = 'data:application/pdf,'+encodeURIComponent(serverMethods().GetFile('test'));

I get an new browser page with pdf empry reader and alert “This PDF document could not be displayed correctly”

Nothing changes adding:

GetInvocationMetadata().ResponseContentType := 'application/pdf';

into the DataSnap function.

I've no other ideas...

EDIT

The task is for a general file download, not only PDF. PDF is a test only. GetFile have to manage .pdf, .xlsx, .docx, .png, .eml, etc...

  • 2
    Is there no way to associate the resource data (the PDF document stream here) with a web resource address such as `http://example.com/resources/mypdf` in DataSnap? Then `window.open('http://example.com/resources/mypdf')` should work. – mjn Sep 05 '14 at 12:09
  • Thankyou @mjn. Creating a server-side file resource can be an option and I'll try it. I'll try a direct URL call for DataSnap REST method from JavaScript too, bypassing the proxy one. – Giorgio Calzolato Sep 05 '14 at 15:33
  • 1
    What type of REST server are you creating? Which wizard? There is a bug in the DataSnap REST Server Application wizard, which makes it impossible to override ResponseContentType. – Anders E. Andersen Sep 05 '14 at 19:45
  • Hi @AndersE.Andersen, I read your [answer](http://stackoverflow.com/a/13879240/2726013) and I've tryed it with no luck with a full JavaScript design. I've used Delphi XE3, DataSnap Rest Application wizard, stand-alone for debugging purposes. But now with a direct URL request http://localhost/datasnap/rest/TserverMethods/GetFile/test.pdf the pdf eventually is correctly displyed by the browser. But I'm looking for a pure JavaScript design if possibile. – Giorgio Calzolato Sep 05 '14 at 21:59
  • Ok well then it doesn't sound like the bug is causing this particular issue. Have you tried first calling document.open("application/pdf") then document.write(..pdf-data..) and finally document.close()? – Anders E. Andersen Sep 05 '14 at 23:20
  • With document.open("application/pdf") ..write(strem) ..close() we have a page showing row data "%PDF-1.4 %âãÏÓ..." (latest FireFox, Safari, IE, Chrome). A valid solution is bypassing the proxy serverMethods().GetFile('test.pdf') with a direct URL call or creating a temporary file resource to download, and it works. But this is very different way than a full JS data processing with JSON request/response. May be this way is not possibile ([post](http://stackoverflow.com/a/23829618/2726013))? – Giorgio Calzolato Sep 07 '14 at 20:36
  • Please see [post](http://stackoverflow.com/a/25753911/2726013) about GetInvocationMetadata().ResponseContentType := 'application/pdf' - I've found this doesn't work for me (Delphi XE3 REST DataSnap server) – Giorgio Calzolato Sep 09 '14 at 21:45

1 Answers1

1

Your server side code works as expected once you set the ResponseContentType. You can test this by calling the method directly from a browser. Change the class name to match the one you're using:

http://localhost:8080/datasnap/rest/TServerMethods1/GetFile/test.pdf

I'm sure there's a way to display the stream properly on the browser side, but I'm not sure what that is. Unless you're doing something special with the stream, I'd recommend getting the document directly or using a web action and getting out of the browser's way. Basically what mjn suggested.

I can think of a couple of solutions.

1) A quick way would be to allow access to the documents directly.

In the WebFileDispatcher, add a WebFileExtension. Select .pdf and it will fill in the mime type for you. Assuming your pdf documents are in the "docs" folder, the url might look like this:

http://localhost:8080/docs/test.pdf

2) I would probably add an action on the web module. It's a little more involved, but it also gives me more control.

Using this url:

http://localhost:8080/getfile?filename=test.pdf

And code like this in the web action handler (no checking or error handling). The Content-Disposition header suggests a file name for the downloaded file:

procedure TWebModule1.WebModule1GetFileActionAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  lStream: TMemoryStream;
  lFilename: string;
begin
  lFilename := Request.QueryFields.Values['filename'];
  lStream := TMemoryStream.Create;
  lStream.LoadFromFile('.\Docs\' + lFilename);
  lStream.Position := 0;
  Response.ContentStream := lStream;
  Response.ContentType := 'application/pdf';
  Response.SetCustomHeader('Content-Disposition',
    Format('attachment; filename="%s"', [lFilename]));
end;
Bruce McGee
  • 15,076
  • 6
  • 55
  • 70
  • Thankyou @Bruce, I confirm this works fine. This is a usefull workaround, but my true question is if it's possibile to process PDF stream data returned from a JSON call in a JSON response, as provided by DataSnap framework, simply to show it. Within an app or a desktop application we can save the PDF stream and show it to the user, we can get data in AJAX query and wait for callback, we can process stream before showing it, etc.. Is there a way to do this in a browser JavaScript web-application? It sounds like no. – Giorgio Calzolato Sep 07 '14 at 21:20
  • @Bruce. I managed to get your second suggestion (Action) working in my Rest Server, but the Request is empty. Any ideas? – Pieter van Wyk Sep 10 '15 at 16:01