#1 2023-09-25 15:22:04

YuraZ
Member
Registered: 2023-09-25
Posts: 3

THttpApiServer and data compression

Hello.
I'm using THttpApiServer. I need to compress the response data. I discovered the CompressGZip and CompressDeflate functions in the mormot.core.zip module. I enabled these functions using RegisterCompress. But when generating a response, I get error 87. After studying the source code, I discovered that in the THttpApiServer.Execute procedure, after data compression, the data length is not adjusted anywhere. I added the necessary code and sending data worked correctly. Perhaps this is a bug in the source code? Or did I connect the data compression functions incorrectly?
Thanks.

procedure THttpApiServer.Execute;

...

  function SendResponse: boolean;

  ...

      if fCompress <> nil then
      begin
        with resp^.headers.KnownHeaders[reqContentEncoding] do
          if RawValueLength = 0 then
          begin
            // no previous encoding -> try if any compression
            CompressContent(compressset, fCompress, ctxt.OutContentType,
              ctxt.fOutContent, outcontenc);
            pRawValue := pointer(outcontenc);
            RawValueLength := length(outcontenc);
          end;

        // The code I added is below
        with resp^.headers.KnownHeaders[reqContentLength] do
        begin
          DataLength := Length(ctxt.OutContent).ToString;
          pRawValue := pointer(DataLength);
          RawValueLength := Length(DataLength);
        end;
        // 

      end;
      resp^.SetContent(datachunkmem, ctxt.OutContent, ctxt.OutContentType);
      flags := GetSendResponseFlags(ctxt);
      EHttpApiServer.RaiseOnError(hSendHttpResponse,
        Http.SendHttpResponse(fReqQueue, req^.RequestId, flags, resp^, nil,
          bytessent, nil, 0, nil, fLogData));

    ...

Offline

#2 2023-09-25 15:56:24

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,725
Website

Re: THttpApiServer and data compression

This part should not have changed since mORMot 1, and it was reported to work as expected IIRC.

Could you please check against mORMot 1 source, and see if there is something missing during the translation?

Note that your fix about reqContentLength is unsafe and should not work because you are mixing UTF-16 and UTF-8 content on Delphi, over a temporary memory buffer.
My guess is that you are using FPC.

Offline

#3 2023-09-25 17:59:56

YuraZ
Member
Registered: 2023-09-25
Posts: 3

Re: THttpApiServer and data compression

This code demonstrates the problem. The problem comes from this line: "Ctxt.AddOutHeader(['Content-Length:' + Length(Ctxt.OutContent).ToString]);". If the "Content-Length" header value is not empty, an error will be raised.

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses System.SysUtils, mormot.net.server, mormot.core.zip, mormot.net.http,
  mormot.core.base, mormot.core.threads, mormot.lib.winhttp;

type
  TMyServer = class(THttpApiServer)
  private
    function ProcessRequest(Ctxt: THttpServerRequestAbstract): Cardinal;
  public
    constructor Create(QueueName: SynUnicode = '';
      const OnStart: TOnNotifyThread = nil; const OnStop: TOnNotifyThread = nil;
      const ProcessName: RawUtf8 = ''; ProcessOptions: THttpServerOptions = []); reintroduce;
  end;

const
  Port = 2147;

var
  Server: TMyServer;


constructor TMyServer.Create(QueueName: SynUnicode; const OnStart,
  OnStop: TOnNotifyThread; const ProcessName: RawUtf8;
  ProcessOptions: THttpServerOptions);
begin
  inherited;

  RegisterCompress(CompressGZip, 0);
  RegisterCompress(CompressDeflate, 0);

  OnRequest := ProcessRequest;

  AddUrl('/', UTF8String(Port.ToString), False, '+', False);
end;

function TMyServer.ProcessRequest(Ctxt: THttpServerRequestAbstract): Cardinal;
begin
  Ctxt.OutContentType := 'text/plain; charset=utf-8';
  Ctxt.OutContent := 'Hello world!';
  Ctxt.OutCustomHeaders := string.Empty;
  Ctxt.AddOutHeader(['Content-Length:' + Length(Ctxt.OutContent).ToString]);
  Ctxt.RespStatus := 200;
  Result := Ctxt.RespStatus;
end;


begin
  try
    Server := TMyServer.Create;
    try
      while True do
        Sleep(10);
    finally
      Server.RemoveUrl('/', UTF8String(Port.ToString), False, '+');
      Server.Free;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Offline

#4 2023-09-25 18:03:11

YuraZ
Member
Registered: 2023-09-25
Posts: 3

Re: THttpApiServer and data compression

ab wrote:

Note that your fix about reqContentLength is unsafe and should not work because you are mixing UTF-16 and UTF-8 content on Delphi, over a temporary memory buffer.
My guess is that you are using FPC.

No. I'm using Delphi. I forgot to say that DataLength: RawUtf8. When assigning, a conversion is performed. That's why this code works for me.

Offline

Board footer

Powered by FluxBB