You are not logged in.
Pages: 1
Thank you very much.
Hello,
I have run in Delphi 10.3 update 3 the project ..\SQLite3\Samples\ThirdPartyDemos\George\REST-tester\mORMotRESTsrv.dpr and an exception is raised when I set the port 80 and click on the "Start server" Button.
I have seen the problem and is the following :
In RestServerUnit.pas this code is executed :
fHTTPServer := TSQLHttpServer.Create(AnsiString(fServerSettings.Port), [fRestServer], '+', useBidirSocket);
After this, in SynCrtSock.pas, the fSock is created in the THttpServer constructor :
constructor THttpServer.Create
begin
.....
fSock := TCrtSocket.Bind(aPort); // BIND + LISTEN
....
end;
But the line fSock := TCrtSocket.Bind(aPort) raises in the TCrtSocket.OpenBind this exception :
raise ECrtSocket.CreateFmt('OpenBind(%s:%s,%s) failed: %s', [aServer,fPort,BINDTXT[doBind],BINDMSG[doBind]],-1);
So, when the destructor of the THttpServer occurs, an access violation is raised because fSock has a nil value, concretly here :
destructor THttpServer.Destroy;
begin
....
if not fExecuteFinished then begin
Sock.Close; // shutdown the socket to unlock Accept() in Execute
DirectShutdown(CallServer('127.0.0.1',Sock.Port,false,cslTCP,1)); // <--------------- WANING, Sock could be nil
end;
.............
end;
I have applied a correction to this code :
destructor THttpServer.Destroy;
begin
....
if not fExecuteFinished then begin
Sock.Close; // shutdown the socket to unlock Accept() in Execute
if Sock <> nil then // <--------------- avoid to use Sock when it is nil
DirectShutdown(CallServer('127.0.0.1',Sock.Port,false,cslTCP,1));
end;
.............
end;
Thank you.
Thank you.
Hello,
I have seen an issue using TRawByteStringStream.Write.
I did write a integer value, after, several string values, and finally I set the TRawByteStringStream Position to 0 and did write a new integer value to the beginning of the stream. My surprise was that the TRawByteStringStream Size was cutted.
I think that there is a problem with the SetLength in this method :
function TRawByteStringStream.Write(const Buffer; Count: Integer): Longint;
begin
if Count<=0 then
Result := 0 else begin
Result := Count;
SetLength(fDataString,fPosition+Result);
{$ifdef FPC}Move{$else}MoveFast{$endif}(Buffer,PByteArray(fDataString)[fPosition],Result);
inc(FPosition,Result);
end;
end;
The SetLength is set although the fPosition+Result not be greater than the length of fDataString.
Is it done thinking in performance?.
Would not be more correct this? :
function TRawByteStringStream.Write(const Buffer; Count: Longint): Longint;
begin
if Count<=0 then
Result := 0
else begin
Result := Count;
if fPosition+Result > Length(fDataString) then
SetLength(fDataString,fPosition+Result);
{$ifdef FPC}Move{$else}MoveFast{$endif}(Buffer,PByteArray(fDataString)[fPosition],Result);
inc(FPosition,Result);
end;
end;
Thank you.
Hello,
I have discovered a bug in the function Base64JSONStringToBytes that is located in the unit SynCrossPlatformJSON compiling with Delphi 10.1 Berlin update 2 and a recently installation of mormot of November 2016 and the project targeting and Android device.
The problem is that in the function Base64JSONStringToBytes the string named JSONString is accesed using 1-based indexing and in mobile compilers in Delphi this strings should be converted to access them using the rule of 0-based indexing ( you can see it in this page : http://docwiki.embarcadero.com/RADStudi … om_Desktop ). The best solution is to use the TStringHelper.Chars property that is 0-based indexing independent of the compiler, so changing the access of JSONString[x] by JSONString.Chars[x-1] the program run well targeting Win32/64 or Android/ios ( mobile devices ).
You can see the corrected function here :
function Base64JSONStringToBytes(const JSONString: string;
var Bytes: TByteDynArray; withBase64Magic: boolean): boolean;
var i,bits,value,x,magiclen,len: cardinal;
begin
result := JSONString='';
if result then
exit;
if withBase64Magic then
if comparemem(pointer(JSONString),@JSON_BASE64_MAGIC,sizeof(JSON_BASE64_MAGIC)) then
magiclen := JSON_BASE64_MAGIC_LEN else
{$ifndef UNICODE}
//if JSONString[1]='?' then // handle UTF-8 decoding error on ANSI Delphi
if JSONString.Chars[0]='?' then // <----- NEW CODE
magiclen := 1 else
{$endif}
exit else
magiclen := 0; // withBase64Magic=false
x := length(JSONString);
len := x-magiclen;
if len and 3<>0 then
exit;
if len=0 then
Bytes := nil else begin
if BASE64DECODE=nil then begin
SetLength(BASE64DECODE,128);
for i := 0 to 127 do
BASE64DECODE[i] := -1;
for i := 0 to high(BASE64) do
BASE64DECODE[ord(BASE64[i])] := i;
end;
len := (len shr 2)*3;
//if Base64One(JSONString[x])<0 then begin
if Base64One(JSONString.Chars[x-1])<0 then begin // <----- NEW CODE
dec(len);
//if Base64One(JSONString[x-1])<0 then
if Base64One(JSONString.Chars[x-2])<0 then // <----- NEW CODE
dec(len);
end;
SetLength(Bytes,len);
bits := 0;
value := 0;
len := 0;
for i := magiclen+1 to Length(JSONString) do begin
//x := ord(JSONString[i]); // inlined Base64One(JSONString[i])
x := ord(JSONString.Chars[i-1]); // <----- NEW CODE
if x>127 then
break;
x := cardinal(BASE64DECODE[x]);
if integer(x)<0 then
break;
value := value*64+x;
bits := bits+6;
if bits>=8 then begin
bits := bits-8;
x := value shr bits;
value := value and ((1 shl bits)-1);
Bytes[len] := x;
inc(len);
end;
end;
end;
result := len=cardinal(length(Bytes));
end;
I suppose that the complementary function BytesToBase64JSONString can have the same problem.
I saw the problem downloading a bitmap content as Base64 from a interface based service server. When I compiled the program targeting Win32 or Win64 the bitmap was decoded using Base64JSONStringToBytes and had a size X. But if I compiled the project targeting Android, the same bitmap had a size of X - 1. Once that I corrected the Base64JSONStringToBytes function to use the Chars property of TStringHelper class the problem solved.
Can anyone confirm me this bug please?. I am in the doubt if I am wrong.
Thank you and best regards.
Hello Administrator,
I have done a modification to SynCrtSock.pas in order to allow customize the block size of the data that is read in TWinHttpAPI.InternalRetrieveAnswer.
The changes has been the following ( I have remarked the changes with the word "changed" ) :
TWinHttpAPI = class(THttpRequest)
protected
...
fBlockSize : cardinal; // <------------------------- changed
...
public
...
/// hoy many bytes should be retrieved for each InternalRead in InternalRetrieveAnswer
property BlockSize : cardinal
read fBlockSize write fBlockSize; // <---------------------------- changed
end;
...
function TWinHttpAPI.InternalRetrieveAnswer(
var Header, Encoding, AcceptEncoding, Data: SockString): integer;
var Bytes, ContentLength, Read: DWORD;
tmp: SockString;
begin // HTTP_QUERY* and WINHTTP_QUERY* do match -> common to TWinINet + TWinHTTP
result := InternalGetInfo32(HTTP_QUERY_STATUS_CODE);
Header := InternalGetInfo(HTTP_QUERY_RAW_HEADERS_CRLF);
Encoding := InternalGetInfo(HTTP_QUERY_CONTENT_ENCODING);
AcceptEncoding := InternalGetInfo(HTTP_QUERY_ACCEPT_ENCODING);
// retrieve received content (if any)
Read := 0;
ContentLength := InternalGetInfo32(HTTP_QUERY_CONTENT_LENGTH);
if Assigned(fOnDownload) then begin
// download per-chunk using calback event
Bytes := fOnDownloadChunkSize;
if Bytes<=0 then
Bytes := 65536; // 64KB seems fair enough by default
SetLength(tmp,Bytes);
repeat
Bytes := InternalReadData(tmp,0);
if Bytes=0 then
break;
inc(Read,Bytes);
if not fOnDownload(self,Read,ContentLength,Bytes,pointer(tmp)^) then
break; // returned false = aborted
if Assigned(fOnProgress) then
fOnProgress(self,Read,ContentLength);
until false;
end else
if ContentLength<>0 then begin
// optimized version reading "Content-Length: xxx" bytes
if fBlockSize <= 0 then // <------------------------------------------ changed
SetLength(Data,ContentLength);
repeat
// ------------------ changed start
if fBlockSize > 0 then
begin
if Read + fBlockSize > ContentLength then
Bytes := ContentLength - Read
else
Bytes := fBlockSize;
SetLength( Data, Read + Bytes );
end;
// ------------------ changed end
Bytes := InternalReadData(Data,Read);
if Bytes=0 then begin
SetLength(Data,Read); // truncated content
break;
end;
inc(Read,Bytes);
if Assigned(fOnProgress) then
fOnProgress(self,Read,ContentLength);
until Read=ContentLength;
end else begin
// Content-Length not set: read response in blocks of HTTP_RESP_BLOCK_SIZE or fBlockSize <------------------- changed
repeat
if fBlockSize <= 0 then // <------------------------------- changed
SetLength(Data,Read+HTTP_RESP_BLOCK_SIZE)
else
SetLength(Data,Read+fBlockSize); // <------------------------------- changed
Bytes := InternalReadData(Data,Read);
if Bytes=0 then
break;
inc(Read,Bytes);
if Assigned(fOnProgress) then
fOnProgress(self,Read,ContentLength);
until false;
SetLength(Data,Read);
end;
end;
These changes are very useful when I use a TSQLHttpClient to allow to consume a function of a interface based services server that returns a RawByteString that is very large, and I need that the client application show a progress during the "download" of this data. Without my modification, the OnProgress is only shown once, but If I set the new BlockSize property to 65535 for example, the progress is shown every 65535 bytes received and the user interface is updated showing a responsive progressbar.
Can you tell me if this is usefull for the synopse framework?.
Thank you and best regards.
Set the appropriate output header.
Thank you, but in the OnRequest procedure I have the Ctxt: THttpServerRequest parameter. I have tried to set the Ctxt.OutCustomHeaders to HTTP/1.0 200 OK and Content-Type: image/jpeg but it does not work, I have sniffed the result and it always return HTTP/1.1 200 OK ..., I do not know how to set the output header. I have stopped the code when I set Result := 200 and followed the code line by line until the execution code return to the procedure THttpApiServer.Execute and I observed that the code arrives until :
EHttpApiServer.RaiseOnError(hSendHttpResponse,Http.SendHttpResponse(fReqQueue,Req^.RequestId,0,Resp^,nil,bytesSent,nil,0,nil,fLogData));
And in the Req^.Version.MajorVersion is 1 and Req^.Version.MinorVersion is 1, so I suspect that the HTTP/1.1 200 OK is responsed by the http.sys because I do not see it in any structure of the Req^ pointer.
Can you help me to set the appropiate header?.
Thank you and best regards.
I have created a vcl form application and created an instance of THttpApiServer class. In the OnRequest event I would like to set the version of the response to set it as HTTP/1.0 instead of HTTP/1.1.
For example, when I receive a request in this format : GET /../jpg/image.cgi HTTP/1.1 .....
I would like to response with : HTTP/1.0 200 OK .... Content-Type: image/jpeg ....
Thank you and best regards.
Pages: 1