Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi REST Server, Android Client using compression

We're building a Delphi REST server that serves up rather large chunks of data (1.5MB per request, of which there are many) to a native Android application. All works fine, except the data sizes in this case will be problematic, causing long transfer times in our environment (limited mobile data rates). I've tried adding the ZLibCompression filter on the DSHTTPWebDispatcher, but the response only comes back again as uncompressed text/html.

Is there any way to force the server to use the filter added as an event before the dispatch?

The server is built using Delphi XE3.

like image 951
bosvos Avatar asked Dec 06 '25 08:12

bosvos


1 Answers

I've managed to figure out where to add the compression and relevant header changes in the DataSnap project.

The key here is the TWebModule class. If one uses the wizard to create a new project, a default implementation of the TWebModule class is constructed, with event properties for BeforeDispatch, AfterDispatch etc. The naming here refers to the action of dispatching the incoming request to where it will be handled. So, BeforeDispatch happens when the request arrives, some processing happens on the server and AfterDispatch triggers just before the response is sent back to the caller.

AfterDispatch is therefore the correct event to use if one wants to modify the constructed response after the fact. This can include changes to both the content and headers.

On the AfterDispatch event:

procedure TWebModule1.WebModuleAfterDispatch(
  Sender: TObject;
  Request: TWebRequest; 
  Response: TWebResponse;
  var Handled: Boolean);
var

srcbuf, destbuf : TBytes;
str : string;

begin
  str := Response.Content;

  //prepare byte array
  srcbuf := BytesOf(str);

  //compress to buff (System.ZLib)
  ZCompress(srcbuf, destbuf, zcMax);

  //prepare responsestream and set content encoding and type
  Response.Content := '';
  Response.ContentStream := TMemoryStream.Create;
  Response.ContentEncoding := 'deflate';
  Response.ContentType := 'application/json';

  //current browser implementations incorrectly handles the first 2 bytes 
  //of a ZLib compressed stream, remove them
  Response.ContentStream.Write(@(destbuf[2]),length(destbuf)-2);
  Response.ContentLength := (length(destbuf))-2;
end;

Not very fancy, one could enable/disable compression depending on the content sent back, but for our implementation we kept it simple.

This works 100% with Fiddler and browsers that can handle deflate.

like image 111
bosvos Avatar answered Dec 08 '25 21:12

bosvos



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!