Friday, July 01, 2005

Delphi problem with uploading compressed streams

In my Advanced Web Services article, I had demonstrated how you could do Datapacket compression by compressing the ENTIRE packet before it was sent from the server, and decompressing it at the client end. (Applies to encryption also)

Now I'd said you could do this the other way around too : compressing packets before sending on the client end, and expanding them at the server, using the BeforeRequest event of THTTPRio. This doesn't work: Firstly there is a bug in D7 SOAP, that ignores the var parameter in the BeforeRequest handler. Look here for a fix I've mentioned.

A bigger problem is this: The BeforeExecute event is declared like this:

TBeforeExecuteEvent =
procedure( const MethodName: string;
var SOAPRequest: InvString) of object;

Now if you do some kind of compression or encryption, you might not like to deal with the WideString parameter. The process might introduce some NULL (0) characters in the character array, which will then be truncated by Delphi (which assumes a string ends on a NULL character).

Fortunately, the source is king. Here's a few steps:

  1. Write a descendant component from THttpRio (call it THTTPRioEnh)

  2. Declare a type like so:

    TBeforeExecuteStreamEvent =
    procedure(const MethodName: string;
    Request: TStream) of object;

  3. In the THTTPRioEnh class, declare a published variable of type:

    property OnBeforeExecuteStream: TBeforeExecuteStreamEvent
    read FOnBeforeExecuteStream
    write FOnBeforeExecuteStream;

    Hit Ctrl+Shift+C. The private variable should get declared

  4. override the DoBeforeExecute procedure and in it put:

    procedure DoBeforeExecute(const MethodName: string;
    Request: TStream);
    inherited DoBeforeExecute(MethodName, Request);

    if Assigned( FOnBeforeExecuteStream ) then
    FOnBeforeExecuteStream( MethodName, Request );

  5. Then register the component using a Register procedure, put it in a package, compile and install.

You can then drop a THTTPRioEnh component on your form, and assign a handler to OnBeforeExecuteStream of this component.

I am lazy, so I did all this in Rio.Pas and instead of creating a handler in the IDE I set this up in code instead, something like:

HTTPRio1.OnBeforeExecuteStream := BeforeExecuteStream;

Where I do the modifications to the request stream.


Blogger Michael said...

Ok, that's for the client side! And how do you do it on the server side?
Request is const!
I've seen in a ng that you found a solution for it.

10:16 AM  

Post a Comment

<< Home