send binary data to javascript

Discussion and questions about programming with Ultibo.
Koen
Posts: 31
Joined: Sat Apr 29, 2017 10:41 am

send binary data to javascript

Postby Koen » Sun Jun 17, 2018 11:54 am

I am trying to send an array to a webpage but something is wrong.
In the DoGet function of a THttpDocument i set the Responce.ContentStream pointing to a memorystream.
The script receives a readyState switching between 4 and 1 and the status is always 0.
The corresponding DoGet function is called more often than expected. Expected every 5 seconds, sometimes called 10 times per second.
After a while no more calls to DoGet are received. (or something got wrong)
I don't know if the error is in the pascal code or in the script. Script is mostly copy/paste.
Code included. RPI 2B
Any advice?
Attachments
testarrabufferscript.zip
(2.64 KiB) Downloaded 16 times
User avatar
Ultibo
Site Admin
Posts: 2040
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: send binary data to javascript

Postby Ultibo » Mon Jun 18, 2018 6:17 am

Koen wrote:I don't know if the error is in the pascal code or in the script. Script is mostly copy/paste.
Code included. RPI 2B
Any advice?

I had a look at your DoGet function, the use of the TMemoryStream seems to be the main cause of the problem.

You have StreamResponse: TMemoryStream declared as a global variable but all you need to do is declare it locally within DoGet and then create a new instance of it every time Action = OFF is called.

Instances of classes in Free Pascal are not reference counted and are not automatically destroyed when they go out of scope, so it is quite ok to create an instance of TMemoryStream locally within a function like DoGet and pass it to something else for later use as long as you know that something else will also free the stream when it is done.

Here's the relevant part of the DoGet function modified so that the memory stream works correctly:

Code: Select all

function TPROCESSTYPE.Doget(Ahost: Thttphost; Arequest: Thttpserverrequest;
  Aresponse: Thttpserverresponse): Boolean;
var
  Action:String;
  Data: array [0..5] of word;
 
  StreamResponse: TMemoryStream;
begin
  Result:=True;
  Action:=Uppercase(ARequest.GetParam('ACTION'));
  if Action = 'ON' then
   begin
    AddResult(AResponse);
    AddContent(AResponse,'action ON ' + IntToStr(RequestCountOn));
    inc(RequestCountOn);
   end

  else
  if Action = 'OFF' then
   begin
    StreamResponse:= TMemoryStream.Create; //Create a new TMemoryStream on each call, the server will free it after sending the response.
   
    AddResult(AResponse);
    inc(RequestCountOff);
    StreamResponse.Clear;

    Data[0]:=1;
    Data[1]:=110;
    Data[2]:=50;
    Data[3]:=80;
    Data[4]:=200;
    Data[5]:=250;
    StreamResponse.Write(Data, SizeOf(Data));
    StreamResponse.Position:=0; //Restore the position to 0 after writing the data
   
    AResponse.ContentStream:=StreamResponse;
   end

  else
   begin
    //StreamResponse:= TMemoryStream.Create; //Not required here
    AddResult(AResponse);
   ...

After these changes it doesn't crash anymore and will keep running for as long as you leave it on the page, the JavaScript still doesn't seem to like your array (shows "undefined") but I'll leave that for you to work out.
Ultibo.org | Make something amazing
https://ultibo.org
Koen
Posts: 31
Joined: Sat Apr 29, 2017 10:41 am

Re: send binary data to javascript

Postby Koen » Mon Jun 18, 2018 1:59 pm

Good advice!
I made the changes as you proposed.
Now I get a response with the expected length.
The new problem is the response type is string as I found out by using typeof(xmlhttp.response) in the script.
I do set xmlhttp.responceType = 'arraybuffer' in the script.

I took a look at the HTTP unit and line 2366, wich sets the header for a stream content, is
SetHeader(HTTP_ENTITY_HEADER_CONTENT_TYPE,HTTP_CONTENT_TEXT_HTML);
Could that be the reason?
I guess I can find a workaround for the script but will wait for your answer first.
User avatar
Ultibo
Site Admin
Posts: 2040
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: send binary data to javascript

Postby Ultibo » Tue Jun 19, 2018 12:14 am

Koen wrote:The new problem is the response type is string as I found out by using typeof(xmlhttp.response) in the script.
I do set xmlhttp.responceType = 'arraybuffer' in the script.

I took a look at the HTTP unit and line 2366, wich sets the header for a stream content, is
SetHeader(HTTP_ENTITY_HEADER_CONTENT_TYPE,HTTP_CONTENT_TEXT_HTML);
Could that be the reason?
I guess I can find a workaround for the script but will wait for your answer first.

You can set your own content type by simply calling AResponse.SetHeader in your DoGet method.

I added it after AddResult in Action = OFF like this:

Code: Select all

 ...
  else
  if Action = 'OFF' then
   begin
    StreamResponse:= TMemoryStream.Create;
   
    AddResult(AResponse);

    {Set Content Type}
    AResponse.SetHeader(HTTP_ENTITY_HEADER_CONTENT_TYPE,'application/octet-stream');

    inc(RequestCountOff);
    ...

And it sends as a stream of binary bytes instead of text.

You also have a spelling mistake, if you change responceType to responseType then your script starts working.

I don't know if application/octet-stream is the correct type, you can find the complete list here https://www.iana.org/assignments/media- ... ypes.xhtml
Ultibo.org | Make something amazing
https://ultibo.org
Koen
Posts: 31
Joined: Sat Apr 29, 2017 10:41 am

Re: send binary data to javascript

Postby Koen » Tue Jun 19, 2018 7:46 am

Ultibo wrote:You also have a spelling mistake, if you change responceType to responseType then your script starts working.

Thanks! That was the deciding error!
It did not show up as error in the browser-konsole.
It seems I don't like javascript. The case-sensitive names are annoying me too.

Ultibo wrote:I don't know if application/octet-stream is the correct type, you can find the complete list here https://www.iana.org/assignments/media- ... ypes.xhtml

There is no need setting the responsetype on the Ultibo side.
I tried both leaving it to default and setting it to 'application/octet-stream'.
Makes no difference on the script side.
Everything is working as espected now.
Thanks again!
Background: it 's the base code for a scope-object for my Pluteus project. Shows the process-values.

Return to “General”

Who is online

Users browsing this forum: No registered users and 0 guests