Thursday, 10 August 2023
  2 Replies
  421 Visits
  Subscribe
Hi,

I'm currently trying to write an HTTP/2 client-server with the sgcWebSocket library. I'm using the sgcWebSockets Entreprise Team 2023.6.0 Edition.

Just for testing purposes i'm using a self-signed SSL certificate, and want to run a simple architecture with a /ping route that responds "pong" to the client.

When I'm using an HTTP/1.1 client like TIdHttp, the REST debugger from Delphi 11 CE, or the requests library from Python, everything works just fine, i'm receiving the "Pong" response from the TsgcWebSocketHTTPServer.

The problem is, as soon as I'm using the TsgcHTTP2Client from sgcWebSockets, I get a "ERangeError with message 'Range check error'" message on the server side (error which I didnt had when running requests from the above http/1.1 clients). BUT I'm getting this error on the server only if I'm using the synchronous Get request from the TsgcHTTP2Client. If I attach an OnHTTP2Response event on the client and use the asynchronous GetAsync method then everything is working just fine.

The error ERangeError raises in the `sgcHTTP2_Frame` Unit. Line 1134

function TsgcHTTP2_Frame.DoReadBuffer(var aBuffer: TBytes;
aCount: Integer): Boolean;
var
vBytes: TBytes;
begin
Result := False;
if aCount <= Length(FReadBuffer) then
begin
// result
SetLength(aBuffer, aCount);
if Length(FReadBuffer) > 0 then
sgcMove(FReadBuffer[0], aBuffer[0], Length(aBuffer));
^^^^^^
// resize
SetLength(vBytes, Length(FReadBuffer) - aCount);
if Length(FReadBuffer) > aCount then
sgcMove(FReadBuffer[aCount], vBytes[0], Length(vBytes));
SetLength(FReadBuffer, Length(vBytes));
if Length(vBytes) > 0 then
sgcMove(vBytes[0], FReadBuffer[0], Length(FReadBuffer));

Result := True;
end;
end;


In the below code sections, Starting is the OnShow event from TForm and Closing is the OnCloseQuery from TForm.

Here is the server side code
(openssl dll and ssl.pem are located at the same place than the executable)

unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
sgcWebSocket, sgcIdContext, sgcIdCustomHTTPServer, sgcWebSocket_Types;

type
TForm1 = class(TForm)
procedure Starting(Sender: TObject);
procedure Stoping(Sender: TObject; var CanClose: Boolean);
procedure Get(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
private
oServer: TsgcWebSocketHTTPServer;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Starting(Sender: TObject);
begin

oServer := TsgcWebSocketHTTPServer.Create(self);
oServer.OnCommandGet := Get;
oServer.HTTP2Options.Enabled := true;

with oServer.Bindings.Add do
begin
IP := '0.0.0.0';
Port := 8080;
end;

oServer.SSL := true;
oServer.SSLOptions.OpenSSL_Options.APIVersion := oslAPI_1_1;
oServer.SSLOptions.Version := tls1_2;
oServer.SSLOptions.CertFile := 'ssl.pem';
oServer.SSLOptions.KeyFile := 'ssl.pem';
oServer.SSLOptions.RootCertFile := 'ssl.pem';
oServer.SSLOptions.Port := 8080;

oServer.Active := true;

end;

procedure TForm1.Stoping(Sender: TObject; var CanClose: Boolean);
begin
oServer.Active := False;
oServer.Free;
end;

procedure TForm1.Get(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
if ARequestInfo.URI.Equals('/ping') then
begin
AResponseInfo.ContentText := 'Pong';
AResponseInfo.ResponseNo := 200;
exit;
end;
AResponseInfo.ResponseNo := 404;
end;

end.


And here is the client-side code which raises the ERangeCheck error on the server when the resquest is sent.
The btnPingClick procedure is a Click event on a TButton.

unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
sgcHTTP, sgcHTTP2_Client, sgcWebSocket_Types;

type
TForm1 = class(TForm)
btnPing: TButton;
procedure btnPingClick(Sender: TObject);
procedure Closing(Sender: TObject; var CanClose: Boolean);
procedure Starting(Sender: TObject);
private
oClient: TsgcHTTP2Client;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Starting(Sender: TObject);
begin
oClient := TsgcHTTP2Client.Create(self);
oClient.TLSOptions.OpenSSL_Options.APIVersion := oslAPI_1_1;
end;

procedure TForm1.Closing(Sender: TObject; var CanClose: Boolean);
begin
oClient.Disconnect;
oClient.Free;
end;

procedure TForm1.btnPingClick(Sender: TObject);
begin
oClient.Get('https://127.0.0.1:8080/ping');
end;

end.


In the attachment files you can check the REST Debugger output when a request is sent on the above server-side code.

I dont know if i'm doing something terribly wrong or if it's a bug but I cant find any solution to this. I can give more details if needed.

Thanks for considering my request.
Attachments (1)